aboutsummaryrefslogtreecommitdiff
path: root/util/romcc
diff options
context:
space:
mode:
authorEric Biederman <ebiederm@xmission.com>2003-10-22 04:03:46 +0000
committerEric Biederman <ebiederm@xmission.com>2003-10-22 04:03:46 +0000
commit5ade04a436c151d88fc02ca18e2de990d7b569dd (patch)
tree059d05c3a62b463ab20bb93eb0fa6a6192173604 /util/romcc
parentfc76dcf0d00f9e1d28d128ffc43320d940f531a6 (diff)
- Update romcc to version 0.37
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1225 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/romcc')
-rw-r--r--util/romcc/Makefile49
-rw-r--r--util/romcc/romcc.c3549
-rw-r--r--util/romcc/tests/linux_test8.c39
-rw-r--r--util/romcc/tests/simple_test69.c22
-rw-r--r--util/romcc/tests/simple_test70.c22
-rw-r--r--util/romcc/tests/simple_test71.c25
-rw-r--r--util/romcc/tests/simple_test72.c164
-rw-r--r--util/romcc/tests/simple_test73.c174
8 files changed, 2679 insertions, 1365 deletions
diff --git a/util/romcc/Makefile b/util/romcc/Makefile
index 62df48d434..e8dd0a9679 100644
--- a/util/romcc/Makefile
+++ b/util/romcc/Makefile
@@ -1,5 +1,5 @@
-VERSION:=0.36
-RELEASE_DATE:=10 October 2003
+VERSION:=0.37
+RELEASE_DATE:=21 October 2003
PACKAGE:=romcc
@@ -25,6 +25,7 @@ LINUX_TESTS=\
linux_test5.c \
linux_test6.c \
linux_test7.c \
+ linux_test8.c \
TESTS=\
hello_world.c \
@@ -89,6 +90,10 @@ TESTS=\
simple_test66.c \
simple_test67.c \
simple_test68.c \
+ simple_test69.c \
+ simple_test71.c \
+ simple_test72.c \
+ simple_test73.c \
raminit_test.c \
raminit_test2.c \
raminit_test3.c \
@@ -117,8 +122,10 @@ TEST_ASM_O_mmmx_msse:=$(patsubst %.c, tests/%.S-O-mmmx-msse, $(TESTS))
TEST_ASM_O2_mmmx :=$(patsubst %.c, tests/%.S-O2-mmmx, $(TESTS))
TEST_ASM_O2_msse :=$(patsubst %.c, tests/%.S-O2-msse, $(TESTS))
TEST_ASM_O2_mmmx_msse:=$(patsubst %.c, tests/%.S-O2-mmmx-msse, $(TESTS))
-TEST_ASM_ALL:= $(TEST_ASM) $(TEST_ASM_O) $(TEST_ASM_O2) $(TEST_ASM_mmmx) $(TEST_ASM_msse) $(TEST_ASM_mmmx_msse) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse)
-TEST_ASM_MOST:= $(TEST_ASM_O) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse)
+TEST_ASM_O2_mmmx_call :=$(patsubst %.c, tests/%.S-O2-mmmx-call, $(TESTS))
+TEST_ASM_O2_mmmx_msse_call:=$(patsubst %.c, tests/%.S-O2-mmmx-msse-call, $(TESTS))
+TEST_ASM_ALL:= $(TEST_ASM) $(TEST_ASM_O) $(TEST_ASM_O2) $(TEST_ASM_mmmx) $(TEST_ASM_msse) $(TEST_ASM_mmmx_msse) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse) $(TEST_ASM_O2_mmmx_call) $(TEST_ASM_O2_mmmx_msse_call)
+TEST_ASM_MOST:= $(TEST_ASM_O) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse) $(TEST_ASM_O2_mmmx_call) $(TEST_ASM_O2_mmmx_msse_call)
TEST_OBJ:=$(patsubst %.c, tests/%.o, $(TESTS))
TEST_ELF:=$(patsubst %.c, tests/%.elf, $(TESTS))
LINUX_ELF:=$(patsubst %.c, tests/%.elf, $(LINUX_TESTS))
@@ -128,48 +135,56 @@ FAIL_SRCS:=$(patsubst %, tests/%, $(FAIL_TESTS))
FAIL_OUT:=$(patsubst %.c, tests/%.out, $(FAIL_TESTS))
+ROMCC_OPTS=-fmax-allocation-passes=8 -fdebug-live-range-conflicts
+
$(TEST_ASM): %.S: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -o $@ $< > $*.debug
$(TEST_ASM_O): %.S-O: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O -o $@ $< > $*.debug
$(TEST_ASM_O2): %.S-O2: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O2 -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O2 -o $@ $< > $*.debug
$(TEST_ASM_mmmx): %.S-mmmx: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -mmmx -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -mmmx -o $@ $< > $*.debug
$(TEST_ASM_msse): %.S-msse: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -msse -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -msse -o $@ $< > $*.debug
$(TEST_ASM_mmmx_msse): %.S-mmmx-msse: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -mmmx -msse -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -mmmx -msse -o $@ $< > $*.debug
$(TEST_ASM_O_mmmx): %.S-O-mmmx: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O -mmmx -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O -mmmx -o $@ $< > $*.debug
$(TEST_ASM_O_msse): %.S-O-msse: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O -msse -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O -msse -o $@ $< > $*.debug
$(TEST_ASM_O_mmmx_msse): %.S-O-mmmx-msse: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O -mmmx -msse -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O -mmmx -msse -o $@ $< > $*.debug
$(TEST_ASM_O2_mmmx): %.S-O2-mmmx: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O2 -mmmx -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O2 -mmmx -o $@ $< > $*.debug
$(TEST_ASM_O2_msse): %.S-O2-msse: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O2 -msse -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O2 -msse -o $@ $< > $*.debug
$(TEST_ASM_O2_mmmx_msse): %.S-O2-mmmx-msse: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O2 -mmmx -msse -o $@ $< > $*.debug
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O2 -mmmx -msse -o $@ $< > $*.debug
+
+$(TEST_ASM_O2_mmmx_call): %.S-O2-mmmx-call: %.c romcc
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O2 -mmmx -fno-always-inline -o $@ $< > $*.debug
+
+$(TEST_ASM_O2_mmmx_msse_call): %.S-O2-mmmx-msse-call: %.c romcc
+ export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -O2 -mmmx -msse -fno-always-inline -o $@ $< > $*.debug
$(FAIL_OUT): %.out: %.c romcc
- export ALLOC_CHECK_=2; if ./romcc -O2 -o $*.S $< > $*.debug 2> $@ ; then exit 1 ; else exit 0 ; fi
+ export ALLOC_CHECK_=2; if ./romcc $(ROMCC_OPTS) -O2 -o $*.S $< > $*.debug 2> $@ ; then exit 1 ; else exit 0 ; fi
$(TEST_OBJ): %.o: %.S-O2-mmmx
as $< -o $@
diff --git a/util/romcc/romcc.c b/util/romcc/romcc.c
index db7d61131e..648f7cae44 100644
--- a/util/romcc/romcc.c
+++ b/util/romcc/romcc.c
@@ -11,15 +11,11 @@
#include <string.h>
#include <limits.h>
-#define DEBUG_ERROR_MESSAGES 0
-#define DEBUG_COLOR_GRAPH 0
-#define DEBUG_SCC 0
-#define DEBUG_CONSISTENCY 1
-#define DEBUG_RANGE_CONFLICTS 0
-#define DEBUG_COALESCING 0
+#define MAX_ALLOCATION_PASSES 100
+
+#define DEBUG_CONSISTENCY 2
#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"
@@ -421,8 +417,8 @@ struct token {
* Not seen outside of expressions.
*/
-#define OP_CALL 72
-/* OP_CALL performs a procedure call.
+#define OP_FCALL 72
+/* OP_FCALL performs a procedure call.
* MISC(0) holds a pointer to the OP_LIST of a function
* RHS(x) holds argument x of a function
*
@@ -437,30 +433,52 @@ struct token {
/* statements */
#define OP_LIST 80
-/* OP_LIST Holds a list of statements, and a result value.
+/* OP_LIST Holds a list of statements that compose a function, and a result value.
* RHS(0) holds the list of statements.
* MISC(0) holds the value of the statements.
+ * A list of all functions is maintained.
*/
-#define OP_BRANCH 81 /* branch */
+#define OP_BRANCH 81 /* an unconditional branch */
/* For branch instructions
* TARG(0) holds the branch target.
- * RHS(0) if present holds the branch condition.
* ->next holds where to branch to if the branch is not taken.
- * The branch target can only be a decl...
+ * The branch target can only be a label
+ */
+
+#define OP_CBRANCH 82 /* a conditional branch */
+/* For conditional branch instructions
+ * RHS(0) holds the branch condition.
+ * TARG(1) holds the branch target.
+ * ->next holds where to branch to if the branch is not taken.
+ * The branch target can only be a label
+ */
+
+#define OP_CALL 83 /* an uncontional branch that will return */
+/* For call instructions
+ * MISC(0) holds the OP_RET that returns from the branch
+ * TARG(0) holds the branch target.
+ * ->next holds where to branch to if the branch is not taken.
+ * The branch target can only be a label
+ */
+
+#define OP_RET 84 /* an uncontinonal branch through a variable back to an OP_CALL */
+/* For call instructions
+ * RHS(0) holds the variable with the return address
+ * The branch target can only be a label
*/
-#define OP_LABEL 83
+#define OP_LABEL 86
/* OP_LABEL is a triple that establishes an target for branches.
* ->use is the list of all branches that use this label.
*/
-#define OP_ADECL 84
-/* OP_DECL is a triple that establishes an lvalue for assignments.
+#define OP_ADECL 87
+/* OP_ADECL is a triple that establishes an lvalue for assignments.
* ->use is a list of statements that use the variable.
*/
-#define OP_SDECL 85
+#define OP_SDECL 88
/* OP_SDECL is a triple that establishes a variable of static
* storage duration.
* ->use is a list of statements that use the variable.
@@ -468,12 +486,12 @@ struct token {
*/
-#define OP_PHI 86
+#define OP_PHI 89
/* OP_PHI is a triple used in SSA form code.
* It is used when multiple code paths merge and a variable needs
* a single assignment from any of those code paths.
* The operation is a cross between OP_DECL and OP_WRITE, which
- * is what OP_PHI is geneared from.
+ * is what OP_PHI is generated from.
*
* RHS(x) points to the value from code path x
* The number of RHS entries is the number of control paths into the block
@@ -531,6 +549,8 @@ struct op_info {
#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 */
+#define BRANCH 32 /* Triple is a branch instruction */
+#define CBRANCH 64 /* Triple is a conditional branch instruction */
unsigned char lhs, rhs, misc, targ;
};
@@ -599,13 +619,15 @@ static const struct op_info table_ops[] = {
[OP_COND ] = OP( 0, 3, 0, 0, 0 | DEF | BLOCK, "cond"),
[OP_COMMA ] = OP( 0, 2, 0, 0, 0 | DEF | BLOCK, "comma"),
/* 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_FCALL ] = OP(-1, -1, 1, 0, 0 | BLOCK, "fcall"),
+/* The sizes of OP_FCALL and OP_VAL_VEC depend upon context */
[OP_VAL_VEC ] = OP( 0, -1, 0, 0, 0 | BLOCK | STRUCTURAL, "valvec"),
[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_BRANCH ] = OP( 0, 0, 0, 1, PURE | BLOCK | BRANCH, "branch"),
+[OP_CBRANCH ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "cbranch"),
+[OP_CALL ] = OP( 0, 0, 1, 1, PURE | BLOCK | BRANCH, "call"),
+[OP_RET ] = OP( 0, 1, 0, 0, PURE | BLOCK | BRANCH, "ret"),
[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"),
@@ -624,17 +646,17 @@ static const struct op_info table_ops[] = {
[OP_SET_ULESSEQ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_ulesseq"),
[OP_SET_SMOREEQ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_smoreq"),
[OP_SET_UMOREEQ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_umoreq"),
-[OP_JMP ] = OP( 0, 0, 0, 1, PURE | BLOCK, "jmp"),
-[OP_JMP_EQ ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_eq"),
-[OP_JMP_NOTEQ ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_noteq"),
-[OP_JMP_SLESS ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_sless"),
-[OP_JMP_ULESS ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_uless"),
-[OP_JMP_SMORE ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_smore"),
-[OP_JMP_UMORE ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_umore"),
-[OP_JMP_SLESSEQ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_slesseq"),
-[OP_JMP_ULESSEQ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_ulesseq"),
-[OP_JMP_SMOREEQ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_smoreq"),
-[OP_JMP_UMOREEQ] = OP( 0, 1, 0, 1, PURE | BLOCK, "jmp_umoreq"),
+[OP_JMP ] = OP( 0, 0, 0, 1, PURE | BLOCK | BRANCH, "jmp"),
+[OP_JMP_EQ ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_eq"),
+[OP_JMP_NOTEQ ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_noteq"),
+[OP_JMP_SLESS ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_sless"),
+[OP_JMP_ULESS ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_uless"),
+[OP_JMP_SMORE ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_smore"),
+[OP_JMP_UMORE ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_umore"),
+[OP_JMP_SLESSEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_slesseq"),
+[OP_JMP_ULESSEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_ulesseq"),
+[OP_JMP_SMOREEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_smoreq"),
+[OP_JMP_UMOREEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_umoreq"),
[OP_INB ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "__inb"),
[OP_INW ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "__inw"),
@@ -749,8 +771,9 @@ struct block_set {
};
struct block {
struct block *work_next;
- struct block *left, *right;
struct triple *first, *last;
+ int edge_count;
+ struct block_set *edges;
int users;
struct block_set *use;
struct block_set *idominates;
@@ -790,9 +813,19 @@ struct hash_entry {
#define HASH_TABLE_SIZE 2048
-struct compile_state {
+struct compiler_state {
const char *label_prefix;
const char *ofilename;
+ unsigned long flags;
+ unsigned long debug;
+ unsigned long max_allocation_passes;
+};
+struct arch_state {
+ unsigned long features;
+};
+struct compile_state {
+ struct compiler_state *compiler;
+ struct arch_state *arch;
FILE *output;
struct file_state *file;
struct occurance *last_occurance;
@@ -804,42 +837,45 @@ struct compile_state {
struct hash_entry *i_continue;
struct hash_entry *i_break;
struct hash_entry *i_default;
+ struct hash_entry *i_return;
int scope_depth;
int if_depth, if_value;
int macro_line;
struct file_state *macro_file;
+ struct triple *functions;
struct triple *main_function;
struct triple *first;
+ struct triple *global_pool;
struct block *first_block, *last_block;
int last_vertex;
- unsigned long features;
- int debug;
- int optimize;
};
/* visibility global/local */
/* static/auto duration */
/* typedef, register, inline */
#define STOR_SHIFT 0
-#define STOR_MASK 0x000f
+#define STOR_MASK 0x001f
/* Visibility */
#define STOR_GLOBAL 0x0001
/* Duration */
#define STOR_PERM 0x0002
+/* Definition locality */
+#define STOR_NONLOCAL 0x0004 /* The definition is not in this translation unit */
/* Storage specifiers */
#define STOR_AUTO 0x0000
#define STOR_STATIC 0x0002
-#define STOR_EXTERN 0x0003
-#define STOR_REGISTER 0x0004
-#define STOR_TYPEDEF 0x0008
-#define STOR_INLINE 0x000c
-
-#define QUAL_SHIFT 4
-#define QUAL_MASK 0x0070
+#define STOR_LOCAL 0x0003
+#define STOR_EXTERN 0x0007
+#define STOR_INLINE 0x0008
+#define STOR_REGISTER 0x0010
+#define STOR_TYPEDEF 0x0018
+
+#define QUAL_SHIFT 5
+#define QUAL_MASK 0x00e0
#define QUAL_NONE 0x0000
-#define QUAL_CONST 0x0010
-#define QUAL_VOLATILE 0x0020
-#define QUAL_RESTRICT 0x0040
+#define QUAL_CONST 0x0020
+#define QUAL_VOLATILE 0x0040
+#define QUAL_RESTRICT 0x0080
#define TYPE_SHIFT 8
#define TYPE_MASK 0x1f00
@@ -974,28 +1010,191 @@ static struct triple *transform_to_arch_instruction(
-#define DEBUG_ABORT_ON_ERROR 0x0001
-#define DEBUG_INTERMEDIATE_CODE 0x0002
-#define DEBUG_CONTROL_FLOW 0x0004
-#define DEBUG_BASIC_BLOCKS 0x0008
-#define DEBUG_FDOMINATORS 0x0010
-#define DEBUG_RDOMINATORS 0x0020
-#define DEBUG_TRIPLES 0x0040
-#define DEBUG_INTERFERENCE 0x0080
-#define DEBUG_ARCH_CODE 0x0100
-#define DEBUG_CODE_ELIMINATION 0x0200
-#define DEBUG_INSERTED_COPIES 0x0400
+#define DEBUG_ABORT_ON_ERROR 0x00000001
+#define DEBUG_BASIC_BLOCKS 0x00000002
+#define DEBUG_FDOMINATORS 0x00000004
+#define DEBUG_RDOMINATORS 0x00000008
+#define DEBUG_TRIPLES 0x00000010
+#define DEBUG_INTERFERENCE 0x00000020
+#define DEBUG_SCC_TRANSFORM 0x00000040
+#define DEBUG_SCC_TRANSFORM2 0x00000080
+#define DEBUG_REBUILD_SSA_FORM 0x00000100
+#define DEBUG_INLINE 0x00000200
+#define DEBUG_RANGE_CONFLICTS 0x00000400
+#define DEBUG_RANGE_CONFLICTS2 0x00000800
+#define DEBUG_COLOR_GRAPH 0x00001000
+#define DEBUG_COLOR_GRAPH2 0x00002000
+#define DEBUG_COALESCING 0x00004000
+#define DEBUG_COALESCING2 0x00008000
+
+#define DEBUG_DEFAULT ( \
+ DEBUG_ABORT_ON_ERROR | \
+ DEBUG_BASIC_BLOCKS | \
+ DEBUG_FDOMINATORS | \
+ DEBUG_RDOMINATORS | \
+ DEBUG_TRIPLES | \
+ 0 )
+
+#define COMPILER_ELIMINATE_INEFECTUAL_CODE 0x00000001
+#define COMPILER_SIMPLIFY 0x00000002
+#define COMPILER_SCC_TRANSFORM 0x00000004
+#define COMPILER_INLINE 0x00000008
+#define COMPILER_ALWAYS_INLINE 0x00000010
+#define COMPILER_SIMPLIFY_OP 0x00000020
+#define COMPILER_SIMPLIFY_PHI 0x00000040
+#define COMPILER_SIMPLIFY_LABEL 0x00000080
+#define COMPILER_SIMPLIFY_BRANCH 0x00000100
+#define COMPILER_SIMPLIFY_COPY 0x00000200
+#define COMPILER_SIMPLIFY_ARITH 0x00000400
+#define COMPILER_SIMPLIFY_SHIFT 0x00000800
+#define COMPILER_SIMPLIFY_BITWISE 0x00001000
+#define COMPILER_SIMPLIFY_LOGICAL 0x00002000
+
+#define COMPILER_DEFAULT_FLAGS ( \
+ COMPILER_ELIMINATE_INEFECTUAL_CODE | \
+ COMPILER_INLINE | \
+ COMPILER_ALWAYS_INLINE | \
+ COMPILER_SIMPLIFY_OP | \
+ COMPILER_SIMPLIFY_PHI | \
+ COMPILER_SIMPLIFY_LABEL | \
+ COMPILER_SIMPLIFY_BRANCH | \
+ COMPILER_SIMPLIFY_COPY | \
+ COMPILER_SIMPLIFY_ARITH | \
+ COMPILER_SIMPLIFY_SHIFT | \
+ COMPILER_SIMPLIFY_BITWISE | \
+ COMPILER_SIMPLIFY_LOGICAL | \
+ 0 )
#define GLOBAL_SCOPE_DEPTH 1
#define FUNCTION_SCOPE_DEPTH (GLOBAL_SCOPE_DEPTH + 1)
static void compile_file(struct compile_state *old_state, const char *filename, int local);
+
+
+static void init_compiler_state(struct compiler_state *compiler)
+{
+ memset(compiler, 0, sizeof(*compiler));
+ compiler->label_prefix = "";
+ compiler->ofilename = "auto.inc";
+ compiler->flags = COMPILER_DEFAULT_FLAGS;
+ compiler->debug = 0;
+ compiler->max_allocation_passes = MAX_ALLOCATION_PASSES;
+
+}
+
+struct compiler_flag {
+ const char *name;
+ unsigned long flag;
+};
+static int set_flag(
+ const struct compiler_flag *ptr, unsigned long *flags,
+ int act, const char *flag)
+{
+ int result = -1;
+ for(; ptr->name; ptr++) {
+ if (strcmp(ptr->name, flag) == 0) {
+ break;
+ }
+ }
+ if (ptr->name) {
+ result = 0;
+ *flags &= ~(ptr->flag);
+ if (act) {
+ *flags |= ptr->flag;
+ }
+ }
+ return result;
+}
+
+static int compiler_encode_flag(
+ struct compiler_state *compiler, const char *flag)
+{
+ static const struct compiler_flag flags[] = {
+ { "eliminate-inefectual-code", COMPILER_ELIMINATE_INEFECTUAL_CODE },
+ { "simplify", COMPILER_SIMPLIFY },
+ { "scc-transform", COMPILER_SCC_TRANSFORM },
+ { "inline", COMPILER_INLINE },
+ { "always-inline", COMPILER_ALWAYS_INLINE },
+ { "simplify-op", COMPILER_SIMPLIFY_OP },
+ { "simplify-phi", COMPILER_SIMPLIFY_PHI },
+ { "simplify-label", COMPILER_SIMPLIFY_LABEL },
+ { "simplify-branch", COMPILER_SIMPLIFY_BRANCH },
+ { "simplify-copy", COMPILER_SIMPLIFY_COPY },
+ { "simplify-arith", COMPILER_SIMPLIFY_ARITH },
+ { "simplify-shift", COMPILER_SIMPLIFY_SHIFT },
+ { "simplify-bitwise", COMPILER_SIMPLIFY_BITWISE },
+ { "simplify-logical", COMPILER_SIMPLIFY_LOGICAL },
+ { 0, 0 },
+ };
+ static const struct compiler_flag opt_flags[] = {
+ { "-O", COMPILER_SIMPLIFY },
+ { "-O2", COMPILER_SIMPLIFY | COMPILER_SCC_TRANSFORM },
+ { 0, 0, },
+ };
+ static const struct compiler_flag debug_flags[] = {
+ { "abort-on-error", DEBUG_ABORT_ON_ERROR },
+ { "basic-blocks", DEBUG_BASIC_BLOCKS },
+ { "fdominators", DEBUG_FDOMINATORS },
+ { "rdominators", DEBUG_RDOMINATORS },
+ { "triples", DEBUG_TRIPLES },
+ { "interference", DEBUG_INTERFERENCE },
+ { "scc-transform", DEBUG_SCC_TRANSFORM },
+ { "scc-transform2", DEBUG_SCC_TRANSFORM2 },
+ { "rebuild-ssa-form", DEBUG_REBUILD_SSA_FORM },
+ { "inline", DEBUG_INLINE },
+ { "live-range-conflicts", DEBUG_RANGE_CONFLICTS },
+ { "live-range-conflicts2", DEBUG_RANGE_CONFLICTS2 },
+ { "color-graph", DEBUG_COLOR_GRAPH },
+ { "color-graph2", DEBUG_COLOR_GRAPH2 },
+ { "coalescing", DEBUG_COALESCING },
+ { "coalescing2", DEBUG_COALESCING2 },
+ { 0, 0 },
+ };
+ int act;
+ int result;
+
+ act = 1;
+ result = -1;
+ if (strncmp(flag, "no-", 3) == 0) {
+ flag += 3;
+ act = 0;
+ }
+ if (strncmp(flag, "-O", 2) == 0) {
+ result = set_flag(opt_flags, &compiler->flags, act, flag);
+ }
+ else if (act && strncmp(flag, "label-prefix=", 13) == 0) {
+ result = 0;
+ compiler->label_prefix = flag + 13;
+ }
+ else if (act && strncmp(flag, "max-allocation-passes=", 22) == 0) {
+ unsigned long max_passes;
+ char *end;
+ max_passes = strtoul(flag + 22, &end, 10);
+ if (end[0] == '\0') {
+ result = 0;
+ compiler->max_allocation_passes = max_passes;
+ }
+ }
+ else if (act && strcmp(flag, "debug") == 0) {
+ result = 0;
+ compiler->debug |= DEBUG_DEFAULT;
+ }
+ else if (strncmp(flag, "debug-", 6) == 0) {
+ flag += 6;
+ result = set_flag(debug_flags, &compiler->debug, act, flag);
+ }
+ else {
+ result = set_flag(flags, &compiler->flags, act, flag);
+ }
+ return result;
+}
+
static void do_cleanup(struct compile_state *state)
{
if (state->output) {
fclose(state->output);
- unlink(state->ofilename);
+ unlink(state->compiler->ofilename);
}
}
@@ -1021,12 +1220,10 @@ static void loc(FILE *fp, struct compile_state *state, struct triple *triple)
int col;
if (triple && triple->occurance) {
struct occurance *spot;
- spot = triple->occurance;
- while(spot->parent) {
- spot = spot->parent;
+ for(spot = triple->occurance; spot; spot = spot->parent) {
+ fprintf(fp, "%s:%d.%d: ",
+ spot->filename, spot->line, spot->col);
}
- fprintf(fp, "%s:%d.%d: ",
- spot->filename, spot->line, spot->col);
return;
}
if (!state->file) {
@@ -1037,12 +1234,13 @@ static void loc(FILE *fp, struct compile_state *state, struct triple *triple)
state->file->report_name, state->file->report_line, col);
}
-static void romcc_internal_error(struct compile_state *state, struct triple *ptr,
+static void internal_error(struct compile_state *state, struct triple *ptr,
char *fmt, ...)
{
va_list args;
va_start(args, fmt);
loc(stderr, state, ptr);
+ fputc('\n', stderr);
if (ptr) {
fprintf(stderr, "%p %s ", ptr, tops(ptr->op));
}
@@ -1055,7 +1253,7 @@ static void romcc_internal_error(struct compile_state *state, struct triple *ptr
}
-static void romcc_internal_warning(struct compile_state *state, struct triple *ptr,
+static void internal_warning(struct compile_state *state, struct triple *ptr,
char *fmt, ...)
{
va_list args;
@@ -1072,26 +1270,27 @@ static void romcc_internal_warning(struct compile_state *state, struct triple *p
-static void romcc_error(struct compile_state *state, struct triple *ptr,
+static void 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)) {
+ fputc('\n', stderr);
+ if (ptr && (state->compiler->debug & DEBUG_ABORT_ON_ERROR)) {
fprintf(stderr, "%p %s ", ptr, tops(ptr->op));
}
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
do_cleanup(state);
- if (state->debug & DEBUG_ABORT_ON_ERROR) {
+ if (state->compiler->debug & DEBUG_ABORT_ON_ERROR) {
abort();
}
exit(1);
}
-static void romcc_warning(struct compile_state *state, struct triple *ptr,
+static void warning(struct compile_state *state, struct triple *ptr,
char *fmt, ...)
{
va_list args;
@@ -1103,17 +1302,6 @@ static void romcc_warning(struct compile_state *state, struct triple *ptr,
va_end(args);
}
-#if DEBUG_ERROR_MESSAGES
-# 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 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__)
static void valid_op(struct compile_state *state, int op)
@@ -1238,18 +1426,22 @@ static void unuse_triple(struct triple *used, struct triple *unuser)
static void put_occurance(struct occurance *occurance)
{
- occurance->count -= 1;
- if (occurance->count <= 0) {
- if (occurance->parent) {
- put_occurance(occurance->parent);
+ if (occurance) {
+ occurance->count -= 1;
+ if (occurance->count <= 0) {
+ if (occurance->parent) {
+ put_occurance(occurance->parent);
+ }
+ xfree(occurance);
}
- xfree(occurance);
}
}
static void get_occurance(struct occurance *occurance)
{
- occurance->count += 1;
+ if (occurance) {
+ occurance->count += 1;
+ }
}
@@ -1299,35 +1491,48 @@ static struct occurance *new_occurance(struct compile_state *state)
}
static struct occurance *inline_occurance(struct compile_state *state,
- struct occurance *new, struct occurance *orig)
+ struct occurance *base, struct occurance *top)
{
struct occurance *result, *last;
+ if (top->parent) {
+ internal_error(state, 0, "inlining an already inlined function?");
+ }
+ /* If I have a null base treat it that way */
+ if ((base->parent == 0) &&
+ (base->col == 0) &&
+ (base->line == 0) &&
+ (base->function[0] == '\0') &&
+ (base->filename[0] == '\0')) {
+ base = 0;
+ }
+ /* See if I can reuse the last occurance I had */
last = state->last_occurance;
if (last &&
- (last->parent == orig) &&
- (last->col == new->col) &&
- (last->line == new->line) &&
- (last->function == new->function) &&
- (last->filename == new->filename)) {
+ (last->parent == base) &&
+ (last->col == top->col) &&
+ (last->line == top->line) &&
+ (last->function == top->function) &&
+ (last->filename == top->filename)) {
get_occurance(last);
return last;
}
+ /* I can't reuse the last occurance so free it */
if (last) {
state->last_occurance = 0;
put_occurance(last);
}
- get_occurance(orig);
+ /* Generate a new occurance structure */
+ get_occurance(base);
result = xmalloc(sizeof(*result), "occurance");
result->count = 2;
- result->filename = new->filename;
- result->function = new->function;
- result->line = new->line;
- result->col = new->col;
- result->parent = orig;
+ result->filename = top->filename;
+ result->function = top->function;
+ result->line = top->line;
+ result->col = top->col;
+ result->parent = base;
state->last_occurance = result;
return result;
}
-
static struct occurance dummy_occurance = {
.count = 2,
@@ -1370,26 +1575,17 @@ static unsigned short triple_sizes(struct compile_state *state,
targ = table_ops[op].targ;
- if (op == OP_CALL) {
- struct type *param;
- rhs = 0;
- param = type->right;
- while((param->type & TYPE_MASK) == TYPE_PRODUCT) {
- rhs++;
- param = param->right;
- }
- if ((param->type & TYPE_MASK) != TYPE_VOID) {
- rhs++;
- }
+ if (op == OP_FCALL) {
+ rhs = rhs_wanted;
lhs = 0;
- if ((type->left->type & TYPE_MASK) == TYPE_STRUCT) {
+ if ((type->type & TYPE_MASK) == TYPE_STRUCT) {
lhs = type->left->elements;
}
}
else if (op == OP_VAL_VEC) {
rhs = type->elements;
}
- else if ((op == OP_BRANCH) || (op == OP_PHI)) {
+ else if (op == OP_PHI) {
rhs = rhs_wanted;
}
else if (op == OP_ASM) {
@@ -1496,20 +1692,20 @@ static struct triple *branch(struct compile_state *state,
struct triple *targ, struct triple *test)
{
struct triple *ret;
- ret = new_triple(state, OP_BRANCH, &void_type, -1, test?1:0);
if (test) {
+ ret = new_triple(state, OP_CBRANCH, &void_type, -1, 1);
RHS(ret, 0) = test;
+ } else {
+ ret = new_triple(state, OP_BRANCH, &void_type, -1, 0);
}
TARG(ret, 0) = targ;
/* record the branch target was used */
if (!targ || (targ->op != OP_LABEL)) {
internal_error(state, 0, "branch not to label");
- use_triple(targ, ret);
}
return ret;
}
-
static void insert_triple(struct compile_state *state,
struct triple *first, struct triple *ptr)
{
@@ -1521,8 +1717,8 @@ static void insert_triple(struct compile_state *state,
ptr->prev = first->prev;
ptr->prev->next = ptr;
ptr->next->prev = ptr;
- if ((ptr->prev->op == OP_BRANCH) &&
- TRIPLE_RHS(ptr->prev->sizes)) {
+
+ if ((ptr->prev->op == OP_CBRANCH) || (ptr->prev->op == OP_CALL)) {
unuse_triple(first, ptr->prev);
use_triple(ptr, ptr->prev);
}
@@ -1544,13 +1740,13 @@ static struct block *block_of_triple(struct compile_state *state,
struct triple *ins)
{
struct triple *first;
- if (!ins) {
+ if (!ins || ins == &zero_triple) {
return 0;
}
first = state->first;
while(ins != first && !triple_stores_block(state, ins)) {
if (ins == ins->prev) {
- internal_error(state, 0, "ins == ins->prev?");
+ internal_error(state, ins, "ins == ins->prev?");
}
ins = ins->prev;
}
@@ -1676,9 +1872,79 @@ static void display_triple(FILE *fp, struct triple *ins)
fflush(fp);
}
+static void display_triple_changes(
+ FILE *fp, const struct triple *new, const struct triple *orig)
+{
+
+ int new_count, orig_count;
+ new_count = TRIPLE_SIZE(new->sizes);
+ orig_count = TRIPLE_SIZE(orig->sizes);
+ if ((new->op != orig->op) ||
+ (new_count != orig_count) ||
+ (memcmp(orig->param, new->param,
+ orig_count * sizeof(orig->param[0])) != 0) ||
+ (memcmp(&orig->u, &new->u, sizeof(orig->u)) != 0))
+ {
+ struct occurance *ptr;
+ int i, min_count, indent;
+ fprintf(fp, "(%p)", orig);
+ if (orig->op == new->op) {
+ fprintf(fp, " %-11s", tops(orig->op));
+ } else {
+ fprintf(fp, " [%-10s %-10s]",
+ tops(new->op), tops(orig->op));
+ }
+ min_count = new_count;
+ if (min_count > orig_count) {
+ min_count = orig_count;
+ }
+ for(indent = i = 0; i < min_count; i++) {
+ if (orig->param[i] == new->param[i]) {
+ fprintf(fp, " %-11p",
+ orig->param[i]);
+ indent += 12;
+ } else {
+ fprintf(fp, " [%-10p %-10p]",
+ new->param[i],
+ orig->param[i]);
+ indent += 24;
+ }
+ }
+ for(; i < orig_count; i++) {
+ fprintf(fp, " [%-9p]", orig->param[i]);
+ indent += 12;
+ }
+ for(; i < new_count; i++) {
+ fprintf(fp, " [%-9p]", new->param[i]);
+ indent += 12;
+ }
+ if ((new->op == OP_INTCONST)||
+ (new->op == OP_ADDRCONST)) {
+ fprintf(fp, " <0x%08lx>",
+ (unsigned long)(new->u.cval));
+ indent += 13;
+ }
+ for(;indent < 36; indent++) {
+ putc(' ', fp);
+ }
+ fprintf(fp, " @");
+ for(ptr = orig->occurance; ptr; ptr = ptr->parent) {
+ fprintf(fp, " %s,%s:%d.%d",
+ ptr->function,
+ ptr->filename,
+ ptr->line,
+ ptr->col);
+
+ }
+ fprintf(fp, "\n");
+ fflush(fp);
+ }
+}
+
static void display_func(FILE *fp, struct triple *func)
{
struct triple *first, *ins;
+ fprintf(fp, "display_func %s\n", func->type->type_ident->name);
first = ins = RHS(func, 0);
do {
display_triple(fp, ins);
@@ -1704,30 +1970,23 @@ static int triple_is_pure(struct compile_state *state, struct triple *ins, unsig
static int triple_is_branch(struct compile_state *state, struct triple *ins)
{
- /* This function is used to determine which triples need
- * a register.
- */
- int is_branch;
+ /* Is this triple a branch instruction? */
valid_ins(state, ins);
- is_branch = (table_ops[ins->op].targ != 0);
- return is_branch;
+ return (table_ops[ins->op].flags & BRANCH) != 0;
}
static int triple_is_cond_branch(struct compile_state *state, struct triple *ins)
{
- /* A conditional branch has the condition argument as a single
- * RHS parameter.
- */
- return triple_is_branch(state, ins) &&
- (TRIPLE_RHS(ins->sizes) == 1);
+ /* Is this triple a conditional branch instruction? */
+ valid_ins(state, ins);
+ return (table_ops[ins->op].flags & CBRANCH) != 0;
}
static int triple_is_uncond_branch(struct compile_state *state, struct triple *ins)
{
- /* A unconditional branch has no RHS parameters.
- */
- return triple_is_branch(state, ins) &&
- (TRIPLE_RHS(ins->sizes) == 0);
+ /* Is this triple a unconditional branch instruction? */
+ valid_ins(state, ins);
+ return (table_ops[ins->op].flags & CBRANCH) == 0;
}
static int triple_is_def(struct compile_state *state, struct triple *ins)
@@ -1796,22 +2055,43 @@ static struct triple **triple_targ(struct compile_state *state,
ret = 0;
count = TRIPLE_TARG(ins->sizes);
vector = &TARG(ins, 0);
- if (count) {
+ if (!ret &&
+ ((ins->op == OP_CALL) || (table_ops[ins->op].flags & CBRANCH))) {
+ if (!last) {
+ ret = &ins->next;
+ } else if (last == &ins->next) {
+ last = 0;
+ }
+ }
+ if (!ret && count) {
if (!last) {
ret = vector;
}
else if ((last >= vector) && (last < (vector + count - 1))) {
ret = last + 1;
}
- else if ((last == (vector + count - 1)) &&
- TRIPLE_RHS(ins->sizes)) {
- ret = &ins->next;
+ else if (last == vector + count - 1) {
+ last = 0;
+ }
+ }
+ if (!ret && (ins->op == OP_RET)) {
+ struct triple_set *use;
+ for(use = ins->use; use; use = use->next) {
+ if (use->member->op != OP_CALL) {
+ continue;
+ }
+ if (!last) {
+ ret = &use->member->next;
+ break;
+ }
+ else if (last == &use->member->next) {
+ last = 0;
+ }
}
}
return ret;
}
-
static void verify_use(struct compile_state *state,
struct triple *user, struct triple *used)
{
@@ -1869,6 +2149,7 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
struct triple_set *set, *next;
struct triple **expr;
struct block *block;
+ valid_ins(state, ptr);
/* Make certain the we are not the first or last element of a block */
block = block_of_triple(state, ptr);
if (block) {
@@ -1903,13 +2184,14 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
}
expr = triple_targ(state, ptr, 0);
for(; expr; expr = triple_targ(state, ptr, expr)) {
- if (*expr) {
+ if (*expr){
unuse_triple(*expr, ptr);
}
}
/* Reomve ptr from use chains where it is used */
for(set = ptr->use; set; set = next) {
next = set->next;
+ valid_ins(state, set->member);
expr = triple_rhs(state, set->member, 0);
for(; expr; expr = triple_rhs(state, set->member, expr)) {
if (*expr == ptr) {
@@ -1939,7 +2221,8 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
free_triple(state, ptr);
}
-static void print_triple(struct compile_state *state, struct triple *ptr);
+static void print_triples(struct compile_state *state);
+static void print_blocks(struct compile_state *state, const char *func, FILE *fp);
#define TOK_UNKNOWN 0
#define TOK_SPACE 1
@@ -3364,6 +3647,7 @@ static void preprocess(struct compile_state *state, int index)
meat(state, index, TOK_LIT_STRING);
name = xmalloc(tk->str_len, "report_name");
token = tk->val.str + 1;
+ base = strrchr(token, '/');
name_len = tk->str_len - 2;
if (base != 0) {
dir_len = base - token;
@@ -3846,7 +4130,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 = {
+static struct type void_ptr_type = {
+ .type = TYPE_POINTER,
+ .left = &void_type,
+};
+
+static struct type void_func_type = {
.type = TYPE_FUNCTION,
.left = &void_type,
.right = &void_type,
@@ -3890,6 +4179,9 @@ static void stor_of(FILE *fp, struct type *type)
case STOR_STATIC:
fprintf(fp, "static ");
break;
+ case STOR_LOCAL:
+ fprintf(fp, "local ");
+ break;
case STOR_EXTERN:
fprintf(fp, "extern ");
break;
@@ -3899,9 +4191,18 @@ static void stor_of(FILE *fp, struct type *type)
case STOR_TYPEDEF:
fprintf(fp, "typedef ");
break;
- case STOR_INLINE:
+ case STOR_INLINE | STOR_LOCAL:
fprintf(fp, "inline ");
break;
+ case STOR_INLINE | STOR_STATIC:
+ fprintf(fp, "static inline");
+ break;
+ case STOR_INLINE | STOR_EXTERN:
+ fprintf(fp, "extern inline");
+ break;
+ default:
+ fprintf(fp, "stor:%x", type->type & STOR_MASK);
+ break;
}
}
static void qual_of(FILE *fp, struct type *type)
@@ -4433,7 +4734,14 @@ static struct triple *integral_promotion(
int_type = type->type & ~TYPE_MASK;
int_type |= do_integral_promotion(type->type);
if (int_type != type->type) {
- def->type = new_type(int_type, 0, 0);
+ if (def->op != OP_LOAD) {
+ def->type = new_type(int_type, 0, 0);
+ }
+ else {
+#warning "FIXME can I just cast all operands like this?"
+ def = triple(state, OP_COPY,
+ new_type(int_type, 0, 0), def, 0);
+ }
}
}
return def;
@@ -4967,7 +5275,7 @@ static int expr_depth(struct compile_state *state, struct triple *ins)
rdepth = expr_depth(state, RHS(ins, 1));
count = (ldepth >= rdepth)? ldepth : rdepth;
}
- else if (ins->op == OP_CALL) {
+ else if (ins->op == OP_FCALL) {
/* Don't figure the depth of a call just guess it is huge */
count = 1000;
}
@@ -4991,17 +5299,18 @@ static struct triple *flatten(
struct compile_state *state, struct triple *first, struct triple *ptr);
static struct triple *flatten_generic(
- struct compile_state *state, struct triple *first, struct triple *ptr)
+ struct compile_state *state, struct triple *first, struct triple *ptr,
+ int ignored)
{
struct rhs_vector {
int depth;
struct triple **ins;
} vector[MAX_RHS];
int i, rhs, lhs;
- /* Only operations with just a rhs should come here */
+ /* Only operations with just a rhs and a lhs should come here */
rhs = TRIPLE_RHS(ptr->sizes);
lhs = TRIPLE_LHS(ptr->sizes);
- if (TRIPLE_SIZE(ptr->sizes) != lhs + rhs) {
+ if (TRIPLE_SIZE(ptr->sizes) != lhs + rhs + ignored) {
internal_error(state, ptr, "unexpected args for: %d %s",
ptr->op, tops(ptr->op));
}
@@ -5125,176 +5434,10 @@ 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)
-{
- struct triple *nfunc;
- struct triple *nfirst, *ofirst;
- struct triple *new, *old;
-
-#if 0
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ copy_func _________\n");
- display_func(stdout, ofunc);
- fprintf(stdout, "__________ copy_func _________ done\n\n");
-#endif
-
- /* Make a new copy of the old function */
- nfunc = triple(state, OP_LIST, ofunc->type, 0, 0);
- nfirst = 0;
- ofirst = old = RHS(ofunc, 0);
- do {
- struct triple *new;
- struct occurance *occurance;
- int old_lhs, old_rhs;
- old_lhs = TRIPLE_LHS(old->sizes);
- old_rhs = TRIPLE_RHS(old->sizes);
- occurance = inline_occurance(state, base_occurance, old->occurance);
- new = alloc_triple(state, old->op, old->type, old_lhs, old_rhs,
- occurance);
- if (!triple_stores_block(state, new)) {
- memcpy(&new->u, &old->u, sizeof(new->u));
- }
- if (!nfirst) {
- RHS(nfunc, 0) = nfirst = new;
- }
- else {
- insert_triple(state, nfirst, new);
- }
- new->id |= TRIPLE_FLAG_FLATTENED;
-
- /* During the copy remember new as user of old */
- use_triple(old, new);
-
- /* Populate the return type if present */
- 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);
-
- /* Make a second pass to fix up any unresolved references */
- old = ofirst;
- new = nfirst;
- do {
- struct triple **oexpr, **nexpr;
- int count, i;
- /* Lookup where the copy is, to join pointers */
- count = TRIPLE_SIZE(old->sizes);
- for(i = 0; i < count; i++) {
- oexpr = &old->param[i];
- nexpr = &new->param[i];
- 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?");
- }
- use_triple(*nexpr, new);
- }
- if (!*nexpr && *oexpr) {
- internal_error(state, 0, "Could not copy %d\n", i);
- }
- }
- old = old->next;
- new = new->next;
- } while((old != ofirst) && (new != nfirst));
-
- /* Make a third pass to cleanup the extra useses */
- old = ofirst;
- 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));
- return nfunc;
-}
-
-static struct triple *flatten_call(
+static struct triple *flatten_fcall(
struct compile_state *state, struct triple *first, struct triple *ptr)
{
- /* Inline the function call */
- struct type *ptype;
- struct triple *ofunc, *nfunc, *nfirst, *param, *result;
- struct triple *end, *nend;
- int pvals, i;
-
- /* Find the triples */
- ofunc = MISC(ptr, 0);
- if (ofunc->op != OP_LIST) {
- internal_error(state, 0, "improper function");
- }
- nfunc = copy_func(state, ofunc, ptr->occurance);
- nfirst = RHS(nfunc, 0)->next;
- /* Prepend the parameter reading into the new function list */
- ptype = nfunc->type->right;
- param = RHS(nfunc, 0)->next;
- pvals = TRIPLE_RHS(ptr->sizes);
- for(i = 0; i < pvals; i++) {
- struct type *atype;
- struct triple *arg;
- atype = ptype;
- if ((ptype->type & TYPE_MASK) == TYPE_PRODUCT) {
- atype = ptype->left;
- }
- while((param->type->type & TYPE_MASK) != (atype->type & TYPE_MASK)) {
- param = param->next;
- }
- arg = RHS(ptr, i);
- flatten(state, nfirst, write_expr(state, param, arg));
- ptype = ptype->right;
- param = param->next;
- }
- result = 0;
- if ((nfunc->type->left->type & TYPE_MASK) != TYPE_VOID) {
- result = read_expr(state, MISC(nfunc,0));
- }
-#if 0
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ flatten_call _________\n");
- display_func(stdout, nfunc);
- fprintf(stdout, "__________ flatten_call _________ done\n\n");
-#endif
-
- /* Get rid of the extra triples */
- nfirst = RHS(nfunc, 0)->next;
- free_triple(state, RHS(nfunc, 0));
- RHS(nfunc, 0) = 0;
- free_triple(state, nfunc);
-
- /* Append the new function list onto the return list */
- end = first->prev;
- nend = nfirst->prev;
- end->next = nfirst;
- nfirst->prev = end;
- nend->next = first;
- first->prev = nend;
-
- return result;
+ return flatten_generic(state, first, ptr, 1);
}
static struct triple *flatten(
@@ -5327,8 +5470,8 @@ static struct triple *flatten(
case OP_COND:
ptr = flatten_cond(state, first, ptr);
break;
- case OP_CALL:
- ptr = flatten_call(state, first, ptr);
+ case OP_FCALL:
+ ptr = flatten_fcall(state, first, ptr);
break;
case OP_READ:
case OP_LOAD:
@@ -5337,15 +5480,29 @@ static struct triple *flatten(
break;
case OP_BRANCH:
use_triple(TARG(ptr, 0), ptr);
- if (TRIPLE_RHS(ptr->sizes)) {
- use_triple(RHS(ptr, 0), ptr);
- if (ptr->next != ptr) {
- use_triple(ptr->next, ptr);
- }
+ break;
+ case OP_CBRANCH:
+ RHS(ptr, 0) = flatten(state, first, RHS(ptr, 0));
+ use_triple(RHS(ptr, 0), ptr);
+ use_triple(TARG(ptr, 0), ptr);
+ if (ptr->next != ptr) {
+ use_triple(ptr->next, ptr);
+ }
+ break;
+ case OP_CALL:
+ MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
+ use_triple(MISC(ptr, 0), ptr);
+ use_triple(TARG(ptr, 0), ptr);
+ if (ptr->next != ptr) {
+ use_triple(ptr->next, ptr);
}
break;
+ case OP_RET:
+ RHS(ptr, 0) = flatten(state, first, RHS(ptr, 0));
+ use_triple(RHS(ptr, 0), ptr);
+ break;
case OP_BLOBCONST:
- insert_triple(state, state->first, ptr);
+ insert_triple(state, state->global_pool, ptr);
ptr->id |= TRIPLE_FLAG_FLATTENED;
ptr->id &= ~TRIPLE_FLAG_LOCAL;
ptr = triple(state, OP_SDECL, ptr->type, ptr, 0);
@@ -5387,7 +5544,7 @@ static struct triple *flatten(
use_triple(MISC(ptr, 0), ptr);
break;
case OP_SDECL:
- first = state->first;
+ first = state->global_pool;
MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
use_triple(MISC(ptr, 0), ptr);
insert_triple(state, first, ptr);
@@ -5398,7 +5555,7 @@ static struct triple *flatten(
break;
default:
/* Flatten the easy cases we don't override */
- ptr = flatten_generic(state, first, ptr);
+ ptr = flatten_generic(state, first, ptr, 0);
break;
}
} while(ptr && (ptr != orig_ptr));
@@ -5660,12 +5817,12 @@ static int constants_equal(struct compile_state *state,
static int is_zero(struct triple *ins)
{
- return is_const(ins) && (ins->u.cval == 0);
+ return is_simple_const(ins) && (ins->u.cval == 0);
}
static int is_one(struct triple *ins)
{
- return is_const(ins) && (ins->u.cval == 1);
+ return is_simple_const(ins) && (ins->u.cval == 1);
}
static long_t bit_count(ulong_t value)
@@ -5740,10 +5897,8 @@ static int is_pow2(struct triple *ins)
}
static ulong_t read_const(struct compile_state *state,
- struct triple *ins, struct triple **expr)
+ struct triple *ins, struct triple *rhs)
{
- struct triple *rhs;
- rhs = *expr;
switch(rhs->type->type &TYPE_MASK) {
case TYPE_CHAR:
case TYPE_SHORT:
@@ -5765,13 +5920,118 @@ static ulong_t read_const(struct compile_state *state,
return rhs->u.cval;
}
-static long_t read_sconst(struct triple *ins, struct triple **expr)
+static long_t read_sconst(struct compile_state *state,
+ struct triple *ins, struct triple *rhs)
{
- struct triple *rhs;
- rhs = *expr;
return (long_t)(rhs->u.cval);
}
+int const_ltrue(struct compile_state *state, struct triple *ins, struct triple *rhs)
+{
+ if (!is_const(rhs)) {
+ internal_error(state, 0, "non const passed to const_true\n");
+ }
+ return !is_zero(rhs);
+}
+
+int const_eq(struct compile_state *state, struct triple *ins,
+ struct triple *left, struct triple *right)
+{
+ int result;
+ if (!is_const(left) || !is_const(right)) {
+ internal_error(state, ins, "non const passed to const_eq\n");
+ result = 0;
+ }
+ else if (left == right) {
+ result = 1;
+ }
+ else if (is_simple_const(left) && is_simple_const(right)) {
+ ulong_t lval, rval;
+ lval = read_const(state, ins, left);
+ rval = read_const(state, ins, right);
+ result = (lval == rval);
+ }
+ else if ((left->op == OP_ADDRCONST) &&
+ (right->op == OP_ADDRCONST)) {
+ result = (MISC(left, 0) == MISC(right, 0)) &&
+ (left->u.cval == right->u.cval);
+ }
+ else {
+ internal_error(state, ins, "incomparable constants passed to const_eq\n");
+ result = 0;
+ }
+ return result;
+
+}
+
+int const_ucmp(struct compile_state *state, struct triple *ins,
+ struct triple *left, struct triple *right)
+{
+ int result;
+ if (!is_const(left) || !is_const(right)) {
+ internal_error(state, ins, "non const past to ucmp_const\n");
+ result = -2;
+ }
+ else if (left == right) {
+ result = 0;
+ }
+ else if (is_simple_const(left) && is_simple_const(right)) {
+ ulong_t lval, rval;
+ lval = read_const(state, ins, left);
+ rval = read_const(state, ins, right);
+ result = 0;
+ if (lval > rval) {
+ result = 1;
+ } else if (rval > lval) {
+ result = -1;
+ }
+ }
+ else if ((left->op == OP_ADDRCONST) &&
+ (right->op == OP_ADDRCONST) &&
+ (MISC(left, 0) == MISC(right, 0))) {
+ result = 0;
+ if (left->u.cval > right->u.cval) {
+ result = 1;
+ } else if (left->u.cval < right->u.cval) {
+ result = -1;
+ }
+ }
+ else {
+ internal_error(state, ins, "incomparable constants passed to const_ucmp\n");
+ result = -2;
+ }
+ return result;
+}
+
+int const_scmp(struct compile_state *state, struct triple *ins,
+ struct triple *left, struct triple *right)
+{
+ int result;
+ if (!is_const(left) || !is_const(right)) {
+ internal_error(state, ins, "non const past to ucmp_const\n");
+ result = -2;
+ }
+ else if (left == right) {
+ result = 0;
+ }
+ else if (is_simple_const(left) && is_simple_const(right)) {
+ long_t lval, rval;
+ lval = read_sconst(state, ins, left);
+ rval = read_sconst(state, ins, right);
+ result = 0;
+ if (lval > rval) {
+ result = 1;
+ } else if (rval > lval) {
+ result = -1;
+ }
+ }
+ else {
+ internal_error(state, ins, "incomparable constants passed to const_scmp\n");
+ result = -2;
+ }
+ return result;
+}
+
static void unuse_rhs(struct compile_state *state, struct triple *ins)
{
struct triple **expr;
@@ -5874,6 +6134,7 @@ static void flatten_structures(struct compile_state *state)
do {
struct triple *next;
next = ins->next;
+ valid_ins(state, ins);
if ((ins->type->type & TYPE_MASK) == TYPE_STRUCT) {
if (ins->op == OP_VAL_VEC) {
/* Do nothing */
@@ -5910,7 +6171,7 @@ static void flatten_structures(struct compile_state *state)
}
propogate_use(state, ins, next);
flatten(state, ins, next);
- free_triple(state, ins);
+ release_triple(state, ins);
}
else if ((ins->op == OP_STORE) || (ins->op == OP_WRITE)) {
struct triple *src, *dst, **vector;
@@ -5945,7 +6206,7 @@ static void flatten_structures(struct compile_state *state)
}
propogate_use(state, ins, next);
flatten(state, ins, next);
- free_triple(state, ins);
+ release_triple(state, ins);
}
}
ins = next;
@@ -5957,6 +6218,9 @@ static void flatten_structures(struct compile_state *state)
struct triple *next;
next = ins->next;
if (ins->op == OP_VAL_VEC) {
+ if (ins->use) {
+ internal_error(state, ins, "valvec used\n");
+ }
release_triple(state, ins);
}
ins = next;
@@ -5996,8 +6260,8 @@ static void simplify_smul(struct compile_state *state, struct triple *ins)
}
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
long_t left, right;
- left = read_sconst(ins, &RHS(ins, 0));
- right = read_sconst(ins, &RHS(ins, 1));
+ left = read_sconst(state, ins, RHS(ins, 0));
+ right = read_sconst(state, ins, RHS(ins, 1));
mkconst(state, ins, left * right);
}
else if (is_zero(RHS(ins, 1))) {
@@ -6010,7 +6274,7 @@ static void simplify_smul(struct compile_state *state, struct triple *ins)
struct triple *val;
val = int_const(state, ins->type, tlog2(RHS(ins, 1)));
ins->op = OP_SL;
- insert_triple(state, ins, val);
+ insert_triple(state, state->global_pool, val);
unuse_triple(RHS(ins, 1), ins);
use_triple(val, ins);
RHS(ins, 1) = val;
@@ -6027,8 +6291,8 @@ static void simplify_umul(struct compile_state *state, struct triple *ins)
}
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left * right);
}
else if (is_zero(RHS(ins, 1))) {
@@ -6041,7 +6305,7 @@ static void simplify_umul(struct compile_state *state, struct triple *ins)
struct triple *val;
val = int_const(state, ins->type, tlog2(RHS(ins, 1)));
ins->op = OP_SL;
- insert_triple(state, ins, val);
+ insert_triple(state, state->global_pool, val);
unuse_triple(RHS(ins, 1), ins);
use_triple(val, ins);
RHS(ins, 1) = val;
@@ -6052,8 +6316,8 @@ static void simplify_sdiv(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
long_t left, right;
- left = read_sconst(ins, &RHS(ins, 0));
- right = read_sconst(ins, &RHS(ins, 1));
+ left = read_sconst(state, ins, RHS(ins, 0));
+ right = read_sconst(state, ins, RHS(ins, 1));
mkconst(state, ins, left / right);
}
else if (is_zero(RHS(ins, 0))) {
@@ -6069,7 +6333,7 @@ static void simplify_sdiv(struct compile_state *state, struct triple *ins)
struct triple *val;
val = int_const(state, ins->type, tlog2(RHS(ins, 1)));
ins->op = OP_SSR;
- insert_triple(state, ins, val);
+ insert_triple(state, state->global_pool, val);
unuse_triple(RHS(ins, 1), ins);
use_triple(val, ins);
RHS(ins, 1) = val;
@@ -6080,8 +6344,8 @@ static void simplify_udiv(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left / right);
}
else if (is_zero(RHS(ins, 0))) {
@@ -6097,7 +6361,7 @@ static void simplify_udiv(struct compile_state *state, struct triple *ins)
struct triple *val;
val = int_const(state, ins->type, tlog2(RHS(ins, 1)));
ins->op = OP_USR;
- insert_triple(state, ins, val);
+ insert_triple(state, state->global_pool, val);
unuse_triple(RHS(ins, 1), ins);
use_triple(val, ins);
RHS(ins, 1) = val;
@@ -6108,8 +6372,8 @@ static void simplify_smod(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
long_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left % right);
}
else if (is_zero(RHS(ins, 0))) {
@@ -6125,7 +6389,7 @@ static void simplify_smod(struct compile_state *state, struct triple *ins)
struct triple *val;
val = int_const(state, ins->type, RHS(ins, 1)->u.cval - 1);
ins->op = OP_AND;
- insert_triple(state, ins, val);
+ insert_triple(state, state->global_pool, val);
unuse_triple(RHS(ins, 1), ins);
use_triple(val, ins);
RHS(ins, 1) = val;
@@ -6136,8 +6400,8 @@ static void simplify_umod(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left % right);
}
else if (is_zero(RHS(ins, 0))) {
@@ -6153,7 +6417,7 @@ static void simplify_umod(struct compile_state *state, struct triple *ins)
struct triple *val;
val = int_const(state, ins->type, RHS(ins, 1)->u.cval - 1);
ins->op = OP_AND;
- insert_triple(state, ins, val);
+ insert_triple(state, state->global_pool, val);
unuse_triple(RHS(ins, 1), ins);
use_triple(val, ins);
RHS(ins, 1) = val;
@@ -6172,8 +6436,8 @@ static void simplify_add(struct compile_state *state, struct triple *ins)
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
if (RHS(ins, 0)->op == OP_INTCONST) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left + right);
}
else if (RHS(ins, 0)->op == OP_ADDRCONST) {
@@ -6201,8 +6465,8 @@ static void simplify_sub(struct compile_state *state, struct triple *ins)
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
if (RHS(ins, 0)->op == OP_INTCONST) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left - right);
}
else if (RHS(ins, 0)->op == OP_ADDRCONST) {
@@ -6223,15 +6487,15 @@ static void simplify_sl(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 1))) {
ulong_t right;
- right = read_const(state, ins, &RHS(ins, 1));
+ right = read_const(state, ins, RHS(ins, 1));
if (right >= (size_of(state, ins->type)*8)) {
warning(state, ins, "left shift count >= width of type");
}
}
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left << right);
}
}
@@ -6240,15 +6504,15 @@ static void simplify_usr(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 1))) {
ulong_t right;
- right = read_const(state, ins, &RHS(ins, 1));
+ right = read_const(state, ins, RHS(ins, 1));
if (right >= (size_of(state, ins->type)*8)) {
warning(state, ins, "right shift count >= width of type");
}
}
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left >> right);
}
}
@@ -6257,15 +6521,15 @@ static void simplify_ssr(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 1))) {
ulong_t right;
- right = read_const(state, ins, &RHS(ins, 1));
+ right = read_const(state, ins, RHS(ins, 1));
if (right >= (size_of(state, ins->type)*8)) {
warning(state, ins, "right shift count >= width of type");
}
}
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
long_t left, right;
- left = read_sconst(ins, &RHS(ins, 0));
- right = read_sconst(ins, &RHS(ins, 1));
+ left = read_sconst(state, ins, RHS(ins, 0));
+ right = read_sconst(state, ins, RHS(ins, 1));
mkconst(state, ins, left >> right);
}
}
@@ -6274,8 +6538,8 @@ static void simplify_and(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left & right);
}
}
@@ -6284,8 +6548,8 @@ static void simplify_or(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left | right);
}
}
@@ -6294,8 +6558,8 @@ static void simplify_xor(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
+ left = read_const(state, ins, RHS(ins, 0));
+ right = read_const(state, ins, RHS(ins, 1));
mkconst(state, ins, left ^ right);
}
}
@@ -6314,7 +6578,7 @@ static void simplify_neg(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0))) {
ulong_t left;
- left = read_const(state, ins, &RHS(ins, 0));
+ left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, -left);
}
else if (RHS(ins, 0)->op == OP_NEG) {
@@ -6326,91 +6590,97 @@ static void simplify_invert(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0))) {
ulong_t left;
- left = read_const(state, ins, &RHS(ins, 0));
+ left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, ~left);
}
}
static void simplify_eq(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
- mkconst(state, ins, left == right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_eq(state, ins, left, right) == 1);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 1);
}
}
static void simplify_noteq(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
- mkconst(state, ins, left != right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_eq(state, ins, left, right) != 1);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ if (left == right) {
mkconst(state, ins, 0);
}
}
static void simplify_sless(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- long_t left, right;
- left = read_sconst(ins, &RHS(ins, 0));
- right = read_sconst(ins, &RHS(ins, 1));
- mkconst(state, ins, left < right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_scmp(state, ins, left, right) < 0);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 0);
}
}
static void simplify_uless(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
- mkconst(state, ins, left < right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_ucmp(state, ins, left, right) < 0);
}
- else if (is_zero(RHS(ins, 0))) {
- mkconst(state, ins, 1);
+ else if (is_zero(right)) {
+ mkconst(state, ins, 0);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 0);
}
}
static void simplify_smore(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- long_t left, right;
- left = read_sconst(ins, &RHS(ins, 0));
- right = read_sconst(ins, &RHS(ins, 1));
- mkconst(state, ins, left > right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_scmp(state, ins, left, right) > 0);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 0);
}
}
static void simplify_umore(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
- mkconst(state, ins, left > right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_ucmp(state, ins, left, right) > 0);
}
- else if (is_zero(RHS(ins, 1))) {
- mkconst(state, ins, 1);
+ else if (is_zero(left)) {
+ mkconst(state, ins, 0);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 0);
}
}
@@ -6418,109 +6688,115 @@ static void simplify_umore(struct compile_state *state, struct triple *ins)
static void simplify_slesseq(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- long_t left, right;
- left = read_sconst(ins, &RHS(ins, 0));
- right = read_sconst(ins, &RHS(ins, 1));
- mkconst(state, ins, left <= right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_scmp(state, ins, left, right) <= 0);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 1);
}
}
static void simplify_ulesseq(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
- mkconst(state, ins, left <= right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_ucmp(state, ins, left, right) <= 0);
}
- else if (is_zero(RHS(ins, 0))) {
+ else if (is_zero(left)) {
mkconst(state, ins, 1);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 1);
}
}
static void simplify_smoreeq(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 0))) {
- long_t left, right;
- left = read_sconst(ins, &RHS(ins, 0));
- right = read_sconst(ins, &RHS(ins, 1));
- mkconst(state, ins, left >= right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_scmp(state, ins, left, right) >= 0);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 1);
}
}
static void simplify_umoreeq(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- ulong_t left, right;
- left = read_const(state, ins, &RHS(ins, 0));
- right = read_const(state, ins, &RHS(ins, 1));
- mkconst(state, ins, left >= right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_const(left) && is_const(right)) {
+ mkconst(state, ins, const_ucmp(state, ins, left, right) >= 0);
}
- else if (is_zero(RHS(ins, 1))) {
+ else if (is_zero(right)) {
mkconst(state, ins, 1);
}
- else if (RHS(ins, 0) == RHS(ins, 1)) {
+ else if (left == right) {
mkconst(state, ins, 1);
}
}
static void simplify_lfalse(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0))) {
- ulong_t left;
- left = read_const(state, ins, &RHS(ins, 0));
- mkconst(state, ins, left == 0);
+ struct triple *rhs;
+ rhs = RHS(ins, 0);
+
+ if (is_const(rhs)) {
+ mkconst(state, ins, !const_ltrue(state, ins, rhs));
}
/* Otherwise if I am the only user... */
- else if ((RHS(ins, 0)->use) &&
- (RHS(ins, 0)->use->member == ins) && (RHS(ins, 0)->use->next == 0)) {
+ else if ((rhs->use) &&
+ (rhs->use->member == ins) && (rhs->use->next == 0)) {
int need_copy = 1;
/* Invert a boolean operation */
- switch(RHS(ins, 0)->op) {
- case OP_LTRUE: RHS(ins, 0)->op = OP_LFALSE; break;
- case OP_LFALSE: RHS(ins, 0)->op = OP_LTRUE; break;
- case OP_EQ: RHS(ins, 0)->op = OP_NOTEQ; break;
- case OP_NOTEQ: RHS(ins, 0)->op = OP_EQ; break;
- case OP_SLESS: RHS(ins, 0)->op = OP_SMOREEQ; break;
- case OP_ULESS: RHS(ins, 0)->op = OP_UMOREEQ; break;
- case OP_SMORE: RHS(ins, 0)->op = OP_SLESSEQ; break;
- case OP_UMORE: RHS(ins, 0)->op = OP_ULESSEQ; break;
- case OP_SLESSEQ: RHS(ins, 0)->op = OP_SMORE; break;
- case OP_ULESSEQ: RHS(ins, 0)->op = OP_UMORE; break;
- case OP_SMOREEQ: RHS(ins, 0)->op = OP_SLESS; break;
- case OP_UMOREEQ: RHS(ins, 0)->op = OP_ULESS; break;
+ switch(rhs->op) {
+ case OP_LTRUE: rhs->op = OP_LFALSE; break;
+ case OP_LFALSE: rhs->op = OP_LTRUE; break;
+ case OP_EQ: rhs->op = OP_NOTEQ; break;
+ case OP_NOTEQ: rhs->op = OP_EQ; break;
+ case OP_SLESS: rhs->op = OP_SMOREEQ; break;
+ case OP_ULESS: rhs->op = OP_UMOREEQ; break;
+ case OP_SMORE: rhs->op = OP_SLESSEQ; break;
+ case OP_UMORE: rhs->op = OP_ULESSEQ; break;
+ case OP_SLESSEQ: rhs->op = OP_SMORE; break;
+ case OP_ULESSEQ: rhs->op = OP_UMORE; break;
+ case OP_SMOREEQ: rhs->op = OP_SLESS; break;
+ case OP_UMOREEQ: rhs->op = OP_ULESS; break;
default:
need_copy = 0;
break;
}
if (need_copy) {
- mkcopy(state, ins, RHS(ins, 0));
+ mkcopy(state, ins, rhs);
}
}
}
static void simplify_ltrue (struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0))) {
- ulong_t left;
- left = read_const(state, ins, &RHS(ins, 0));
- mkconst(state, ins, left != 0);
+ struct triple *rhs;
+ rhs = RHS(ins, 0);
+
+ if (is_const(rhs)) {
+ mkconst(state, ins, const_ltrue(state, ins, rhs));
}
- else switch(RHS(ins, 0)->op) {
+ else switch(rhs->op) {
case OP_LTRUE: case OP_LFALSE: case OP_EQ: case OP_NOTEQ:
case OP_SLESS: case OP_ULESS: case OP_SMORE: case OP_UMORE:
case OP_SLESSEQ: case OP_ULESSEQ: case OP_SMOREEQ: case OP_UMOREEQ:
- mkcopy(state, ins, RHS(ins, 0));
+ mkcopy(state, ins, rhs);
}
}
@@ -6532,7 +6808,7 @@ static void simplify_copy(struct compile_state *state, struct triple *ins)
case OP_INTCONST:
{
ulong_t left;
- left = read_const(state, ins, &RHS(ins, 0));
+ left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, left);
break;
}
@@ -6574,10 +6850,13 @@ static int phi_dependency(struct block *block)
* 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;
+ if (block) {
+ struct block_set *edge;
+ for(edge = block->edges; edge; edge = edge->next) {
+ if (phi_present(edge->member)) {
+ return 1;
+ }
+ }
}
return 0;
}
@@ -6590,7 +6869,8 @@ static struct triple *branch_target(struct compile_state *state, struct triple *
* loop back onto themselves. If I see one don't advance the
* target.
*/
- while(triple_is_structural(state, targ) && (targ->next != targ)) {
+ while(triple_is_structural(state, targ) &&
+ (targ->next != targ) && (targ->next != state->first)) {
targ = targ->next;
}
return targ;
@@ -6600,7 +6880,7 @@ static struct triple *branch_target(struct compile_state *state, struct triple *
static void simplify_branch(struct compile_state *state, struct triple *ins)
{
int simplified;
- if (ins->op != OP_BRANCH) {
+ if ((ins->op != OP_BRANCH) && (ins->op != OP_CBRANCH)) {
internal_error(state, ins, "not branch");
}
if (ins->use != 0) {
@@ -6620,27 +6900,27 @@ static void simplify_branch(struct compile_state *state, struct triple *ins)
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;
- }
+ if ((targ != ins) && (targ->op == OP_BRANCH) &&
+ !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.
*/
- if (TRIPLE_RHS(ins->sizes) && is_const(RHS(ins, 0))) {
+ if ((ins->op == OP_CBRANCH) && is_const(RHS(ins, 0))) {
struct triple *targ;
ulong_t value;
- value = read_const(state, ins, &RHS(ins, 0));
+ value = read_const(state, ins, RHS(ins, 0));
unuse_triple(RHS(ins, 0), ins);
targ = TARG(ins, 0);
ins->sizes = TRIPLE_SIZES(0, 0, 0, 1);
+ ins->op = OP_BRANCH;
if (value) {
unuse_triple(ins->next, ins);
TARG(ins, 0) = targ;
@@ -6651,12 +6931,12 @@ static void simplify_branch(struct compile_state *state, struct triple *ins)
}
}
- /* If we have an unconditional branch to the next instruction
+ /* If we have a 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)) {
+ if (ins->op == OP_CBRANCH) {
unuse_triple(RHS(ins, 0), ins);
unuse_triple(ins->next, ins);
}
@@ -6670,8 +6950,6 @@ static void simplify_branch(struct compile_state *state, struct triple *ins)
static void simplify_label(struct compile_state *state, struct triple *ins)
{
- struct triple *first;
- first = state->first;
/* Ignore volatile labels */
if (!triple_is_pure(state, ins, ins->id)) {
return;
@@ -6688,13 +6966,17 @@ static void simplify_label(struct compile_state *state, struct triple *ins)
struct triple_set *user, *next;
ins->op = OP_NOOP;
for(user = ins->use; user; user = next) {
- struct triple *use;
+ struct triple *use, **expr;
next = user->next;
use = user->member;
- if (TARG(use, 0) == ins) {
- TARG(use, 0) = ins->prev;
- unuse_triple(ins, use);
- use_triple(ins->prev, use);
+ expr = triple_targ(state, use, 0);
+ for(;expr; expr = triple_targ(state, use, expr)) {
+ if (*expr == ins) {
+ *expr = ins->prev;
+ unuse_triple(ins, use);
+ use_triple(ins->prev, use);
+ }
+
}
}
if (ins->use) {
@@ -6717,11 +6999,11 @@ static void simplify_phi(struct compile_state *state, struct triple *ins)
}
/* 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]);
+ 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]))) {
+ (cvalue != read_const(state, ins, slot[i]))) {
break;
}
}
@@ -6750,7 +7032,7 @@ static void simplify_bsf(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0))) {
ulong_t left;
- left = read_const(state, ins, &RHS(ins, 0));
+ left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, bsf(left));
}
}
@@ -6759,162 +7041,93 @@ static void simplify_bsr(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0))) {
ulong_t left;
- left = read_const(state, ins, &RHS(ins, 0));
+ left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, bsr(left));
}
}
typedef void (*simplify_t)(struct compile_state *state, struct triple *ins);
-static const simplify_t table_simplify[] = {
-#if 1
+static const struct simplify_table {
+ simplify_t func;
+ unsigned long flag;
+} table_simplify[] = {
#define simplify_sdivt simplify_noop
#define simplify_udivt simplify_noop
-#endif
-#if 0
-#define simplify_smul simplify_noop
-#define simplify_umul simplify_noop
-#define simplify_sdiv simplify_noop
-#define simplify_udiv simplify_noop
-#define simplify_smod simplify_noop
-#define simplify_umod simplify_noop
-#endif
-#if 0
-#define simplify_add simplify_noop
-#define simplify_sub simplify_noop
-#endif
-#if 0
-#define simplify_sl simplify_noop
-#define simplify_usr simplify_noop
-#define simplify_ssr simplify_noop
-#endif
-#if 0
-#define simplify_and simplify_noop
-#define simplify_xor simplify_noop
-#define simplify_or simplify_noop
-#endif
-#if 0
-#define simplify_pos simplify_noop
-#define simplify_neg simplify_noop
-#define simplify_invert simplify_noop
-#endif
-
-#if 0
-#define simplify_eq simplify_noop
-#define simplify_noteq simplify_noop
-#endif
-#if 0
-#define simplify_sless simplify_noop
-#define simplify_uless simplify_noop
-#define simplify_smore simplify_noop
-#define simplify_umore simplify_noop
-#endif
-#if 0
-#define simplify_slesseq simplify_noop
-#define simplify_ulesseq simplify_noop
-#define simplify_smoreeq simplify_noop
-#define simplify_umoreeq simplify_noop
-#endif
-#if 0
-#define simplify_lfalse simplify_noop
-#endif
-#if 0
-#define simplify_ltrue simplify_noop
-#endif
-
-#if 0
-#define simplify_copy simplify_noop
-#endif
-
-#if 0
-#define simplify_branch simplify_noop
-#endif
-#if 0
-#define simplify_label simplify_noop
-#endif
-
-#if 0
-#define simplify_phi simplify_noop
-#endif
-
-#if 0
-#define simplify_bsf simplify_noop
-#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,
-[OP_UMUL ] = simplify_umul,
-[OP_SDIV ] = simplify_sdiv,
-[OP_UDIV ] = simplify_udiv,
-[OP_SMOD ] = simplify_smod,
-[OP_UMOD ] = simplify_umod,
-[OP_ADD ] = simplify_add,
-[OP_SUB ] = simplify_sub,
-[OP_SL ] = simplify_sl,
-[OP_USR ] = simplify_usr,
-[OP_SSR ] = simplify_ssr,
-[OP_AND ] = simplify_and,
-[OP_XOR ] = simplify_xor,
-[OP_OR ] = simplify_or,
-[OP_POS ] = simplify_pos,
-[OP_NEG ] = simplify_neg,
-[OP_INVERT ] = simplify_invert,
-
-[OP_EQ ] = simplify_eq,
-[OP_NOTEQ ] = simplify_noteq,
-[OP_SLESS ] = simplify_sless,
-[OP_ULESS ] = simplify_uless,
-[OP_SMORE ] = simplify_smore,
-[OP_UMORE ] = simplify_umore,
-[OP_SLESSEQ ] = simplify_slesseq,
-[OP_ULESSEQ ] = simplify_ulesseq,
-[OP_SMOREEQ ] = simplify_smoreeq,
-[OP_UMOREEQ ] = simplify_umoreeq,
-[OP_LFALSE ] = simplify_lfalse,
-[OP_LTRUE ] = simplify_ltrue,
-
-[OP_LOAD ] = simplify_noop,
-[OP_STORE ] = simplify_noop,
-
-[OP_NOOP ] = simplify_noop,
-
-[OP_INTCONST ] = simplify_noop,
-[OP_BLOBCONST ] = simplify_noop,
-[OP_ADDRCONST ] = simplify_noop,
-
-[OP_WRITE ] = simplify_noop,
-[OP_READ ] = simplify_noop,
-[OP_COPY ] = simplify_copy,
-[OP_PIECE ] = simplify_piece,
-[OP_ASM ] = simplify_noop,
-
-[OP_DOT ] = simplify_noop,
-[OP_VAL_VEC ] = simplify_noop,
-
-[OP_LIST ] = simplify_noop,
-[OP_BRANCH ] = simplify_branch,
-[OP_LABEL ] = simplify_label,
-[OP_ADECL ] = simplify_noop,
-[OP_SDECL ] = simplify_noop,
-[OP_PHI ] = simplify_phi,
-
-[OP_INB ] = simplify_noop,
-[OP_INW ] = simplify_noop,
-[OP_INL ] = simplify_noop,
-[OP_OUTB ] = simplify_noop,
-[OP_OUTW ] = simplify_noop,
-[OP_OUTL ] = simplify_noop,
-[OP_BSF ] = simplify_bsf,
-[OP_BSR ] = simplify_bsr,
-[OP_RDMSR ] = simplify_noop,
-[OP_WRMSR ] = simplify_noop,
-[OP_HLT ] = simplify_noop,
+[OP_SDIVT ] = { simplify_sdivt, COMPILER_SIMPLIFY_ARITH },
+[OP_UDIVT ] = { simplify_udivt, COMPILER_SIMPLIFY_ARITH },
+[OP_SMUL ] = { simplify_smul, COMPILER_SIMPLIFY_ARITH },
+[OP_UMUL ] = { simplify_umul, COMPILER_SIMPLIFY_ARITH },
+[OP_SDIV ] = { simplify_sdiv, COMPILER_SIMPLIFY_ARITH },
+[OP_UDIV ] = { simplify_udiv, COMPILER_SIMPLIFY_ARITH },
+[OP_SMOD ] = { simplify_smod, COMPILER_SIMPLIFY_ARITH },
+[OP_UMOD ] = { simplify_umod, COMPILER_SIMPLIFY_ARITH },
+[OP_ADD ] = { simplify_add, COMPILER_SIMPLIFY_ARITH },
+[OP_SUB ] = { simplify_sub, COMPILER_SIMPLIFY_ARITH },
+[OP_SL ] = { simplify_sl, COMPILER_SIMPLIFY_SHIFT },
+[OP_USR ] = { simplify_usr, COMPILER_SIMPLIFY_SHIFT },
+[OP_SSR ] = { simplify_ssr, COMPILER_SIMPLIFY_SHIFT },
+[OP_AND ] = { simplify_and, COMPILER_SIMPLIFY_BITWISE },
+[OP_XOR ] = { simplify_xor, COMPILER_SIMPLIFY_BITWISE },
+[OP_OR ] = { simplify_or, COMPILER_SIMPLIFY_BITWISE },
+[OP_POS ] = { simplify_pos, COMPILER_SIMPLIFY_ARITH },
+[OP_NEG ] = { simplify_neg, COMPILER_SIMPLIFY_ARITH },
+[OP_INVERT ] = { simplify_invert, COMPILER_SIMPLIFY_BITWISE },
+
+[OP_EQ ] = { simplify_eq, COMPILER_SIMPLIFY_LOGICAL },
+[OP_NOTEQ ] = { simplify_noteq, COMPILER_SIMPLIFY_LOGICAL },
+[OP_SLESS ] = { simplify_sless, COMPILER_SIMPLIFY_LOGICAL },
+[OP_ULESS ] = { simplify_uless, COMPILER_SIMPLIFY_LOGICAL },
+[OP_SMORE ] = { simplify_smore, COMPILER_SIMPLIFY_LOGICAL },
+[OP_UMORE ] = { simplify_umore, COMPILER_SIMPLIFY_LOGICAL },
+[OP_SLESSEQ ] = { simplify_slesseq, COMPILER_SIMPLIFY_LOGICAL },
+[OP_ULESSEQ ] = { simplify_ulesseq, COMPILER_SIMPLIFY_LOGICAL },
+[OP_SMOREEQ ] = { simplify_smoreeq, COMPILER_SIMPLIFY_LOGICAL },
+[OP_UMOREEQ ] = { simplify_umoreeq, COMPILER_SIMPLIFY_LOGICAL },
+[OP_LFALSE ] = { simplify_lfalse, COMPILER_SIMPLIFY_LOGICAL },
+[OP_LTRUE ] = { simplify_ltrue, COMPILER_SIMPLIFY_LOGICAL },
+
+[OP_LOAD ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_STORE ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+
+[OP_NOOP ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+
+[OP_INTCONST ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_BLOBCONST ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_ADDRCONST ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+
+[OP_WRITE ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_READ ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_COPY ] = { simplify_copy, COMPILER_SIMPLIFY_COPY },
+[OP_PIECE ] = { simplify_piece, COMPILER_SIMPLIFY_OP },
+[OP_ASM ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+
+[OP_DOT ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_VAL_VEC ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+
+[OP_LIST ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_BRANCH ] = { simplify_branch, COMPILER_SIMPLIFY_BRANCH },
+[OP_CBRANCH ] = { simplify_branch, COMPILER_SIMPLIFY_BRANCH },
+[OP_CALL ] = { simplify_noop, COMPILER_SIMPLIFY_BRANCH },
+[OP_RET ] = { simplify_noop, COMPILER_SIMPLIFY_BRANCH },
+[OP_LABEL ] = { simplify_label, COMPILER_SIMPLIFY_LABEL },
+[OP_ADECL ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_SDECL ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_PHI ] = { simplify_phi, COMPILER_SIMPLIFY_PHI },
+
+[OP_INB ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_INW ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_INL ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_OUTB ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_OUTW ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_OUTL ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_BSF ] = { simplify_bsf, COMPILER_SIMPLIFY_OP },
+[OP_BSR ] = { simplify_bsr, COMPILER_SIMPLIFY_OP },
+[OP_RDMSR ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_WRMSR ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_HLT ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
};
static void simplify(struct compile_state *state, struct triple *ins)
@@ -6927,68 +7140,30 @@ static void simplify(struct compile_state *state, struct triple *ins)
if ((op < 0) || (op > sizeof(table_simplify)/sizeof(table_simplify[0]))) {
do_simplify = 0;
}
+ else if (state->compiler->flags & table_simplify[op].flag) {
+ do_simplify = table_simplify[op].func;
+ }
else {
- do_simplify = table_simplify[op];
+ do_simplify = simplify_noop;
}
+
if (!do_simplify) {
internal_error(state, ins, "cannot simplify op: %d %s\n",
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 rebuild_ssa_form(struct compile_state *state);
+
static void simplify_all(struct compile_state *state)
{
struct triple *ins, *first;
+ if (!(state->compiler->flags & COMPILER_SIMPLIFY)) {
+ return;
+ }
first = state->first;
ins = first->prev;
do {
@@ -7000,6 +7175,9 @@ static void simplify_all(struct compile_state *state)
simplify(state, ins);
ins = ins->next;
}while(ins != first);
+ rebuild_ssa_form(state);
+
+ print_blocks(state, __func__, stdout);
}
/*
@@ -7011,7 +7189,7 @@ static void register_builtin_function(struct compile_state *state,
const char *name, int op, struct type *rtype, ...)
{
struct type *ftype, *atype, *param, **next;
- struct triple *def, *arg, *result, *work, *last, *first;
+ struct triple *def, *arg, *result, *work, *last, *first, *retvar, *ret;
struct hash_entry *ident;
struct file_state file;
int parameters;
@@ -7037,7 +7215,7 @@ static void register_builtin_function(struct compile_state *state,
}
/* Find the function type */
- ftype = new_type(TYPE_FUNCTION, rtype, 0);
+ ftype = new_type(TYPE_FUNCTION | STOR_INLINE | STOR_STATIC, rtype, 0);
next = &ftype->right;
va_start(args, rtype);
for(i = 0; i < parameters; i++) {
@@ -7058,6 +7236,9 @@ static void register_builtin_function(struct compile_state *state,
def = triple(state, OP_LIST, ftype, 0, 0);
first = label(state);
RHS(def, 0) = first;
+ retvar = variable(state, &void_ptr_type);
+ retvar = flatten(state, first, retvar);
+ ret = triple(state, OP_RET, &void_type, read_expr(state, retvar), 0);
/* Now string them together */
param = ftype->right;
@@ -7076,7 +7257,7 @@ static void register_builtin_function(struct compile_state *state,
}
MISC(def, 0) = result;
work = new_triple(state, op, rtype, -1, parameters);
- for(i = 0, arg = first->next; i < parameters; i++, arg = arg->next) {
+ for(i = 0, arg = first->next->next; i < parameters; i++, arg = arg->next) {
RHS(work, i) = read_expr(state, arg);
}
if (result && ((rtype->type & TYPE_MASK) == TYPE_STRUCT)) {
@@ -7111,19 +7292,27 @@ static void register_builtin_function(struct compile_state *state,
}
work = flatten(state, first, work);
last = flatten(state, first, label(state));
+ ret = flatten(state, first, ret);
name_len = strlen(name);
ident = lookup(state, name, name_len);
+ ftype->type_ident = ident;
symbol(state, ident, &ident->sym_ident, def, ftype);
state->file = file.prev;
state->function = 0;
-#if 0
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ builtin_function _________\n");
- print_triple(state, def);
- fprintf(stdout, "__________ builtin_function _________ done\n\n");
-#endif
+
+ if (!state->functions) {
+ state->functions = def;
+ } else {
+ insert_triple(state, state->functions, def);
+ }
+ if (state->compiler->debug & DEBUG_INLINE) {
+ fprintf(stdout, "\n");
+ loc(stdout, state, 0);
+ fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(stdout, def);
+ fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ }
}
static struct type *partial_struct(struct compile_state *state,
@@ -7263,10 +7452,17 @@ static struct triple *call_expr(
eat(state, TOK_LPAREN);
/* Find the return type without any specifiers */
type = clone_type(0, func->type->left);
- def = new_triple(state, OP_CALL, func->type, -1, -1);
- def->type = type;
-
- pvals = TRIPLE_RHS(def->sizes);
+ /* Count the number of rhs entries for OP_FCALL */
+ param = func->type->right;
+ pvals = 0;
+ while((param->type & TYPE_MASK) == TYPE_PRODUCT) {
+ pvals++;
+ param = param->right;
+ }
+ if ((param->type & TYPE_MASK) != TYPE_VOID) {
+ pvals++;
+ }
+ def = new_triple(state, OP_FCALL, type, -1, pvals);
MISC(def, 0) = func;
param = func->type->right;
@@ -8260,7 +8456,7 @@ static void return_statement(struct compile_state *state, struct triple *first)
/* Find the return variable */
var = MISC(state->main_function, 0);
/* Find the return destination */
- dest = RHS(state->main_function, 0)->prev;
+ dest = state->i_return->sym_ident->def;
mv = jmp = 0;
/* If needed generate a jump instruction */
if (!last) {
@@ -8766,7 +8962,7 @@ static struct type *param_decl(struct compile_state *state)
static struct type *param_type_list(struct compile_state *state, struct type *type)
{
struct type *ftype, **next;
- ftype = new_type(TYPE_FUNCTION, type, param_decl(state));
+ ftype = new_type(TYPE_FUNCTION | (type->type & STOR_MASK), type, param_decl(state));
next = &ftype->right;
while(peek(state) == TOK_COMMA) {
eat(state, TOK_COMMA);
@@ -9089,7 +9285,7 @@ static unsigned int storage_class_specifier_opt(struct compile_state *state)
break;
default:
if (state->scope_depth <= GLOBAL_SCOPE_DEPTH) {
- specifiers = STOR_STATIC;
+ specifiers = STOR_LOCAL;
}
else {
specifiers = STOR_AUTO;
@@ -9580,7 +9776,7 @@ static void resolve_branches(struct compile_state *state)
static struct triple *function_definition(
struct compile_state *state, struct type *type)
{
- struct triple *def, *tmp, *first, *end;
+ struct triple *def, *tmp, *first, *end, *retvar, *ret;
struct hash_entry *ident;
struct type *param;
int i;
@@ -9621,6 +9817,17 @@ static struct triple *function_definition(
/* Put a label at the very end of a function */
end = label(state);
flatten(state, first, end);
+ /* Remember where return goes */
+ ident = state->i_return;
+ symbol(state, ident, &ident->sym_ident, end, end->type);
+
+ /* Allocate a variable for the return address */
+ retvar = variable(state, &void_ptr_type);
+ retvar = flatten(state, end, retvar);
+
+ /* Add in the return instruction */
+ ret = triple(state, OP_RET, &void_type, read_expr(state, retvar), 0);
+ ret = flatten(state, first, ret);
/* Walk through the parameters and create symbol table entries
* for them.
@@ -9664,13 +9871,20 @@ static struct triple *function_definition(
/* Remove the parameter scope */
end_scope(state);
-#if 0
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ function_definition _________\n");
- print_triple(state, def);
- fprintf(stdout, "__________ function_definition _________ done\n\n");
-#endif
+
+ /* Remember I have defined a function */
+ if (!state->functions) {
+ state->functions = def;
+ } else {
+ insert_triple(state, state->functions, def);
+ }
+ if (state->compiler->debug & DEBUG_INLINE) {
+ fprintf(stdout, "\n");
+ loc(stdout, state, 0);
+ fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(stdout, def);
+ fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ }
return def;
}
@@ -9690,6 +9904,7 @@ static struct triple *do_decl(struct compile_state *state,
type->type &= ~STOR_MASK;
type->type |= STOR_AUTO;
break;
+ case STOR_LOCAL:
case STOR_EXTERN:
type->type &= ~STOR_MASK;
type->type |= STOR_STATIC;
@@ -9732,6 +9947,7 @@ static void decl(struct compile_state *state, struct triple *first)
type = declarator(state, base_type, &ident, 0);
if (global && ident && (peek(state) == TOK_LBRACE)) {
/* function */
+ type->type_ident = ident;
state->function = ident->name;
def = function_definition(state, type);
symbol(state, ident, &ident->sym_ident, def, type);
@@ -9786,10 +10002,458 @@ static void decls(struct compile_state *state)
}
}
+/*
+ * Function inlining
+ */
+
+static struct triple *call(struct compile_state *state,
+ struct triple *retvar, struct triple *ret_addr,
+ struct triple *targ, struct triple *ret)
+{
+ struct triple *call;
+
+ if (!retvar || !is_lvalue(state, retvar)) {
+ internal_error(state, 0, "writing to a non lvalue?");
+ }
+ write_compatible(state, retvar->type, &void_ptr_type);
+
+ call = new_triple(state, OP_CALL, &void_type, 1, 0);
+ TARG(call, 0) = targ;
+ MISC(call, 0) = ret;
+ if (!targ || (targ->op != OP_LABEL)) {
+ internal_error(state, 0, "call not to a label");
+ }
+ if (!ret || (ret->op != OP_RET)) {
+ internal_error(state, 0, "call not matched with return");
+ }
+ return call;
+}
+
+static void mark_live_functions(struct compile_state *state, struct triple *first)
+{
+ struct triple *ptr;
+ ptr = first;
+ do {
+ if (ptr->op == OP_FCALL) {
+ struct triple *func;
+ func = MISC(ptr, 0);
+ if (func->u.cval++ == 0) {
+ mark_live_functions(state, RHS(func, 0));
+ }
+ }
+ ptr = ptr->next;
+ } while(ptr != first);
+}
+
+static void walk_functions(struct compile_state *state,
+ void (*cb)(struct compile_state *state, struct triple *func, void *arg),
+ void *arg)
+{
+ struct triple *func, *first;
+ func = first = state->functions;
+ do {
+ cb(state, func, arg);
+ func = func->next;
+ } while(func != first);
+}
+
+
+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)
+{
+ struct triple *nfunc;
+ struct triple *nfirst, *ofirst;
+ struct triple *new, *old;
+
+ if (state->compiler->debug & DEBUG_INLINE) {
+ fprintf(stdout, "\n");
+ loc(stdout, state, 0);
+ fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(stdout, ofunc);
+ fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ }
+
+ /* Make a new copy of the old function */
+ nfunc = triple(state, OP_LIST, ofunc->type, 0, 0);
+ nfirst = 0;
+ ofirst = old = RHS(ofunc, 0);
+ do {
+ struct triple *new;
+ struct occurance *occurance;
+ int old_lhs, old_rhs;
+ old_lhs = TRIPLE_LHS(old->sizes);
+ old_rhs = TRIPLE_RHS(old->sizes);
+ occurance = inline_occurance(state, base_occurance, old->occurance);
+ if (ofunc->u.cval && (old->op == OP_FCALL)) {
+ MISC(old, 0)->u.cval += 1;
+ }
+ new = alloc_triple(state, old->op, old->type, old_lhs, old_rhs,
+ occurance);
+ if (!triple_stores_block(state, new)) {
+ memcpy(&new->u, &old->u, sizeof(new->u));
+ }
+ if (!nfirst) {
+ RHS(nfunc, 0) = nfirst = new;
+ }
+ else {
+ insert_triple(state, nfirst, new);
+ }
+ new->id |= TRIPLE_FLAG_FLATTENED;
+
+ /* During the copy remember new as user of old */
+ use_triple(old, new);
+
+ /* Populate the return type if present */
+ 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);
+
+ /* Make a second pass to fix up any unresolved references */
+ old = ofirst;
+ new = nfirst;
+ do {
+ struct triple **oexpr, **nexpr;
+ int count, i;
+ /* Lookup where the copy is, to join pointers */
+ count = TRIPLE_SIZE(old->sizes);
+ for(i = 0; i < count; i++) {
+ oexpr = &old->param[i];
+ nexpr = &new->param[i];
+ 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?");
+ }
+ use_triple(*nexpr, new);
+ }
+ if (!*nexpr && *oexpr) {
+ internal_error(state, 0, "Could not copy %d\n", i);
+ }
+ }
+ old = old->next;
+ new = new->next;
+ } while((old != ofirst) && (new != nfirst));
+
+ /* Make a third pass to cleanup the extra useses */
+ old = ofirst;
+ 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));
+ return nfunc;
+}
+
+static struct triple *flatten_inline_call(
+ struct compile_state *state, struct triple *first, struct triple *ptr)
+{
+ /* Inline the function call */
+ struct type *ptype;
+ struct triple *ofunc, *nfunc, *nfirst, *param, *result;
+ struct triple *end, *nend;
+ int pvals, i;
+
+ /* Find the triples */
+ ofunc = MISC(ptr, 0);
+ if (ofunc->op != OP_LIST) {
+ internal_error(state, 0, "improper function");
+ }
+ nfunc = copy_func(state, ofunc, ptr->occurance);
+ nfirst = RHS(nfunc, 0)->next->next;
+ /* Prepend the parameter reading into the new function list */
+ ptype = nfunc->type->right;
+ param = RHS(nfunc, 0)->next->next;
+ pvals = TRIPLE_RHS(ptr->sizes);
+ for(i = 0; i < pvals; i++) {
+ struct type *atype;
+ struct triple *arg;
+ atype = ptype;
+ if ((ptype->type & TYPE_MASK) == TYPE_PRODUCT) {
+ atype = ptype->left;
+ }
+ while((param->type->type & TYPE_MASK) != (atype->type & TYPE_MASK)) {
+ param = param->next;
+ }
+ arg = RHS(ptr, i);
+ flatten(state, nfirst, write_expr(state, param, arg));
+ ptype = ptype->right;
+ param = param->next;
+ }
+ result = 0;
+ if ((nfunc->type->left->type & TYPE_MASK) != TYPE_VOID) {
+ result = read_expr(state, MISC(nfunc,0));
+ }
+ if (state->compiler->debug & DEBUG_INLINE) {
+ fprintf(stdout, "\n");
+ loc(stdout, state, 0);
+ fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(stdout, nfunc);
+ fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ }
+
+ /* Get rid of the extra triples */
+ nfirst = RHS(nfunc, 0)->next->next;
+ release_triple(state, RHS(nfunc, 0)->prev->prev);
+ release_triple(state, RHS(nfunc, 0)->prev);
+ release_triple(state, RHS(nfunc, 0)->next);
+ free_triple(state, RHS(nfunc, 0));
+ RHS(nfunc, 0) = 0;
+ free_triple(state, nfunc);
+
+ /* Append the new function list onto the return list */
+ end = first->prev;
+ nend = nfirst->prev;
+ end->next = nfirst;
+ nfirst->prev = end;
+ nend->next = first;
+ first->prev = nend;
+
+ return result;
+}
+
+static struct triple *flatten_function_call(
+ struct compile_state *state, struct triple *first, struct triple *ptr)
+{
+ /* Generate an ordinary function call */
+ struct triple *func, *func_first, *func_last, *retvar;
+ struct type *ptype;
+ struct triple *param;
+ struct triple *jmp;
+ struct triple *ret_addr, *ret_loc, *ret_set;
+ struct triple *result;
+ int pvals, i;
+
+ FINISHME();
+ /* Find the triples */
+ func = MISC(ptr, 0);
+ func_first = RHS(func, 0);
+ retvar = func_first->next;
+ func_last = func_first->prev;
+
+ /* Generate some needed triples */
+ ret_loc = label(state);
+ ret_addr = triple(state, OP_ADDRCONST, &void_ptr_type, ret_loc, 0);
+
+ /* Pass the parameters to the new function */
+ ptype = func->type->right;
+ param = func_first->next->next;
+ pvals = TRIPLE_RHS(ptr->sizes);
+ for(i = 0; i < pvals; i++) {
+ struct type *atype;
+ struct triple *arg;
+ atype = ptype;
+ if ((ptype->type & TYPE_MASK) == TYPE_PRODUCT) {
+ atype = ptype->left;
+ }
+ while((param->type->type & TYPE_MASK) != (atype->type & TYPE_MASK)) {
+ param = param->next;
+ }
+ arg = RHS(ptr, i);
+ flatten(state, first, write_expr(state, param, arg));
+ ptype = ptype->right;
+ param = param->next;
+ }
+
+ /* Thread the triples together */
+ ret_loc = flatten(state, first, ret_loc);
+ ret_addr = flatten(state, ret_loc, ret_addr);
+ ret_set = flatten(state, ret_loc, write_expr(state, retvar, ret_addr));
+ jmp = flatten(state, ret_loc,
+ call(state, retvar, ret_addr, func_first, func_last));
+
+ /* Find the result */
+ result = 0;
+ if ((func->type->left->type & TYPE_MASK) != TYPE_VOID) {
+ result = read_expr(state, MISC(func, 0));
+ }
+
+ if (state->compiler->debug & DEBUG_INLINE) {
+ fprintf(stdout, "\n");
+ loc(stdout, state, 0);
+ fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(stdout, func);
+ fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ }
+
+ return result;
+}
+
+static void inline_functions(struct compile_state *state, struct triple *first)
+{
+ struct triple *ptr, *next;
+ ptr = next = first;
+ do {
+ int do_inline;
+ struct triple *func, *prev, *new;
+ ptr = next;
+ prev = ptr->prev;
+ next = ptr->next;
+ if (ptr->op != OP_FCALL) {
+ continue;
+ }
+ func = MISC(ptr, 0);
+ /* See if the function should be inlined */
+ switch(func->type->type & STOR_MASK) {
+ case STOR_STATIC | STOR_INLINE:
+ case STOR_LOCAL | STOR_INLINE:
+ case STOR_EXTERN | STOR_INLINE:
+ do_inline = 1;
+ break;
+ default:
+ do_inline = (func->u.cval == 1);
+ break;
+ }
+ if (state->compiler->flags & COMPILER_ALWAYS_INLINE) {
+ do_inline = 1;
+ }
+ if (!(state->compiler->flags & COMPILER_INLINE)) {
+ do_inline = 0;
+ }
+ if (!do_inline) {
+ continue;
+ }
+ if (state->compiler->debug & DEBUG_INLINE) {
+ fprintf(stderr, "inlining %s\n",
+ func->type->type_ident->name);
+ }
+
+ /* Update the function use counts */
+ func->u.cval -= 1;
+ /* Unhook the call and really inline it */
+ next->prev = prev;
+ prev->next = next;
+ ptr->next = ptr->prev = ptr;
+
+ new = flatten(state, next,
+ flatten_inline_call(state, next, ptr));
+ if (new) {
+ propogate_use(state, ptr, new);
+ }
+ release_triple(state, ptr);
+ next = prev->next;
+ } while (next != first);
+ ptr = next = first;
+ do {
+ struct triple *func, *prev, *new;
+ ptr = next;
+ prev = ptr->prev;
+ next = ptr->next;
+ if (ptr->op != OP_FCALL) {
+ continue;
+ }
+ func = MISC(ptr, 0);
+ inline_functions(state, RHS(func, 0));
+ /* Unhook the call and really flatten it */
+ next->prev = prev;
+ prev->next = next;
+ ptr->next = ptr->prev = ptr;
+ new = flatten(state, next,
+ flatten_function_call(state, next, ptr));
+ if (new) {
+ propogate_use(state, ptr, new);
+ }
+ release_triple(state, ptr);
+ next = prev->next;
+ } while(next != first);
+}
+
+static void insert_function(struct compile_state *state,
+ struct triple *func, void *arg)
+{
+ struct triple *first, *end, *ffirst, *fend;
+
+ if (state->compiler->debug & DEBUG_INLINE) {
+ fprintf(stderr, "%s func count: %d\n",
+ func->type->type_ident->name, func->u.cval);
+ }
+ if (func->u.cval == 0) {
+ return;
+ }
+ if (state->compiler->flags & COMPILER_ALWAYS_INLINE) {
+ internal_error(state, func, "always inline failed\n");
+ }
+
+ /* Find the end points of the lists */
+ first = arg;
+ end = first->prev;
+ ffirst = RHS(func, 0);
+ fend = ffirst->prev;
+
+ /* splice the lists together */
+ end->next = ffirst;
+ ffirst->prev = end;
+ fend->next = first;
+ first->prev = fend;
+}
+
+static void join_functions(struct compile_state *state)
+{
+ struct triple *jmp, *start, *end, *call;
+ struct file_state file;
+
+ /* Dummy file state to get debug handing right */
+ memset(&file, 0, sizeof(file));
+ file.basename = "";
+ file.line = 0;
+ file.report_line = 0;
+ file.report_name = file.basename;
+ file.prev = state->file;
+ state->file = &file;
+ state->function = "";
+
+ /* Lay down the basic program structure */
+ end = label(state);
+ start = label(state);
+ start = flatten(state, state->first, start);
+ end = flatten(state, state->first, end);
+ call = new_triple(state, OP_FCALL, &void_type, -1, 0);
+ MISC(call, 0) = state->main_function;
+ flatten(state, state->first, call);
+
+ /* See which functions are called, and how often */
+ mark_live_functions(state, state->first);
+ inline_functions(state, state->first);
+ walk_functions(state, insert_function, end);
+
+ if (start->next != end) {
+ jmp = flatten(state, start, branch(state, end, 0));
+ }
+
+ /* Done now cleanup */
+ state->file = file.prev;
+ state->function = 0;
+}
+
/*
* Data structurs for optimation.
*/
+
static int do_use_block(
struct block *used, struct block_set **head, struct block *user,
int front)
@@ -9856,6 +10520,20 @@ static void unuse_block(struct block *used, struct block *unuser)
used->users -= count;
}
+static void add_block_edge(struct block *block, struct block *edge, int front)
+{
+ int count;
+ count = do_use_block(block, &block->edges, edge, front);
+ block->edge_count += count;
+}
+
+static void remove_block_edge(struct block *block, struct block *edge)
+{
+ int count;
+ count = do_unuse_block(block, &block->edges, edge);
+ block->edge_count -= count;
+}
+
static void idom_block(struct block *idom, struct block *user)
{
do_use_block(idom, &idom->idominates, user, 0);
@@ -9928,7 +10606,7 @@ static int do_print_triple(struct compile_state *state, struct triple *ins)
}
display_triple(stdout, ins);
- if ((ins->op == OP_BRANCH) && ins->use) {
+ if (triple_is_branch(state, ins) && ins->use && (ins->op != OP_RET)) {
internal_error(state, ins, "branch used?");
}
if (triple_is_branch(state, ins)) {
@@ -9939,7 +10617,9 @@ static int do_print_triple(struct compile_state *state, struct triple *ins)
static void print_triples(struct compile_state *state)
{
- walk_triples(state, do_print_triple);
+ if (state->compiler->debug & DEBUG_TRIPLES) {
+ walk_triples(state, do_print_triple);
+ }
}
struct cf_block {
@@ -9947,12 +10627,14 @@ struct cf_block {
};
static void find_cf_blocks(struct cf_block *cf, struct block *block)
{
+ struct block_set *edge;
if (!block || (cf[block->vertex].block == block)) {
return;
}
cf[block->vertex].block = block;
- find_cf_blocks(cf, block->left);
- find_cf_blocks(cf, block->right);
+ for(edge = block->edges; edge; edge = edge->next) {
+ find_cf_blocks(cf, edge->member);
+ }
}
static void print_control_flow(struct compile_state *state)
@@ -9965,15 +10647,13 @@ static void print_control_flow(struct compile_state *state)
for(i = 1; i <= state->last_vertex; i++) {
struct block *block;
+ struct block_set *edge;
block = cf[i].block;
if (!block)
continue;
printf("(%p) %d:", block, block->vertex);
- if (block->left) {
- printf(" %d", block->left->vertex);
- }
- if (block->right && (block->right != block->left)) {
- printf(" %d", block->right->vertex);
+ for(edge = block->edges; edge; edge = edge->next) {
+ printf(" %d", edge->member->vertex);
}
printf("\n");
}
@@ -9982,8 +10662,7 @@ static void print_control_flow(struct compile_state *state)
}
-static struct block *basic_block(struct compile_state *state,
- struct triple *first)
+static struct block *basic_block(struct compile_state *state, struct triple *first)
{
struct block *block;
struct triple *ptr;
@@ -10018,32 +10697,52 @@ static struct block *basic_block(struct compile_state *state,
/* 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);
+ struct block *next;
+ next = basic_block(state, ptr);
+ add_block_edge(block, next, 0);
+ use_block(next, block);
}
else if (triple_is_branch(state, ptr)) {
- block->left = 0;
- /* Trace the branch target */
- block->right = basic_block(state, TARG(ptr, 0));
- use_block(block->right, block);
- /* If there is a test trace the branch as well */
- if (TRIPLE_RHS(ptr->sizes)) {
- block->left = basic_block(state, ptr->next);
- use_block(block->left, block);
+ struct triple **expr, *first;
+ struct block *child;
+ /* Find the branch targets.
+ * I special case the first branch as that magically
+ * avoids some difficult cases for the register allocator.
+ */
+ expr = triple_targ(state, ptr, 0);
+ if (!expr) {
+ internal_error(state, ptr, "branch without targets");
+ }
+ first = *expr;
+ expr = triple_targ(state, ptr, expr);
+ for(; expr; expr = triple_targ(state, ptr, expr)) {
+ if (!*expr) continue;
+ child = basic_block(state, *expr);
+ use_block(child, block);
+ add_block_edge(block, child, 0);
+ }
+ if (first) {
+ child = basic_block(state, first);
+ use_block(child, block);
+ add_block_edge(block, child, 1);
}
}
else {
internal_error(state, 0, "Bad basic block split");
}
#if 0
- fprintf(stderr, "basic_block: %10p [%2d] ( %10p - %10p ) %10p [%2d] %10p [%2d] \n",
+{
+ struct block_set *edge;
+ fprintf(stderr, "basic_block: %10p [%2d] ( %10p - %10p )",
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);
+ block->first, block->last);
+ for(edge = block->edges; edge; edge = edge->next) {
+ fprintf(stderr, " %10p [%2d]",
+ edge->member ? edge->member->first : 0,
+ edge->member ? edge->member->vertex : -1);
+ }
+ fprintf(stderr, "\n");
+}
#endif
return block;
}
@@ -10059,17 +10758,14 @@ static void walk_blocks(struct compile_state *state,
first = state->first;
ptr = first;
do {
- struct block *block;
if (triple_stores_block(state, ptr)) {
+ struct block *block;
block = ptr->u.block;
if (block && (block != last_block)) {
cb(state, block, arg);
}
last_block = block;
}
- if (block && (block->last == ptr)) {
- block = 0;
- }
ptr = ptr->next;
} while(ptr != first);
}
@@ -10077,17 +10773,21 @@ static void walk_blocks(struct compile_state *state,
static void print_block(
struct compile_state *state, struct block *block, void *arg)
{
- struct block_set *user;
+ struct block_set *user, *edge;
struct triple *ptr;
FILE *fp = arg;
- fprintf(fp, "\nblock: %p (%d) %p<-%p %p<-%p\n",
+ fprintf(fp, "\nblock: %p (%d) ",
block,
- block->vertex,
- block->left,
- block->left && block->left->use?block->left->use->member : 0,
- block->right,
- block->right && block->right->use?block->right->use->member : 0);
+ block->vertex);
+
+ for(edge = block->edges; edge; edge = edge->next) {
+ fprintf(fp, " %p<-%p",
+ edge->member,
+ (edge->member && edge->member->use)?
+ edge->member->use->member : 0);
+ }
+ fprintf(fp, "\n");
if (block->first->op == OP_LABEL) {
fprintf(fp, "%p:\n", block->first);
}
@@ -10106,11 +10806,19 @@ static void print_block(
}
-static void print_blocks(struct compile_state *state, FILE *fp)
+static void romcc_print_blocks(struct compile_state *state, FILE *fp)
{
fprintf(fp, "--------------- blocks ---------------\n");
walk_blocks(state, print_block, fp);
}
+static void print_blocks(struct compile_state *state, const char *func, FILE *fp)
+{
+ if (state->compiler->debug & DEBUG_BASIC_BLOCKS) {
+ fprintf(fp, "After %s\n", func);
+ romcc_print_blocks(state, fp);
+ print_control_flow(state);
+ }
+}
static void prune_nonblock_triples(struct compile_state *state)
{
@@ -10164,26 +10872,33 @@ static void setup_basic_blocks(struct compile_state *state)
{
struct block *block, *prev_block;
struct triple *final;
+
prev_block = state->last_block;
+
final = label(state);
flatten(state, state->first, final);
+ final->id |= TRIPLE_FLAG_VOLATILE;
use_triple(final, final);
block = basic_block(state, final);
+
state->last_block = block;
- prev_block->left = block;
- use_block(prev_block->left, prev_block);
+
+ add_block_edge(prev_block, block, 0);
+ use_block(block, prev_block);
}
+#if 0
/* If we are debugging print what I have just done */
- if (state->debug & DEBUG_BASIC_BLOCKS) {
+ if (state->compiler->debug & DEBUG_BASIC_BLOCKS) {
print_blocks(state, stdout);
print_control_flow(state);
}
+#endif
}
static void free_basic_block(struct compile_state *state, struct block *block)
{
- struct block_set *entry, *next;
+ struct block_set *edge, *entry;
struct block *child;
if (!block) {
return;
@@ -10192,11 +10907,10 @@ static void free_basic_block(struct compile_state *state, struct block *block)
return;
}
block->vertex = -1;
- if (block->left) {
- unuse_block(block->left, block);
- }
- if (block->right) {
- unuse_block(block->right, block);
+ for(edge = block->edges; edge; edge = edge->next) {
+ if (edge->member) {
+ unuse_block(edge->member, block);
+ }
}
if (block->idom) {
unidom_block(block->idom, block);
@@ -10206,46 +10920,48 @@ static void free_basic_block(struct compile_state *state, struct block *block)
unipdom_block(block->ipdom, block);
}
block->ipdom = 0;
- for(entry = block->use; entry; entry = next) {
- next = entry->next;
+ while((entry = block->use)) {
child = entry->member;
unuse_block(block, child);
- if (child->left == block) {
- child->left = 0;
- }
- if (child->right == block) {
- child->right = 0;
+ if (child && (child->vertex != -1)) {
+ for(edge = child->edges; edge; edge = edge->next) {
+ edge->member = 0;
+ }
}
}
- for(entry = block->idominates; entry; entry = next) {
- next = entry->next;
+ while((entry = block->idominates)) {
child = entry->member;
unidom_block(block, child);
- child->idom = 0;
+ if (child && (child->vertex != -1)) {
+ child->idom = 0;
+ }
}
- for(entry = block->domfrontier; entry; entry = next) {
- next = entry->next;
+ while((entry = block->domfrontier)) {
child = entry->member;
undomf_block(block, child);
}
- for(entry = block->ipdominates; entry; entry = next) {
- next = entry->next;
+ while((entry = block->ipdominates)) {
child = entry->member;
unipdom_block(block, child);
- child->ipdom = 0;
+ if (child && (child->vertex != -1)) {
+ child->ipdom = 0;
+ }
}
- for(entry = block->ipdomfrontier; entry; entry = next) {
- next = entry->next;
+ while((entry = block->ipdomfrontier)) {
child = entry->member;
unipdomf_block(block, child);
}
if (block->users != 0) {
internal_error(state, 0, "block still has users");
}
- free_basic_block(state, block->left);
- block->left = 0;
- free_basic_block(state, block->right);
- block->right = 0;
+ while((edge = block->edges)) {
+ child = edge->member;
+ remove_block_edge(block, child);
+
+ if (child && (child->vertex != -1)) {
+ free_basic_block(state, child);
+ }
+ }
memset(block, -1, sizeof(*block));
xfree(block);
}
@@ -10308,6 +11024,7 @@ static void sdom_block(struct sdom_block *sdom, struct sdom_block *block)
static int initialize_sdblock(struct sdom_block *sd,
struct block *parent, struct block *block, int vertex)
{
+ struct block_set *edge;
if (!block || (sd[block->vertex].block == block)) {
return vertex;
}
@@ -10320,8 +11037,9 @@ static int initialize_sdblock(struct sdom_block *sd,
sd[vertex].parent = parent? &sd[parent->vertex] : 0;
sd[vertex].ancestor = 0;
sd[vertex].vertex = vertex;
- vertex = initialize_sdblock(sd, block, block->left, vertex);
- vertex = initialize_sdblock(sd, block, block->right, vertex);
+ for(edge = block->edges; edge; edge = edge->next) {
+ vertex = initialize_sdblock(sd, block, edge->member, vertex);
+ }
return vertex;
}
@@ -10355,25 +11073,21 @@ static int setup_spdblocks(struct compile_state *state, struct sdom_block *sd)
/* Setup as many sdpblocks as possible without using fake edges */
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.
+ /* Walk through the graph and find unconnected blocks. 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) {
if (sd[block->vertex].block == block) {
continue;
}
- if (block->left != 0) {
- continue;
- }
-
#if DEBUG_SDP_BLOCKS
fprintf(stderr, "Adding %d\n", vertex +1);
#endif
+ add_block_edge(block, state->last_block, 0);
+ use_block(state->last_block, block);
- block->left = state->last_block;
- use_block(block->left, block);
vertex = initialize_spdblock(state, sd, state->last_block, block, vertex);
}
return vertex;
@@ -10473,19 +11187,13 @@ static void compute_spdom(struct compile_state *state, struct sdom_block *sd)
*/
for(i = state->last_vertex; i >= 2; i--) {
struct sdom_block *u, *v, *parent, *next;
+ struct block_set *edge;
struct block *block;
block = sd[i].block;
parent = sd[i].parent;
/* Step 2 */
- if (block->left) {
- v = &sd[block->left->vertex];
- u = !(v->ancestor)? v : (compress_ancestors(v), v->label);
- if (u->sdom->vertex < sd[i].sdom->vertex) {
- sd[i].sdom = u->sdom;
- }
- }
- if (block->right && (block->right != block->left)) {
- v = &sd[block->right->vertex];
+ for(edge = block->edges; edge; edge = edge->next) {
+ v = &sd[edge->member->vertex];
u = !(v->ancestor)? v : (compress_ancestors(v), v->label);
if (u->sdom->vertex < sd[i].sdom->vertex) {
sd[i].sdom = u->sdom;
@@ -10637,7 +11345,7 @@ static void find_post_dominators(struct compile_state *state)
static void find_block_domf(struct compile_state *state, struct block *block)
{
struct block *child;
- struct block_set *user;
+ struct block_set *user, *edge;
if (block->domfrontier != 0) {
internal_error(state, block->first, "domfrontier present?");
}
@@ -10648,11 +11356,10 @@ static void find_block_domf(struct compile_state *state, struct block *block)
}
find_block_domf(state, child);
}
- if (block->left && block->left->idom != block) {
- domf_block(block, block->left);
- }
- if (block->right && block->right->idom != block) {
- domf_block(block, block->right);
+ for(edge = block->edges; edge; edge = edge->next) {
+ if (edge->member->idom != block) {
+ domf_block(block, edge->member);
+ }
}
for(user = block->idominates; user; user = user->next) {
struct block_set *frontier;
@@ -10711,17 +11418,58 @@ static void print_dominated(
fprintf(fp,"\n");
}
+static void print_dominated2(
+ struct compile_state *state, FILE *fp, int depth, struct block *block)
+{
+ struct block_set *user;
+ struct triple *ins;
+ struct occurance *ptr, *ptr2;
+ const char *filename1, *filename2;
+ int equal_filenames;
+ int i;
+ for(i = 0; i < depth; i++) {
+ fprintf(fp, " ");
+ }
+ fprintf(fp, "%3d: %p (%p - %p) @",
+ block->vertex, block, block->first, block->last);
+ ins = block->first;
+ while(ins != block->last && (ins->occurance->line == 0)) {
+ ins = ins->next;
+ }
+ ptr = ins->occurance;
+ ptr2 = block->last->occurance;
+ filename1 = ptr->filename? ptr->filename : "";
+ filename2 = ptr2->filename? ptr2->filename : "";
+ equal_filenames = (strcmp(filename1, filename2) == 0);
+ if ((ptr == ptr2) || (equal_filenames && ptr->line == ptr2->line)) {
+ fprintf(fp, " %s:%d", ptr->filename, ptr->line);
+ } else if (equal_filenames) {
+ fprintf(fp, " %s:(%d - %d)",
+ ptr->filename, ptr->line, ptr2->line);
+ } else {
+ fprintf(fp, " (%s:%d - %s:%d)",
+ ptr->filename, ptr->line,
+ ptr2->filename, ptr2->line);
+ }
+ fprintf(fp, "\n");
+ for(user = block->idominates; user; user = user->next) {
+ print_dominated2(state, fp, depth + 1, user->member);
+ }
+}
+
static void print_dominators(struct compile_state *state, FILE *fp)
{
fprintf(fp, "\ndominates\n");
walk_blocks(state, print_dominated, fp);
+ fprintf(fp, "dominates\n");
+ print_dominated2(state, fp, 0, state->first_block);
}
static int print_frontiers(
struct compile_state *state, struct block *block, int vertex)
{
- struct block_set *user;
+ struct block_set *user, *edge;
if (!block || (block->vertex != vertex + 1)) {
return vertex;
@@ -10733,9 +11481,10 @@ static int print_frontiers(
printf(" %d", user->member->vertex);
}
printf("\n");
-
- vertex = print_frontiers(state, block->left, vertex);
- vertex = print_frontiers(state, block->right, vertex);
+
+ for(edge = block->edges; edge; edge = edge->next) {
+ vertex = print_frontiers(state, edge->member, vertex);
+ }
return vertex;
}
static void print_dominance_frontiers(struct compile_state *state)
@@ -10752,7 +11501,7 @@ static void analyze_idominators(struct compile_state *state)
/* Find the dominance frontiers */
find_block_domf(state, state->first_block);
/* If debuging print the print what I have just found */
- if (state->debug & DEBUG_FDOMINATORS) {
+ if (state->compiler->debug & DEBUG_FDOMINATORS) {
print_dominators(state, stdout);
print_dominance_frontiers(state);
print_control_flow(state);
@@ -10817,7 +11566,7 @@ static void analyze_ipdominators(struct compile_state *state)
/* Find the control dependencies (post dominance frontiers) */
find_block_ipdomf(state, state->last_block);
/* If debuging print the print what I have just found */
- if (state->debug & DEBUG_RDOMINATORS) {
+ if (state->compiler->debug & DEBUG_RDOMINATORS) {
print_ipdominators(state, stdout);
print_ipdominance_frontiers(state);
print_control_flow(state);
@@ -11099,7 +11848,7 @@ static void fixup_block_phi_variables(
static void rename_block_variables(
struct compile_state *state, struct stack *stacks, struct block *block)
{
- struct block_set *user;
+ struct block_set *user, *edge;
struct triple *ptr, *next, *last;
int done;
if (!block)
@@ -11167,8 +11916,9 @@ static void rename_block_variables(
block->last = last;
/* Fixup PHI functions in the cf successors */
- fixup_block_phi_variables(state, stacks, block, block->left);
- fixup_block_phi_variables(state, stacks, block, block->right);
+ for(edge = block->edges; edge; edge = edge->next) {
+ fixup_block_phi_variables(state, stacks, block, edge->member);
+ }
/* rename variables in the dominated nodes */
for(user = block->idominates; user; user = user->next) {
rename_block_variables(state, stacks, user->member);
@@ -11353,6 +12103,8 @@ static void transform_to_ssa_form(struct compile_state *state)
prune_block_variables(state, state->first_block);
prune_unused_phis(state);
+
+ print_blocks(state, __func__, stdout);
}
@@ -11363,13 +12115,10 @@ static void clear_vertex(
* of the current blocks neighbors in case there are malformed
* blocks with now instructions at this point.
*/
- struct block_set *user;
+ struct block_set *user, *edge;
block->vertex = 0;
- if (block->left) {
- block->left->vertex = 0;
- }
- if (block->right) {
- block->right->vertex = 0;
+ for(edge = block->edges; edge; edge = edge->next) {
+ edge->member->vertex = 0;
}
for(user = block->use; user; user = user->next) {
user->member->vertex = 0;
@@ -11422,11 +12171,6 @@ 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 = state->first;
for(phi = first->next; phi != first ; phi = next) {
@@ -11575,11 +12319,10 @@ static void transform_from_ssa_form(struct compile_state *state)
}
}
-#if 0
-#define HI() do { fprintf(stderr, "@ %s:%d\n", __FILE__, __LINE__); print_blocks(state, stderr); } while (0)
-#else
-#define HI()
-#endif
+#define HI() if (state->compiler->debug & DEBUG_REBUILD_SSA_FORM) { \
+ fprintf(stderr, "@ %s:%d\n", __FILE__, __LINE__); romcc_print_blocks(state, stderr); \
+ }
+
static void rebuild_ssa_form(struct compile_state *state)
{
HI();
@@ -11970,6 +12713,7 @@ static void insert_copies_to_phi(struct compile_state *state)
transform_to_arch_instruction(state, move);
}
}
+ print_blocks(state, __func__, stdout);
}
struct triple_reg_set {
@@ -12207,16 +12951,12 @@ static struct reg_block *compute_variable_lifetimes(
int i;
change = 0;
for(i = 1; i <= state->last_vertex; i++) {
+ struct block_set *edge;
struct reg_block *rb;
rb = &blocks[i];
- /* Add the left successor's input set to in */
- if (rb->block->left) {
- change |= reg_in(state, blocks, rb, rb->block->left);
- }
- /* Add the right successor's input set to in */
- if ((rb->block->right) &&
- (rb->block->right != rb->block->left)) {
- change |= reg_in(state, blocks, rb, rb->block->right);
+ /* Add the all successor's input set to in */
+ for(edge = rb->block->edges; edge; edge = edge->next) {
+ change |= reg_in(state, blocks, rb, edge->member);
}
/* Add use to in... */
change |= use_in(state, rb);
@@ -12385,6 +13125,10 @@ static void eliminate_inefectual_code(struct compile_state *state)
int triples, i;
struct triple *first, *final, *ins;
+ if (!(state->compiler->flags & COMPILER_ELIMINATE_INEFECTUAL_CODE)) {
+ return;
+ }
+
/* Setup the work list */
work_list = 0;
work_list_tail = &work_list;
@@ -12452,12 +13196,13 @@ static void eliminate_inefectual_code(struct compile_state *state)
} while(expr);
/* 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");
+ struct triple *last;
+ last = user->member->last;
+ while((last->op == OP_NOOP) && (last != user->member->first)) {
+ internal_warning(state, last, "awakening noop?");
+ last = last->prev;
}
+ awaken(state, dtriple, &last, &work_list_tail);
}
}
for(dt = &dtriple[1]; dt <= &dtriple[triples]; dt++) {
@@ -12471,6 +13216,10 @@ static void eliminate_inefectual_code(struct compile_state *state)
}
}
xfree(dtriple);
+
+ rebuild_ssa_form(state);
+
+ print_blocks(state, __func__, stdout);
}
@@ -12626,6 +13375,8 @@ static void insert_mandatory_copies(struct compile_state *state)
next:
ins = ins->next;
} while(ins != first);
+
+ print_blocks(state, __func__, stdout);
}
@@ -12677,7 +13428,6 @@ struct reg_state {
unsigned defs;
unsigned ranges;
int passes, max_passes;
-#define MAX_ALLOCATION_PASSES 100
};
@@ -12693,6 +13443,7 @@ static void print_interference_block(
{
struct print_interference_block_info *info = arg;
struct reg_state *rstate = info->rstate;
+ struct block_set *edge;
FILE *fp = info->fp;
struct reg_block *rb;
struct triple *ptr;
@@ -12700,13 +13451,14 @@ static void print_interference_block(
int done;
rb = &rstate->blocks[block->vertex];
- fprintf(fp, "\nblock: %p (%d), %p<-%p %p<-%p\n",
- block,
- block->vertex,
- block->left,
- block->left && block->left->use?block->left->use->member : 0,
- block->right,
- block->right && block->right->use?block->right->use->member : 0);
+ fprintf(fp, "\nblock: %p (%d),",
+ block, block->vertex);
+ for(edge = block->edges; edge; edge = edge->next) {
+ fprintf(fp, " %p<-%p",
+ edge->member,
+ edge->member && edge->member->use?edge->member->use->member : 0);
+ }
+ fprintf(fp, "\n");
if (rb->in) {
struct triple_reg_set *in_set;
fprintf(fp, " in:");
@@ -13125,21 +13877,21 @@ static struct live_range *coalesce_ranges(
internal_error(state, lr1->defs->def,
"cannot coalesce live ranges with dissimilar register classes");
}
-#if DEBUG_COALESCING
- fprintf(stderr, "coalescing:");
- lrd = lr1->defs;
- do {
- fprintf(stderr, " %p", lrd->def);
- lrd = lrd->next;
- } while(lrd != lr1->defs);
- fprintf(stderr, " |");
- lrd = lr2->defs;
- do {
- fprintf(stderr, " %p", lrd->def);
- lrd = lrd->next;
- } while(lrd != lr2->defs);
- fprintf(stderr, "\n");
-#endif
+ if (state->compiler->debug & DEBUG_COALESCING) {
+ fprintf(stderr, "coalescing:");
+ lrd = lr1->defs;
+ do {
+ fprintf(stderr, " %p", lrd->def);
+ lrd = lrd->next;
+ } while(lrd != lr1->defs);
+ fprintf(stderr, " |");
+ lrd = lr2->defs;
+ do {
+ fprintf(stderr, " %p", lrd->def);
+ lrd = lrd->next;
+ } while(lrd != lr2->defs);
+ fprintf(stderr, "\n");
+ }
/* If there is a clear dominate live range put it in lr1,
* For purposes of this test phi functions are
* considered dominated by the definitions that feed into
@@ -13327,10 +14079,11 @@ static void initialize_live_ranges(
}
zrhs = TRIPLE_RHS(ins->sizes);
-#if DEBUG_COALESCING > 1
- fprintf(stderr, "mandatory coalesce: %p %d %d\n",
- ins, zlhs, zrhs);
-#endif
+ if (state->compiler->debug & DEBUG_COALESCING2) {
+ fprintf(stderr, "mandatory coalesce: %p %d %d\n",
+ ins, zlhs, zrhs);
+ }
+
for(i = 0; i < zlhs; i++) {
struct reg_info linfo;
struct live_range_def *lhs;
@@ -13343,11 +14096,12 @@ static void initialize_live_ranges(
} else {
lhs = &rstate->lrd[LHS(ins, i)->id];
}
-#if DEBUG_COALESCING > 1
- fprintf(stderr, "coalesce lhs(%d): %p %d\n",
- i, lhs, linfo.reg);
-
-#endif
+
+ if (state->compiler->debug & DEBUG_COALESCING2) {
+ fprintf(stderr, "coalesce lhs(%d): %p %d\n",
+ i, lhs, linfo.reg);
+ }
+
for(j = 0; j < zrhs; j++) {
struct reg_info rinfo;
struct live_range_def *rhs;
@@ -13356,11 +14110,12 @@ static void initialize_live_ranges(
continue;
}
rhs = &rstate->lrd[RHS(ins, j)->id];
-#if DEBUG_COALESCING > 1
- fprintf(stderr, "coalesce rhs(%d): %p %d\n",
- j, rhs, rinfo.reg);
-
-#endif
+
+ if (state->compiler->debug & DEBUG_COALESCING2) {
+ fprintf(stderr, "coalesce rhs(%d): %p %d\n",
+ j, rhs, rinfo.reg);
+ }
+
if (rinfo.reg == linfo.reg) {
coalesce_ranges(state, rstate,
lhs->lr, rhs->lr);
@@ -13887,37 +14642,49 @@ static void cleanup_rstate(struct compile_state *state, struct reg_state *rstate
struct triple *find_constrained_def(
struct compile_state *state, struct live_range *range, struct triple *constrained)
{
- struct live_range_def *lrd;
- lrd = range->defs;
+ struct live_range_def *lrd, *lrd_next;
+ lrd_next = range->defs;
do {
struct reg_info info;
unsigned regcm;
- int is_constrained;
+
+ lrd = lrd_next;
+ lrd_next = lrd->next;
+
regcm = arch_type_to_regcm(state, lrd->def->type);
info = find_lhs_color(state, lrd->def, 0);
regcm = arch_regcm_reg_normalize(state, regcm);
info.regcm = arch_regcm_reg_normalize(state, info.regcm);
- /* If the 2 register class masks are not equal the
- * the current register class is constrained.
+ /* If the 2 register class masks are equal then
+ * the current register class is not constrained.
*/
- is_constrained = regcm != info.regcm;
+ if (regcm == info.regcm) {
+ continue;
+ }
+ /* If there is just one use.
+ * That use cannot accept a larger register class.
+ * There are no intervening definitions except
+ * definitions that feed into that use.
+ * Then a triple is not constrained.
+ * FIXME handle this case!
+ */
+#warning "FIXME ignore cases that cannot be fixed (a definition followed by a use)"
+
+
/* Of the constrained live ranges deal with the
* least dominated one first.
*/
- if (is_constrained) {
-#if DEBUG_RANGE_CONFLICTS
+ if (state->compiler->debug & DEBUG_RANGE_CONFLICTS) {
fprintf(stderr, "canidate: %p %-8s regcm: %x %x\n",
lrd->def, tops(lrd->def->op), regcm, info.regcm);
-#endif
- if (!constrained ||
- tdominates(state, lrd->def, constrained))
- {
- constrained = lrd->def;
- }
}
- lrd = lrd->next;
- } while(lrd != range->defs);
+ if (!constrained ||
+ tdominates(state, lrd->def, constrained))
+ {
+ constrained = lrd->def;
+ }
+ } while(lrd_next != range->defs);
return constrained;
}
@@ -13938,13 +14705,15 @@ static int split_constrained_ranges(
for(edge = range->edges; edge; edge = edge->next) {
constrained = find_constrained_def(state, edge->node, constrained);
}
+#warning "FIXME should I call find_constrained_def here only if no previous constrained def was found?"
if (!constrained) {
constrained = find_constrained_def(state, range, constrained);
}
-#if DEBUG_RANGE_CONFLICTS
- fprintf(stderr, "constrained: %p %-8s\n",
- constrained, tops(constrained->op));
-#endif
+
+ if (state->compiler->debug & DEBUG_RANGE_CONFLICTS) {
+ fprintf(stderr, "constrained: %p %-8s\n",
+ constrained, tops(constrained->op));
+ }
if (constrained) {
ids_from_rstate(state, rstate);
cleanup_rstate(state, rstate);
@@ -13958,10 +14727,10 @@ static int split_ranges(
char *used, struct live_range *range)
{
int split;
-#if DEBUG_RANGE_CONFLICTS
- fprintf(stderr, "split_ranges %d %s %p\n",
- rstate->passes, tops(range->defs->def->op), range->defs->def);
-#endif
+ if (state->compiler->debug & DEBUG_RANGE_CONFLICTS) {
+ fprintf(stderr, "split_ranges %d %s %p\n",
+ rstate->passes, tops(range->defs->def->op), range->defs->def);
+ }
if ((range->color == REG_UNNEEDED) ||
(rstate->passes >= rstate->max_passes)) {
return 0;
@@ -13981,29 +14750,57 @@ static int split_ranges(
*
*/
#warning "WISHLIST implement live range splitting..."
- if ((DEBUG_RANGE_CONFLICTS > 1) &&
- (!split || (DEBUG_RANGE_CONFLICTS > 2))) {
+
+ if (!split && (state->compiler->debug & DEBUG_RANGE_CONFLICTS2)) {
print_interference_blocks(state, rstate, stderr, 0);
print_dominators(state, stderr);
}
return split;
}
-#if DEBUG_COLOR_GRAPH > 1
-#define cgdebug_printf(...) fprintf(stdout, __VA_ARGS__)
-#define cgdebug_flush() fflush(stdout)
-#define cgdebug_loc(STATE, TRIPLE) loc(stdout, STATE, TRIPLE)
-#elif DEBUG_COLOR_GRAPH == 1
-#define cgdebug_printf(...) fprintf(stderr, __VA_ARGS__)
-#define cgdebug_flush() fflush(stderr)
-#define cgdebug_loc(STATE, TRIPLE) loc(stderr, STATE, TRIPLE)
-#else
-#define cgdebug_printf(...)
-#define cgdebug_flush()
-#define cgdebug_loc(STATE, TRIPLE)
-#endif
+static FILE *cgdebug_fp(struct compile_state *state)
+{
+ FILE *fp;
+ fp = 0;
+ if (!fp && (state->compiler->debug & DEBUG_COLOR_GRAPH2)) {
+ fp = stderr;
+ }
+ if (!fp && (state->compiler->debug & DEBUG_COLOR_GRAPH)) {
+ fp = stdout;
+ }
+ return fp;
+}
+
+static void cgdebug_printf(struct compile_state *state, const char *fmt, ...)
+{
+ FILE *fp;
+ fp = cgdebug_fp(state);
+ if (fp) {
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(fp, fmt, args);
+ va_end(args);
+ }
+}
+
+static void cgdebug_flush(struct compile_state *state)
+{
+ FILE *fp;
+ fp = cgdebug_fp(state);
+ if (fp) {
+ fflush(fp);
+ }
+}
+
+static void cgdebug_loc(struct compile_state *state, struct triple *ins)
+{
+ FILE *fp;
+ fp = cgdebug_fp(state);
+ if (fp) {
+ loc(fp, state, ins);
+ }
+}
-
static int select_free_color(struct compile_state *state,
struct reg_state *rstate, struct live_range *range)
{
@@ -14027,24 +14824,24 @@ static int select_free_color(struct compile_state *state,
}
reg_fill_used(state, used, edge->node->color);
}
-#if DEBUG_COLOR_GRAPH > 1
- {
+
+ if (state->compiler->debug & DEBUG_COLOR_GRAPH2) {
int i;
i = 0;
for(edge = range->edges; edge; edge = edge->next) {
i++;
}
- cgdebug_printf("\n%s edges: %d @%s:%d.%d\n",
- tops(range->def->op), i,
- range->def->filename, range->def->line, range->def->col);
+ cgdebug_printf(state, "\n%s edges: %d",
+ tops(range->defs->def->op), i);
+ cgdebug_loc(state, range->defs->def);
+ cgdebug_printf(state, "\n");
for(i = 0; i < MAX_REGISTERS; i++) {
if (used[i]) {
- cgdebug_printf("used: %s\n",
+ cgdebug_printf(state, "used: %s\n",
arch_reg_str(i));
}
}
}
-#endif
/* If a color is already assigned see if it will work */
if (range->color != REG_UNSET) {
@@ -14207,11 +15004,7 @@ static int select_free_color(struct compile_state *state,
arch_reg_str(i));
}
}
-#if DEBUG_COLOR_GRAPH < 2
error(state, range->defs->def, "too few registers");
-#else
- internal_error(state, range->defs->def, "too few registers");
-#endif
}
range->classes &= arch_reg_regcm(state, range->color);
if ((range->color == REG_UNSET) || (range->classes == 0)) {
@@ -14226,7 +15019,7 @@ static int color_graph(struct compile_state *state, struct reg_state *rstate)
struct live_range_edge *edge;
struct live_range *range;
if (rstate->low) {
- cgdebug_printf("Lo: ");
+ cgdebug_printf(state, "Lo: ");
range = rstate->low;
if (*range->group_prev != range) {
internal_error(state, 0, "lo: *prev != range?");
@@ -14243,7 +15036,7 @@ static int color_graph(struct compile_state *state, struct reg_state *rstate)
}
}
else if (rstate->high) {
- cgdebug_printf("Hi: ");
+ cgdebug_printf(state, "Hi: ");
range = rstate->high;
if (*range->group_prev != range) {
internal_error(state, 0, "hi: *prev != range?");
@@ -14262,7 +15055,7 @@ static int color_graph(struct compile_state *state, struct reg_state *rstate)
else {
return 1;
}
- cgdebug_printf(" %d\n", range - rstate->lr);
+ cgdebug_printf(state, " %d\n", range - rstate->lr);
range->group_prev = 0;
for(edge = range->edges; edge; edge = edge->next) {
struct live_range *node;
@@ -14280,7 +15073,7 @@ static int color_graph(struct compile_state *state, struct reg_state *rstate)
if (&node->group_next == rstate->high_tail) {
rstate->high_tail = node->group_prev;
}
- cgdebug_printf("Moving...%d to low\n", node - rstate->lr);
+ cgdebug_printf(state, "Moving...%d to low\n", node - rstate->lr);
node->group_prev = rstate->low_tail;
node->group_next = 0;
*rstate->low_tail = node;
@@ -14293,11 +15086,11 @@ static int color_graph(struct compile_state *state, struct reg_state *rstate)
}
colored = color_graph(state, rstate);
if (colored) {
- cgdebug_printf("Coloring %d @", range - rstate->lr);
+ cgdebug_printf(state, "Coloring %d @", range - rstate->lr);
cgdebug_loc(state, range->defs->def);
- cgdebug_flush();
+ cgdebug_flush(state);
colored = select_free_color(state, rstate, range);
- cgdebug_printf(" %s\n", arch_reg_str(range->color));
+ cgdebug_printf(state, " %s\n", arch_reg_str(range->color));
}
return colored;
}
@@ -14416,9 +15209,10 @@ static void ids_from_rstate(struct compile_state *state,
return;
}
/* Display the graph if desired */
- if (state->debug & DEBUG_INTERFERENCE) {
- print_blocks(state, stdout);
+ if (state->compiler->debug & DEBUG_INTERFERENCE) {
+ print_interference_blocks(state, rstate, stdout, 0);
print_control_flow(state);
+ fflush(stdout);
}
first = state->first;
ins = first;
@@ -14466,7 +15260,7 @@ static void allocate_registers(struct compile_state *state)
/* Clear out the reg_state */
memset(&rstate, 0, sizeof(rstate));
- rstate.max_passes = MAX_ALLOCATION_PASSES;
+ rstate.max_passes = state->compiler->max_allocation_passes;
do {
struct live_range **point, **next;
@@ -14474,9 +15268,10 @@ static void allocate_registers(struct compile_state *state)
int tangles;
int coalesced;
-#if DEBUG_RANGE_CONFLICTS
- fprintf(stderr, "pass: %d\n", rstate.passes);
-#endif
+ if (state->compiler->debug & DEBUG_RANGE_CONFLICTS) {
+ fprintf(stderr, "pass: %d\n", rstate.passes);
+ fflush(stderr);
+ }
/* Restore ids */
ids_from_rstate(state, &rstate);
@@ -14500,11 +15295,8 @@ static void allocate_registers(struct compile_state *state)
tangles = correct_tangles(state, rstate.blocks);
} while(tangles);
- if (state->debug & DEBUG_INSERTED_COPIES) {
- printf("After resolve_tangles\n");
- print_blocks(state, stdout);
- print_control_flow(state);
- }
+
+ print_blocks(state, "resolve_tangles", stdout);
verify_consistency(state);
/* Allocate and initialize the live ranges */
@@ -14516,9 +15308,10 @@ static void allocate_registers(struct compile_state *state)
* yields some benefit.
*/
do {
-#if DEBUG_COALESCING
- fprintf(stderr, "coalescing\n");
-#endif
+ if (state->compiler->debug & DEBUG_COALESCING) {
+ fprintf(stderr, "coalescing\n");
+ }
+
/* Remove any previous live edge calculations */
cleanup_live_edges(&rstate);
@@ -14527,7 +15320,7 @@ static void allocate_registers(struct compile_state *state)
state, rstate.blocks, graph_ins, &rstate);
/* Display the interference graph if desired */
- if (state->debug & DEBUG_INTERFERENCE) {
+ if (state->compiler->debug & DEBUG_INTERFERENCE) {
print_interference_blocks(state, &rstate, stdout, 1);
printf("\nlive variables by instruction\n");
walk_variable_lifetimes(
@@ -14537,9 +15330,9 @@ static void allocate_registers(struct compile_state *state)
coalesced = coalesce_live_ranges(state, &rstate);
-#if DEBUG_COALESCING
- fprintf(stderr, "coalesced: %d\n", coalesced);
-#endif
+ if (state->compiler->debug & DEBUG_COALESCING) {
+ fprintf(stderr, "coalesced: %d\n", coalesced);
+ }
} while(coalesced);
#if DEBUG_CONSISTENCY > 1
@@ -14579,7 +15372,7 @@ static void allocate_registers(struct compile_state *state)
*/
if ((range->degree < regc_max_size(state, range->classes)) ||
(range->color != REG_UNSET)) {
- cgdebug_printf("Lo: %5d degree %5d%s\n",
+ cgdebug_printf(state, "Lo: %5d degree %5d%s\n",
range - rstate.lr, range->degree,
(range->color != REG_UNSET) ? " (colored)": "");
*range->group_prev = range->group_next;
@@ -14596,7 +15389,7 @@ static void allocate_registers(struct compile_state *state)
next = point;
}
else {
- cgdebug_printf("hi: %5d degree %5d%s\n",
+ cgdebug_printf(state, "hi: %5d degree %5d%s\n",
range - rstate.lr, range->degree,
(range->color != REG_UNSET) ? " (colored)": "");
}
@@ -14614,6 +15407,9 @@ static void allocate_registers(struct compile_state *state)
/* Cleanup the temporary data structures */
cleanup_rstate(state, &rstate);
+
+ /* Display the new graph */
+ print_blocks(state, __func__, stdout);
}
/* Sparce Conditional Constant Propogation
@@ -14648,11 +15444,12 @@ struct flow_edge {
struct flow_edge *out_next;
int executable;
};
+#define MAX_FLOW_BLOCK_EDGES 3
struct flow_block {
struct block *block;
struct flow_edge *in;
struct flow_edge *out;
- struct flow_edge left, right;
+ struct flow_edge *edges;
};
struct scc_state {
@@ -14668,9 +15465,20 @@ struct scc_state {
static void scc_add_fedge(struct compile_state *state, struct scc_state *scc,
struct flow_edge *fedge)
{
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
+ fprintf(stderr, "adding fedge: %p (%4d -> %5d)\n",
+ fedge,
+ fedge->src->block?fedge->src->block->last->id: 0,
+ fedge->dst->block?fedge->dst->block->first->id: 0);
+ }
if ((fedge == scc->flow_work_list) ||
(fedge->work_next != fedge) ||
(fedge->work_prev != fedge)) {
+
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
+ fprintf(stderr, "dupped fedge: %p\n",
+ fedge);
+ }
return;
}
if (!scc->flow_work_list) {
@@ -14708,19 +15516,20 @@ 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 (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
+ fprintf(stderr, "adding sedge: %5d (%4d -> %5d)\n",
+ sedge - scc->ssa_edges,
+ sedge->src->def->id,
+ sedge->dst->def->id);
+ }
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
+
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
+ fprintf(stderr, "dupped sedge: %5d\n",
+ sedge - scc->ssa_edges);
+ }
return;
}
if (!scc->ssa_work_list) {
@@ -14778,10 +15587,10 @@ static void initialize_scc_state(
}
ins = ins->next;
} while(ins != first);
-#if DEBUG_SCC
- fprintf(stderr, "ins_count: %d ssa_edge_count: %d vertex_count: %d\n",
- ins_count, ssa_edge_count, state->last_vertex);
-#endif
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
+ fprintf(stderr, "ins_count: %d ssa_edge_count: %d vertex_count: %d\n",
+ ins_count, ssa_edge_count, state->last_vertex);
+ }
scc->ins_count = ins_count;
scc->lattice =
xcmalloc(sizeof(*scc->lattice)*(ins_count + 1), "lattice");
@@ -14806,6 +15615,8 @@ static void initialize_scc_state(
block->vertex = fblock_index;
fblock = &scc->flow_blocks[fblock_index];
fblock->block = block;
+ fblock->edges = xcmalloc(sizeof(*fblock->edges)*block->edge_count,
+ "flow_edges");
}
{
struct lattice_node *lnode;
@@ -14825,6 +15636,25 @@ static void initialize_scc_state(
fblock = 0;
ins = first;
do {
+ {
+ struct triple_set *edge;
+ struct ssa_edge **stail;
+ struct lattice_node *lnode;
+ lnode = &scc->lattice[ins->id];
+ lnode->out = 0;
+ stail = &lnode->out;
+ for(edge = ins->use; edge; edge = edge->next) {
+ struct ssa_edge *sedge;
+ ssa_edge_index += 1;
+ sedge = &scc->ssa_edges[ssa_edge_index];
+ *stail = sedge;
+ stail = &sedge->out_next;
+ sedge->src = lnode;
+ sedge->dst = &scc->lattice[edge->member->id];
+ sedge->work_next = sedge->work_prev = sedge;
+ sedge->out_next = 0;
+ }
+ }
if ((ins->op == OP_LABEL) && (block != ins->u.block)) {
struct flow_edge *fedge, **ftail;
struct block_set *bedge;
@@ -14833,29 +15663,35 @@ static void initialize_scc_state(
fblock->in = 0;
fblock->out = 0;
ftail = &fblock->out;
- if (block->left) {
- fblock->left.dst = &scc->flow_blocks[block->left->vertex];
- if (fblock->left.dst->block != block->left) {
- internal_error(state, 0, "block mismatch");
- }
- fblock->left.out_next = 0;
- *ftail = &fblock->left;
- ftail = &fblock->left.out_next;
- }
- if (block->right) {
- fblock->right.dst = &scc->flow_blocks[block->right->vertex];
- if (fblock->right.dst->block != block->right) {
+
+ fedge = fblock->edges;
+ bedge = block->edges;
+ for(; bedge; bedge = bedge->next, fedge++) {
+ fedge->dst = &scc->flow_blocks[bedge->member->vertex];
+ if (fedge->dst->block != bedge->member) {
internal_error(state, 0, "block mismatch");
}
- fblock->right.out_next = 0;
- *ftail = &fblock->right;
- ftail = &fblock->right.out_next;
+ *ftail = fedge;
+ ftail = &fedge->out_next;
+ fedge->out_next = 0;
}
for(fedge = fblock->out; fedge; fedge = fedge->out_next) {
fedge->src = fblock;
fedge->work_next = fedge->work_prev = fedge;
fedge->executable = 0;
}
+ }
+ ins = ins->next;
+ } while (ins != first);
+ block = 0;
+ fblock = 0;
+ ins = first;
+ do {
+ if ((ins->op == OP_LABEL) && (block != ins->u.block)) {
+ struct flow_edge **ftail;
+ struct block_set *bedge;
+ block = ins->u.block;
+ fblock = &scc->flow_blocks[block->vertex];
ftail = &fblock->in;
for(bedge = block->use; bedge; bedge = bedge->next) {
struct block *src_block;
@@ -14863,36 +15699,19 @@ static void initialize_scc_state(
struct flow_edge *sfedge;
src_block = bedge->member;
sfblock = &scc->flow_blocks[src_block->vertex];
- sfedge = 0;
- if (src_block->left == block) {
- sfedge = &sfblock->left;
- } else {
- sfedge = &sfblock->right;
+ for(sfedge = sfblock->out; sfedge; sfedge = sfedge->out_next) {
+ if (sfedge->dst == fblock) {
+ break;
+ }
+ }
+ if (!sfedge) {
+ internal_error(state, 0, "edge mismatch");
}
*ftail = sfedge;
ftail = &sfedge->in_next;
sfedge->in_next = 0;
}
}
- {
- struct triple_set *edge;
- struct ssa_edge **stail;
- struct lattice_node *lnode;
- lnode = &scc->lattice[ins->id];
- lnode->out = 0;
- stail = &lnode->out;
- for(edge = ins->use; edge; edge = edge->next) {
- struct ssa_edge *sedge;
- ssa_edge_index += 1;
- sedge = &scc->ssa_edges[ssa_edge_index];
- *stail = sedge;
- stail = &sedge->out_next;
- sedge->src = lnode;
- sedge->dst = &scc->lattice[edge->member->id];
- sedge->work_next = sedge->work_prev = sedge;
- sedge->out_next = 0;
- }
- }
ins = ins->next;
} while(ins != first);
/* Setup a dummy block 0 as a node above the start node */
@@ -14901,10 +15720,11 @@ static void initialize_scc_state(
struct flow_edge *fedge;
fblock = &scc->flow_blocks[0];
fblock->block = 0;
+ fblock->edges = xcmalloc(sizeof(*fblock->edges)*1, "flow_edges");
fblock->in = 0;
- fblock->out = &fblock->left;
+ fblock->out = fblock->edges;
dst = &scc->flow_blocks[state->first_block->vertex];
- fedge = &fblock->left;
+ fedge = fblock->edges;
fedge->src = fblock;
fedge->dst = dst;
fedge->work_next = fedge;
@@ -14919,16 +15739,25 @@ static void initialize_scc_state(
scc->ssa_work_list = 0;
scc_add_fedge(state, scc, fedge);
}
-#if DEBUG_SCC
- fprintf(stderr, "ins_index: %d ssa_edge_index: %d fblock_index: %d\n",
- ins_index, ssa_edge_index, fblock_index);
-#endif
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
+ fprintf(stderr, "ins_index: %d ssa_edge_index: %d fblock_index: %d\n",
+ ins_index, ssa_edge_index, fblock_index);
+ }
}
static void free_scc_state(
struct compile_state *state, struct scc_state *scc)
{
+ int i;
+ for(i = 0; i < state->last_vertex + 1; i++) {
+ struct flow_block *fblock;
+ fblock = &scc->flow_blocks[i];
+ if (fblock->edges) {
+ xfree(fblock->edges);
+ fblock->edges = 0;
+ }
+ }
xfree(scc->flow_blocks);
xfree(scc->ssa_edges);
xfree(scc->lattice);
@@ -14987,6 +15816,34 @@ static int lval_changed(struct compile_state *state,
}
+static void scc_debug_lnode(
+ struct compile_state *state, struct lattice_node *lnode, int changed)
+{
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
+ FILE *fp = stderr;
+ struct triple *val, **expr;
+ val = lnode->val? lnode->val : lnode->def;
+ fprintf(fp, "%p %s %3d %10s (",
+ lnode->def,
+ ((lnode->def->op == OP_PHI)? "phi: ": "expr:"),
+ lnode->def->id,
+ tops(lnode->def->op));
+ expr = triple_rhs(state, lnode->def, 0);
+ for(;expr;expr = triple_rhs(state, lnode->def, expr)) {
+ if (*expr) {
+ fprintf(fp, " %d", (*expr)->id);
+ }
+ }
+ if (val->op == OP_INTCONST) {
+ fprintf(fp, " <0x%08lx>", (unsigned long)(val->u.cval));
+ }
+ fprintf(fp, " ) -> %s %s\n",
+ ((!lnode->val)? "lo": is_const(lnode->val)? "const": "hi"),
+ changed? "changed" : ""
+ );
+ }
+}
+
static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
struct lattice_node *lnode)
{
@@ -15006,13 +15863,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 (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
+ fprintf(stderr, "Examining edge: %d vertex: %d executable: %d\n",
+ index,
+ fedge->dst->block->vertex,
+ fedge->executable
+ );
+ }
if (!fedge->executable) {
continue;
}
@@ -15042,14 +15899,8 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
}
}
changed = lval_changed(state, old, lnode);
-#if DEBUG_SCC
- fprintf(stderr, "%p phi: %d -> %s %s\n",
- lnode->def,
- lnode->def->id,
- ((!lnode->val)? "lo": is_const(lnode->val)? "const": "hi"),
- changed? "changed" : ""
- );
-#endif
+ scc_debug_lnode(state, lnode, changed);
+
/* If the lattice value has changed update the work lists. */
if (changed) {
struct ssa_edge *sedge;
@@ -15090,7 +15941,7 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
*vexpr = (tmp->val)? tmp->val : tmp->def;
}
}
- if (scratch->op == OP_BRANCH) {
+ if (triple_is_branch(state, scratch)) {
scratch->next = lnode->def->next;
}
/* Recompute the value */
@@ -15105,7 +15956,7 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
}
if ((scratch->prev != scratch) ||
((scratch->next != scratch) &&
- ((lnode->def->op != OP_BRANCH) ||
+ (!triple_is_branch(state, lnode->def) ||
(scratch->next != lnode->def->next)))) {
internal_error(state, lnode->def, "scratch in list?");
}
@@ -15157,6 +16008,11 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
}
lnode->val = 0;
}
+ /* Report what has just happened */
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
+ display_triple_changes(stderr, scratch, lnode->def);
+ }
+
/* See if we need to free the scratch value */
if (lnode->val != scratch) {
xfree(scratch);
@@ -15168,10 +16024,11 @@ static void scc_visit_branch(struct compile_state *state, struct scc_state *scc,
struct lattice_node *lnode)
{
struct lattice_node *cond;
-#if DEBUG_SCC
- {
+ struct flow_edge *left, *right;
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
struct flow_edge *fedge;
- fprintf(stderr, "branch: %d (",
+ fprintf(stderr, "%s: %d (",
+ tops(lnode->def->op),
lnode->def->id);
for(fedge = lnode->fblock->out; fedge; fedge = fedge->out_next) {
@@ -15184,29 +16041,43 @@ static void scc_visit_branch(struct compile_state *state, struct scc_state *scc,
}
fprintf(stderr, "\n");
}
-#endif
- if (lnode->def->op != OP_BRANCH) {
+ if (!triple_is_branch(state, lnode->def)) {
internal_error(state, lnode->def, "not branch");
}
/* This only applies to conditional branches */
- if (TRIPLE_RHS(lnode->def->sizes) == 0) {
+ if (!triple_is_cond_branch(state, lnode->def)) {
return;
}
cond = triple_to_lattice(state, scc, RHS(lnode->def,0));
+ for(left = cond->fblock->out; left; left = left->out_next) {
+ if (left->dst->block->first == lnode->def->next) {
+ break;
+ }
+ }
+ if (!left) {
+ internal_error(state, lnode->def, "Cannot find left branch edge");
+ }
+ for(right = cond->fblock->out; right; right = right->out_next) {
+ if (right->dst->block->first == TARG(lnode->def, 0)) {
+ break;
+ }
+ }
+ if (!right) {
+ internal_error(state, lnode->def, "Cannot find right branch edge");
+ }
if (cond->val && !is_const(cond->val)) {
#warning "FIXME do I need to do something here?"
warning(state, cond->def, "condition not constant?");
return;
}
if (cond->val == 0) {
- scc_add_fedge(state, scc, cond->fblock->out);
- scc_add_fedge(state, scc, cond->fblock->out->out_next);
+ scc_add_fedge(state, scc, left);
+ scc_add_fedge(state, scc, right);
}
else if (cond->val->u.cval) {
- scc_add_fedge(state, scc, cond->fblock->out->out_next);
-
+ scc_add_fedge(state, scc, right);
} else {
- scc_add_fedge(state, scc, cond->fblock->out);
+ scc_add_fedge(state, scc, left);
}
}
@@ -15217,24 +16088,10 @@ static void scc_visit_expr(struct compile_state *state, struct scc_state *scc,
int changed;
changed = compute_lnode_val(state, scc, lnode);
-#if DEBUG_SCC
- {
- struct triple **expr;
- fprintf(stderr, "expr: %3d %10s (",
- lnode->def->id, tops(lnode->def->op));
- expr = triple_rhs(state, lnode->def, 0);
- for(;expr;expr = triple_rhs(state, lnode->def, expr)) {
- if (*expr) {
- fprintf(stderr, " %d", (*expr)->id);
- }
- }
- fprintf(stderr, " ) -> %s\n",
- (!lnode->val)? "lo": is_const(lnode->val)? "const": "hi");
- }
-#endif
- if (lnode->def->op == OP_BRANCH) {
- scc_visit_branch(state, scc, lnode);
+ scc_debug_lnode(state, lnode, changed);
+ if (triple_is_branch(state, lnode->def)) {
+ scc_visit_branch(state, scc, lnode);
}
else if (changed) {
struct ssa_edge *sedge;
@@ -15253,28 +16110,30 @@ static void scc_writeback_values(
do {
struct lattice_node *lnode;
lnode = triple_to_lattice(state, scc, ins);
-#if DEBUG_SCC
- 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));
+
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
+ 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)) {
@@ -15309,6 +16168,9 @@ static void scc_writeback_values(
static void scc_transform(struct compile_state *state)
{
struct scc_state scc;
+ if (!(state->compiler->flags & COMPILER_SCC_TRANSFORM)) {
+ return;
+ }
initialize_scc_state(state, &scc);
@@ -15340,11 +16202,12 @@ static void scc_transform(struct compile_state *state)
reps++;
}
}
-#if DEBUG_SCC
- fprintf(stderr, "vertex: %d reps: %d\n",
- block->vertex, reps);
-#endif
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
+ fprintf(stderr, "vertex: %d reps: %d\n",
+ block->vertex, reps);
+ }
+
done = 0;
for(ptr = block->first; !done; ptr = ptr->next) {
struct lattice_node *lnode;
@@ -15357,8 +16220,12 @@ static void scc_transform(struct compile_state *state)
scc_visit_expr(state, &scc, lnode);
}
}
- if (fblock->out && !fblock->out->out_next) {
- scc_add_fedge(state, &scc, fblock->out);
+ /* Add unconditional branch edges */
+ if (!triple_is_cond_branch(state, fblock->block->last)) {
+ struct flow_edge *out;
+ for(out = fblock->out; out; out = out->out_next) {
+ scc_add_fedge(state, &scc, out);
+ }
}
}
while((sedge = scc_next_sedge(state, &scc))) {
@@ -15366,12 +16233,14 @@ static void scc_transform(struct compile_state *state)
struct flow_block *fblock;
lnode = sedge->dst;
fblock = lnode->fblock;
-#if DEBUG_SCC
- fprintf(stderr, "sedge: %5d (%5d -> %5d)\n",
- sedge - scc.ssa_edges,
- sedge->src->def->id,
- sedge->dst->def->id);
-#endif
+
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
+ fprintf(stderr, "sedge: %5d (%5d -> %5d)\n",
+ sedge - scc.ssa_edges,
+ sedge->src->def->id,
+ sedge->dst->def->id);
+ }
+
if (lnode->def->op == OP_PHI) {
scc_visit_phi(state, &scc, lnode);
}
@@ -15390,6 +16259,9 @@ static void scc_transform(struct compile_state *state)
scc_writeback_values(state, &scc);
free_scc_state(state, &scc);
+ rebuild_ssa_form(state);
+
+ print_blocks(state, __func__, stdout);
}
@@ -15401,6 +16273,8 @@ static void transform_to_arch_instructions(struct compile_state *state)
do {
ins = transform_to_arch_instruction(state, ins);
} while(ins != first);
+
+ print_blocks(state, __func__, stdout);
}
#if DEBUG_CONSISTENCY
@@ -15463,6 +16337,20 @@ static void verify_blocks_present(struct compile_state *state)
}
+
+static int edge_present(struct compile_state *state, struct block *block, struct triple *edge)
+{
+ struct block_set *bedge;
+ struct block *targ;
+ targ = block_of_triple(state, edge);
+ for(bedge = block->edges; bedge; bedge = bedge->next) {
+ if (bedge->member == targ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
static void verify_blocks(struct compile_state *state)
{
struct triple *ins;
@@ -15475,7 +16363,7 @@ static void verify_blocks(struct compile_state *state)
blocks = 0;
do {
int users;
- struct block_set *user;
+ struct block_set *user, *edge;
blocks++;
for(ins = block->first; ins != block->last->next; ins = ins->next) {
if (triple_stores_block(state, ins) && (ins->u.block != block)) {
@@ -15493,49 +16381,42 @@ static void verify_blocks(struct compile_state *state)
(user->member == state->first_block)) {
continue;
}
- if ((user->member->left != block) &&
- (user->member->right != block)) {
+ for(edge = user->member->edges; edge; edge = edge->next) {
+ if (edge->member == block) {
+ break;
+ }
+ }
+ if (!edge) {
internal_error(state, user->member->first,
"user does not use block");
}
}
- if (triple_is_branch(state, block->last) &&
- (block->right != block_of_triple(state, TARG(block->last, 0))))
- {
- internal_error(state, block->last, "block->right != TARG(0)");
+ if (triple_is_branch(state, block->last)) {
+ struct triple **expr;
+ expr = triple_targ(state, block->last, 0);
+ for(;expr; expr = triple_targ(state, block->last, expr)) {
+ if (*expr && !edge_present(state, block, *expr)) {
+ internal_error(state, block->last, "no edge to targ");
+ }
+ }
}
if (!triple_is_uncond_branch(state, block->last) &&
(block != state->last_block) &&
- (block->left != block_of_triple(state, block->last->next)))
- {
- internal_error(state, block->last, "block->left != block->last->next");
+ !edge_present(state, block, block->last->next)) {
+ internal_error(state, block->last, "no edge to block->last->next");
}
- if (block->left) {
- for(user = block->left->use; user; user = user->next) {
+ for(edge = block->edges; edge; edge = edge->next) {
+ for(user = edge->member->use; user; user = user->next) {
if (user->member == block) {
break;
}
}
if (!user || user->member != block) {
internal_error(state, block->first,
- "block does not use left");
+ "block does not use edge");
}
- 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) {
- if (user->member == block) {
- break;
- }
- }
- if (!user || user->member != block) {
- internal_error(state, block->first,
- "block does not use right");
- }
- if (!block->right->first) {
- internal_error(state, block->first, "right block is empty");
+ if (!edge->member->first) {
+ internal_error(state, block->first, "edge block is empty");
}
}
if (block->users != users) {
@@ -15543,13 +16424,6 @@ static void verify_blocks(struct compile_state *state)
"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");
@@ -15582,7 +16456,7 @@ static void verify_domination(struct compile_state *state)
struct triple *use_point;
int i, zrhs;
use_point = 0;
- zrhs = TRIPLE_RHS(ins->sizes);
+ zrhs = TRIPLE_RHS(set->member->sizes);
slot = &RHS(set->member, 0);
/* See if the use is on the right hand side */
for(i = 0; i < zrhs; i++) {
@@ -15608,8 +16482,6 @@ static void verify_domination(struct compile_state *state)
}
if (use_point &&
!tdominates(state, ins, use_point)) {
- internal_warning(state, ins,
- "ins does not dominate rhs use");
internal_error(state, use_point,
"non dominated rhs use point?");
}
@@ -15697,14 +16569,13 @@ static void verify_consistency(struct compile_state *state) {}
static void optimize(struct compile_state *state)
{
- if (state->debug & DEBUG_TRIPLES) {
- print_triples(state);
- }
+ /* Dump what the instruction graph intially looks like */
+ print_triples(state);
+
/* Replace structures with simpler data types */
flatten_structures(state);
- if (state->debug & DEBUG_TRIPLES) {
- print_triples(state);
- }
+ print_triples(state);
+
verify_consistency(state);
/* Analize the intermediate code */
analyze_basic_blocks(state);
@@ -15719,32 +16590,17 @@ static void optimize(struct compile_state *state)
* phi functions early and I kill them often.
*/
transform_to_ssa_form(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);
- rebuild_ssa_form(state);
- }
- if (state->debug & DEBUG_CODE_ELIMINATION) {
- fprintf(stdout, "After simplify_all\n");
- print_blocks(state, stdout);
- }
+ simplify_all(state);
verify_consistency(state);
/* Propogate constants throughout the code */
- if (state->optimize >= 2) {
- scc_transform(state);
- rebuild_ssa_form(state);
- }
+ scc_transform(state);
verify_consistency(state);
#warning "WISHLIST implement single use constants (least possible register pressure)"
#warning "WISHLIST implement induction variable elimination"
@@ -15753,44 +16609,21 @@ static void optimize(struct compile_state *state)
*/
transform_to_arch_instructions(state);
verify_consistency(state);
- if (state->debug & DEBUG_ARCH_CODE) {
- printf("After transform_to_arch_instructions\n");
- 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");
- print_blocks(state, stdout);
- print_control_flow(state);
- }
verify_consistency(state);
+
/* Color all of the variables to see if they will fit in registers */
insert_copies_to_phi(state);
- if (state->debug & DEBUG_INSERTED_COPIES) {
- printf("After insert_copies_to_phi\n");
- print_blocks(state, stdout);
- print_control_flow(state);
- }
verify_consistency(state);
+
insert_mandatory_copies(state);
- if (state->debug & DEBUG_INSERTED_COPIES) {
- printf("After insert_mandatory_copies\n");
- print_blocks(state, stdout);
- print_control_flow(state);
- }
verify_consistency(state);
+
allocate_registers(state);
verify_consistency(state);
- if (state->debug & DEBUG_INTERMEDIATE_CODE) {
- print_blocks(state, stdout);
- }
- if (state->debug & DEBUG_CONTROL_FLOW) {
- print_control_flow(state);
- }
+
/* Remove the optimization information.
* This is more to check for memory consistency than to free memory.
*/
@@ -16009,12 +16842,20 @@ static const struct {
[REGC_IMM8] = { REGC_IMM8_FIRST, REGC_IMM8_LAST },
};
-static int arch_encode_feature(const char *feature, unsigned long *features)
+static void init_arch_state(struct arch_state *arch)
{
- struct cpu {
- const char *name;
- int cpu;
- } cpus[] = {
+ memset(arch, 0, sizeof(*arch));
+ arch->features = 0;
+}
+
+static int arch_encode_flag(struct arch_state *arch, const char *flag)
+{
+ static const struct compiler_flag flags[] = {
+ { "mmx", X86_MMX_REGS },
+ { "sse", X86_XMM_REGS },
+ { 0, 0 },
+ };
+ static const struct compiler_flag cpus[] = {
{ "i386", 0 },
{ "p2", X86_MMX_REGS },
{ "p3", X86_MMX_REGS | X86_XMM_REGS },
@@ -16025,30 +16866,21 @@ static int arch_encode_feature(const char *feature, unsigned long *features)
{ "c3-2", X86_MMX_REGS | X86_XMM_REGS }, /* Nehemiah */
{ 0, 0 }
};
- struct cpu *ptr;
- 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;
- }
+ int result;
+ int act;
+
+ act = 1;
+ result = -1;
+ if (strncmp(flag, "no-", 3) == 0) {
+ flag += 3;
+ act = 0;
+ }
+ if (act && strncmp(flag, "cpu=", 4) == 0) {
+ flag += 4;
+ result = set_flag(cpus, &arch->features, 1, flag);
}
else {
- result = -1;
+ result = set_flag(flags, &arch->features, act, flag);
}
return result;
}
@@ -16259,10 +17091,10 @@ 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;
- if (state->features & X86_MMX_REGS) {
+ if (state->arch->features & X86_MMX_REGS) {
avail_mask |= REGCM_MMX;
}
- if (state->features & X86_XMM_REGS) {
+ if (state->arch->features & X86_XMM_REGS) {
avail_mask |= REGCM_XMM;
}
return avail_mask;
@@ -16638,27 +17470,28 @@ static int get_imm8(struct triple *ins, struct triple **expr)
#define TEMPLATE_TEST32 41
#define TEMPLATE_SET 42
#define TEMPLATE_JMP 43
-#define TEMPLATE_INB_DX 44
-#define TEMPLATE_INB_IMM 45
-#define TEMPLATE_INW_DX 46
-#define TEMPLATE_INW_IMM 47
-#define TEMPLATE_INL_DX 48
-#define TEMPLATE_INL_IMM 49
-#define TEMPLATE_OUTB_DX 50
-#define TEMPLATE_OUTB_IMM 51
-#define TEMPLATE_OUTW_DX 52
-#define TEMPLATE_OUTW_IMM 53
-#define TEMPLATE_OUTL_DX 54
-#define TEMPLATE_OUTL_IMM 55
-#define TEMPLATE_BSF 56
-#define TEMPLATE_RDMSR 57
-#define TEMPLATE_WRMSR 58
-#define TEMPLATE_UMUL8 59
-#define TEMPLATE_UMUL16 60
-#define TEMPLATE_UMUL32 61
-#define TEMPLATE_DIV8 62
-#define TEMPLATE_DIV16 63
-#define TEMPLATE_DIV32 64
+#define TEMPLATE_RET 44
+#define TEMPLATE_INB_DX 45
+#define TEMPLATE_INB_IMM 46
+#define TEMPLATE_INW_DX 47
+#define TEMPLATE_INW_IMM 48
+#define TEMPLATE_INL_DX 49
+#define TEMPLATE_INL_IMM 50
+#define TEMPLATE_OUTB_DX 51
+#define TEMPLATE_OUTB_IMM 52
+#define TEMPLATE_OUTW_DX 53
+#define TEMPLATE_OUTW_IMM 54
+#define TEMPLATE_OUTL_DX 55
+#define TEMPLATE_OUTL_IMM 56
+#define TEMPLATE_BSF 57
+#define TEMPLATE_RDMSR 58
+#define TEMPLATE_WRMSR 59
+#define TEMPLATE_UMUL8 60
+#define TEMPLATE_UMUL16 61
+#define TEMPLATE_UMUL32 62
+#define TEMPLATE_DIV8 63
+#define TEMPLATE_DIV16 64
+#define TEMPLATE_DIV32 65
#define LAST_TEMPLATE TEMPLATE_DIV32
#if LAST_TEMPLATE >= MAX_TEMPLATES
#error "MAX_TEMPLATES to low"
@@ -16948,6 +17781,9 @@ static struct ins_template templates[] = {
[TEMPLATE_JMP] = {
.rhs = { [0] = { REG_EFLAGS, REGCM_FLAGS } },
},
+ [TEMPLATE_RET] = {
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ },
[TEMPLATE_INB_DX] = {
.lhs = { [0] = { REG_AL, REGCM_GPR8_LO } },
.rhs = { [0] = { REG_DX, REGCM_GPR16 } },
@@ -17114,7 +17950,7 @@ static void fixup_branches(struct compile_state *state,
if (entry->member->op == OP_COPY) {
fixup_branches(state, cmp, entry->member, jmp_op);
}
- else if (entry->member->op == OP_BRANCH) {
+ else if (entry->member->op == OP_CBRANCH) {
struct triple *branch;
struct triple *left, *right;
left = right = 0;
@@ -17389,23 +18225,16 @@ static struct triple *transform_to_arch_instruction(
case OP_LOAD:
switch(ins->type->type & TYPE_MASK) {
case TYPE_CHAR: case TYPE_UCHAR:
- ins->template_id = TEMPLATE_LOAD8;
- break;
- case TYPE_SHORT:
- case TYPE_USHORT:
- ins->template_id = TEMPLATE_LOAD16;
- break;
- case TYPE_INT:
- case TYPE_UINT:
- case TYPE_LONG:
- case TYPE_ULONG:
+ case TYPE_SHORT: case TYPE_USHORT:
+ case TYPE_INT: case TYPE_UINT:
+ case TYPE_LONG: case TYPE_ULONG:
case TYPE_POINTER:
- ins->template_id = TEMPLATE_LOAD32;
break;
default:
internal_error(state, ins, "unknown type in load");
break;
}
+ ins->template_id = TEMPLATE_LOAD32;
break;
case OP_ADD:
case OP_SUB:
@@ -17490,15 +18319,18 @@ static struct triple *transform_to_arch_instruction(
bool_cmp(state, ins, OP_TEST, OP_JMP_EQ, OP_SET_EQ);
break;
case OP_BRANCH:
- if (TRIPLE_RHS(ins->sizes) > 0) {
- 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_CBRANCH:
+ fixup_branch(state, ins, OP_JMP_NOTEQ, OP_TEST,
+ RHS(ins, 0)->type, RHS(ins, 0), 0);
+ break;
+ case OP_CALL:
+ ins->template_id = TEMPLATE_NOP;
+ break;
+ case OP_RET:
+ ins->template_id = TEMPLATE_RET;
break;
case OP_INB:
case OP_INW:
@@ -17677,14 +18509,16 @@ static void print_const_val(
(long)(ins->u.cval));
break;
case OP_ADDRCONST:
- if (MISC(ins, 0)->op != OP_SDECL) {
+ if ((MISC(ins, 0)->op != OP_SDECL) &&
+ (MISC(ins, 0)->op != OP_LABEL))
+ {
internal_error(state, ins, "bad base for addrconst");
}
if (MISC(ins, 0)->u.cval <= 0) {
internal_error(state, ins, "unlabeled constant");
}
fprintf(fp, " $L%s%lu+%lu ",
- state->label_prefix,
+ state->compiler->label_prefix,
(unsigned long)(MISC(ins, 0)->u.cval),
(unsigned long)(ins->u.cval));
break;
@@ -17722,14 +18556,15 @@ static void print_const(struct compile_state *state,
}
break;
case OP_ADDRCONST:
- if (MISC(ins, 0)->op != OP_SDECL) {
+ if ((MISC(ins, 0)->op != OP_SDECL) &&
+ (MISC(ins, 0)->op != OP_LABEL)) {
internal_error(state, ins, "bad base for addrconst");
}
if (MISC(ins, 0)->u.cval <= 0) {
internal_error(state, ins, "unlabeled constant");
}
fprintf(fp, ".int L%s%lu+%lu\n",
- state->label_prefix,
+ state->compiler->label_prefix,
(unsigned long)(MISC(ins, 0)->u.cval),
(unsigned long)(ins->u.cval));
break;
@@ -17761,7 +18596,7 @@ static long get_const_pool_ref(
ref = next_label(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, ref);
+ fprintf(fp, "L%s%lu:\n", state->compiler->label_prefix, ref);
print_const(state, ins, fp);
fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
return ref;
@@ -18167,8 +19002,8 @@ static void print_op_move(struct compile_state *state,
else if (dst_regcm & (REGCM_XMM | REGCM_MMX)) {
long ref;
ref = get_const_pool_ref(state, src, fp);
- fprintf(fp, "\tmovq L%s%lu, %s\n",
- state->label_prefix, ref,
+ fprintf(fp, "\tmovd L%s%lu, %s\n",
+ state->compiler->label_prefix, ref,
reg(state, dst, (REGCM_XMM | REGCM_MMX)));
}
else {
@@ -18181,14 +19016,31 @@ static void print_op_load(struct compile_state *state,
struct triple *ins, FILE *fp)
{
struct triple *dst, *src;
+ const char *op;
dst = ins;
src = RHS(ins, 0);
if (is_const(src) || is_const(dst)) {
internal_error(state, ins, "unknown load operation");
}
- fprintf(fp, "\tmov (%s), %s\n",
+ switch(ins->type->type & TYPE_MASK) {
+ case TYPE_CHAR: op = "movsbl"; break;
+ case TYPE_UCHAR: op = "movzbl"; break;
+ case TYPE_SHORT: op = "movswl"; break;
+ case TYPE_USHORT: op = "movzwl"; break;
+ case TYPE_INT: case TYPE_UINT:
+ case TYPE_LONG: case TYPE_ULONG:
+ case TYPE_POINTER:
+ op = "movl";
+ break;
+ default:
+ internal_error(state, ins, "unknown type in load");
+ op = "<invalid opcode>";
+ break;
+ }
+ fprintf(fp, "\t%s (%s), %s\n",
+ op,
reg(state, src, REGCM_GPR32),
- reg(state, dst, REGCM_GPR8_LO | REGCM_GPR16 | REGCM_GPR32));
+ reg(state, dst, REGCM_GPR32));
}
@@ -18283,7 +19135,7 @@ static void print_op_branch(struct compile_state *state,
struct triple *branch, FILE *fp)
{
const char *bop = "j";
- if (branch->op == OP_JMP) {
+ if ((branch->op == OP_JMP) || (branch->op == OP_CALL)) {
if (TRIPLE_RHS(branch->sizes) != 0) {
internal_error(state, branch, "jmp with condition?");
}
@@ -18325,10 +19177,17 @@ static void print_op_branch(struct compile_state *state,
}
fprintf(fp, "\t%s L%s%lu\n",
bop,
- state->label_prefix,
+ state->compiler->label_prefix,
(unsigned long)(TARG(branch, 0)->u.cval));
}
+static void print_op_ret(struct compile_state *state,
+ struct triple *branch, FILE *fp)
+{
+ fprintf(fp, "\tjmp *%s\n",
+ reg(state, RHS(branch, 0), REGCM_GPR32));
+}
+
static void print_op_set(struct compile_state *state,
struct triple *set, FILE *fp)
{
@@ -18393,7 +19252,7 @@ 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, (unsigned long)(ins->u.cval));
+ state->compiler->label_prefix, (unsigned long)(ins->u.cval));
print_const(state, MISC(ins, 0), fp);
fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
@@ -18450,8 +19309,12 @@ static void print_instruction(struct compile_state *state,
case OP_JMP_SMORE: case OP_JMP_UMORE:
case OP_JMP_SLESSEQ: case OP_JMP_ULESSEQ:
case OP_JMP_SMOREEQ: case OP_JMP_UMOREEQ:
+ case OP_CALL:
print_op_branch(state, ins, fp);
break;
+ case OP_RET:
+ print_op_ret(state, ins, fp);
+ break;
case OP_SET_EQ: case OP_SET_NOTEQ:
case OP_SET_SLESS: case OP_SET_ULESS:
case OP_SET_SMORE: case OP_SET_UMORE:
@@ -18493,7 +19356,7 @@ static void print_instruction(struct compile_state *state,
return;
}
fprintf(fp, "L%s%lu:\n",
- state->label_prefix, (unsigned long)(ins->u.cval));
+ state->compiler->label_prefix, (unsigned long)(ins->u.cval));
break;
/* Ignore OP_PIECE */
case OP_PIECE:
@@ -18595,40 +19458,26 @@ 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,
- unsigned long features, int debug, int opt, const char *label_prefix)
+static void compile(const char *filename,
+ struct compiler_state *compiler, struct arch_state *arch)
{
int i;
struct compile_state state;
struct triple *ptr;
memset(&state, 0, sizeof(state));
+ state.compiler = compiler;
+ state.arch = arch;
state.file = 0;
for(i = 0; i < sizeof(state.token)/sizeof(state.token[0]); i++) {
memset(&state.token[i], 0, sizeof(state.token[i]));
state.token[i].tok = -1;
}
- /* Remember the debug settings */
- state.features = features;
- state.debug = debug;
- state.optimize = opt;
/* Remember the output filename */
- state.ofilename = ofilename;
- state.output = fopen(state.ofilename, "w");
+ state.output = fopen(state.compiler->ofilename, "w");
if (!state.output) {
error(&state, 0, "Cannot open output file %s\n",
- ofilename);
+ state.compiler->ofilename);
}
- /* Remember the label prefix */
- state.label_prefix = label_prefix;
/* Prep the preprocessor */
state.if_depth = 0;
state.if_value = 0;
@@ -18642,6 +19491,7 @@ static void compile(const char *filename, const char *ofilename,
state.i_continue = lookup(&state, "continue", 8);
state.i_break = lookup(&state, "break", 5);
state.i_default = lookup(&state, "default", 7);
+ state.i_return = lookup(&state, "return", 6);
/* Allocate beginning bounding labels for the function list */
state.first = label(&state);
@@ -18652,6 +19502,12 @@ static void compile(const char *filename, const char *ofilename,
use_triple(ptr, ptr);
flatten(&state, state.first, ptr);
+ /* Allocate a label for the pool of global variables */
+ state.global_pool = label(&state);
+ state.global_pool->id |= TRIPLE_FLAG_VOLATILE;
+ flatten(&state, state.first, state.global_pool);
+
+
/* Enter the globl definition scope */
start_scope(&state);
register_builtins(&state);
@@ -18660,11 +19516,12 @@ static void compile(const char *filename, const char *ofilename,
print_tokens(&state);
#endif
decls(&state);
+
/* Exit the global definition scope */
end_scope(&state);
- /* Call the main function */
- call_main(&state);
+ /* Join all of the functions into one giant function */
+ join_functions(&state);
/* Now that basic compilation has happened
* optimize the intermediate code
@@ -18672,7 +19529,7 @@ static void compile(const char *filename, const char *ofilename,
optimize(&state);
generate_code(&state);
- if (state.debug) {
+ if (state.compiler->debug) {
fprintf(stderr, "done\n");
}
}
@@ -18704,62 +19561,58 @@ static void arg_error(char *fmt, ...)
int main(int argc, char **argv)
{
const char *filename;
- const char *ofilename;
- const char *label_prefix;
- unsigned long features;
- int last_argc;
- int debug;
- int optimize;
- features = 0;
- label_prefix = "";
- ofilename = "auto.inc";
- optimize = 0;
- debug = 0;
- last_argc = -1;
- while((argc > 1) && (argc != last_argc)) {
- last_argc = argc;
- if (strncmp(argv[1], "--debug=", 8) == 0) {
- debug = atoi(argv[1] + 8);
- argv++;
- argc--;
- }
- else if (strncmp(argv[1], "--label-prefix=", 15) == 0) {
- label_prefix= argv[1] + 15;
- argv++;
- argc--;
- }
- else if ((strcmp(argv[1],"-O") == 0) ||
- (strcmp(argv[1], "-O1") == 0)) {
- optimize = 1;
- argv++;
- argc--;
- }
- else if (strcmp(argv[1],"-O2") == 0) {
- optimize = 2;
- argv++;
- argc--;
- }
- else if ((strcmp(argv[1], "-o") == 0) && (argc > 2)) {
- ofilename = argv[2];
+ struct compiler_state compiler;
+ struct arch_state arch;
+ int all_opts;
+ init_compiler_state(&compiler);
+ init_arch_state(&arch);
+ filename = 0;
+ all_opts = 0;
+ while(argc > 1) {
+ if (!all_opts && (strcmp(argv[1], "-o") == 0) && (argc > 2)) {
+ compiler.ofilename = argv[2];
argv += 2;
argc -= 2;
}
- else if (strncmp(argv[1], "-m", 2) == 0) {
+ else if (!all_opts && argv[1][0] == '-') {
int result;
- result = arch_encode_feature(argv[1] + 2, &features);
+ result = -1;
+ if (strcmp(argv[1], "--") == 0) {
+ result = 0;
+ all_opts = 1;
+ }
+ else if (strncmp(argv[1],"-O", 2) == 0) {
+ result = compiler_encode_flag(&compiler, argv[1]);
+ }
+ else if (strncmp(argv[1], "--label-prefix=", 15) == 0) {
+ result = compiler_encode_flag(&compiler, argv[1]+2);
+ }
+ else if (strncmp(argv[1], "-f", 2) == 0) {
+ result = compiler_encode_flag(&compiler, argv[1]+2);
+ }
+ else if (strncmp(argv[1], "-m", 2) == 0) {
+ result = arch_encode_flag(&arch, argv[1]+2);
+ }
if (result < 0) {
- arg_error("Invalid feature specified: %s\n",
- argv[1] + 2);
+ arg_error("Invalid option specified: %s\n",
+ argv[1]);
}
argv++;
argc--;
}
+ else {
+ if (filename) {
+ arg_error("Only one filename may be specified\n");
+ }
+ filename = argv[1];
+ argv++;
+ argc--;
+ }
}
- if (argc != 2) {
- arg_error("Wrong argument count %d\n", argc);
+ if (!filename) {
+ arg_error("No filename specified\n");
}
- filename = argv[1];
- compile(filename, ofilename, features, debug, optimize, label_prefix);
+ compile(filename, &compiler, &arch);
return 0;
}
diff --git a/util/romcc/tests/linux_test8.c b/util/romcc/tests/linux_test8.c
new file mode 100644
index 0000000000..adee3c108d
--- /dev/null
+++ b/util/romcc/tests/linux_test8.c
@@ -0,0 +1,39 @@
+#include "linux_syscall.h"
+#include "linux_console.h"
+
+struct mem_param {
+ unsigned char cycle_time;
+ unsigned char divisor;
+ unsigned char tRC;
+ unsigned char tRFC;
+ unsigned dch_memclk;
+ unsigned short dch_tref4k, dch_tref8k;
+ unsigned char dtl_twr;
+ char name[9];
+};
+
+static void test(void)
+{
+ static const struct mem_param param0 = {
+ .name = "166Mhz\r\n",
+ .cycle_time = 0x60,
+ .divisor = (6<<1),
+ .tRC = 0x3C,
+ .tRFC = 0x48,
+ .dch_memclk = 5 << 20,
+ .dch_tref4k = 0x02,
+ .dch_tref8k = 0x0A,
+ .dtl_twr = 3,
+ };
+ int value;
+ unsigned clocks;
+ const struct mem_param *param;
+ param = &param0;
+ value = 0x48;
+ /* This used to generate 32bit loads instead of 8 bit loads */
+ clocks = (value + (param->divisor << 1) - 1)/(param->divisor << 1);
+ print_debug("clocks: ");
+ print_debug_hex32(clocks);
+ print_debug("\r\n");
+ _exit(0);
+}
diff --git a/util/romcc/tests/simple_test69.c b/util/romcc/tests/simple_test69.c
new file mode 100644
index 0000000000..c01338fc62
--- /dev/null
+++ b/util/romcc/tests/simple_test69.c
@@ -0,0 +1,22 @@
+static void outb(unsigned char value, unsigned short port)
+{
+ __builtin_outb(value, port);
+}
+
+static void pnp_write_config(void)
+{
+ unsigned char port;
+ unsigned char value;
+ unsigned char reg;
+ port = 0x2e;
+ value = 0x03;
+ reg = 0x07;
+ outb(reg, port);
+ outb(value, port +1);
+ outb(value -1, port +2);
+}
+
+static void main(void)
+{
+ pnp_write_config();
+}
diff --git a/util/romcc/tests/simple_test70.c b/util/romcc/tests/simple_test70.c
new file mode 100644
index 0000000000..ae7b2b172e
--- /dev/null
+++ b/util/romcc/tests/simple_test70.c
@@ -0,0 +1,22 @@
+static void main(void)
+{
+ int i;
+ int dest;
+
+ goto start;
+ foo:
+ __builtin_outl(dest, 0x5678);
+ if (dest == 2) goto middle;
+ goto head;
+
+start:
+ dest = 1;
+ goto foo;
+ head:
+ for(i = 0; i < 10; i++) {
+ dest = 2;
+ goto foo;
+ middle:
+ __builtin_outl(i, 0x1234);
+ }
+}
diff --git a/util/romcc/tests/simple_test71.c b/util/romcc/tests/simple_test71.c
new file mode 100644
index 0000000000..35956c5ea8
--- /dev/null
+++ b/util/romcc/tests/simple_test71.c
@@ -0,0 +1,25 @@
+static void foo(void)
+{
+ __builtin_outl(22, 0x5678);
+}
+static void main(void)
+{
+ int i;
+
+#if 1
+ foo();
+#endif
+#if 1
+ foo();
+#endif
+ for(i = 0; i < 10; i++) {
+#if 1
+ foo();
+#endif
+#if 0
+ foo();
+#endif
+ __builtin_outl(i, 0x1234);
+ }
+
+}
diff --git a/util/romcc/tests/simple_test72.c b/util/romcc/tests/simple_test72.c
new file mode 100644
index 0000000000..2011fea7fa
--- /dev/null
+++ b/util/romcc/tests/simple_test72.c
@@ -0,0 +1,164 @@
+static const char *addr_of_char(unsigned char ch)
+{
+ static const char byte[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ };
+ return byte + ch;
+}
+
+
+static void print_debug_char(int c)
+{
+ asm volatile(
+ "int $0x80"
+ :
+ : "a" (4), "b" (1), "c" (addr_of_char(c)), "d" (1)
+ );
+
+}
+static void print_debug_nibble(unsigned nibble)
+{
+ unsigned char digit;
+ digit = nibble + '0';
+ if (digit > '9') {
+ digit += 39;
+ }
+ print_debug_char(digit);
+}
+static void print_debug_hex8(unsigned char value)
+{
+ print_debug_nibble((value >> 4U) & 0x0fU);
+ print_debug_nibble(value & 0x0fU);
+}
+
+static int smbus_read_byte(unsigned device, unsigned address)
+{
+ static const unsigned char dimm[] = {
+0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
+0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
+0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+
+0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
+0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
+0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+ return dimm[(device << 8) + address];
+}
+
+static void spd_set_memclk(void)
+{
+ /* Compute the minimum cycle time for these dimms */
+ unsigned min_cycle_time, min_latency;
+ unsigned device;
+ unsigned value;
+
+ value = 0x50;
+ min_cycle_time= 0x75;
+ min_latency = 2;
+ device = 0;
+
+
+ /* Compute the least latency with the fastest clock supported
+ * by both the memory controller and the dimms.
+ */
+ int new_cycle_time, new_latency;
+ int index;
+ int latencies;
+ int latency;
+
+ /* First find the supported CAS latencies
+ * Byte 18 for DDR SDRAM is interpreted:
+ * bit 0 == CAS Latency = 1.0
+ * bit 1 == CAS Latency = 1.5
+ * bit 2 == CAS Latency = 2.0
+ * bit 3 == CAS Latency = 2.5
+ * bit 4 == CAS Latency = 3.0
+ * bit 5 == CAS Latency = 3.5
+ * bit 6 == TBD
+ * bit 7 == TBD
+ */
+ new_cycle_time = 0xa0;
+ new_latency = 5;
+
+ latencies = smbus_read_byte(device, 18);
+
+ /* Compute the lowest cas latency supported */
+ latency = __builtin_bsr(latencies) -2;
+
+ /* Loop through and find a fast clock with a low latency */
+ for(index = 0; index < 1; index++, latency++)
+ {
+ int value;
+
+ if ((latency < 2) || (latency > 4) ||
+ (!(latencies & (1 << latency)))) {
+ continue;
+ }
+ value = smbus_read_byte(device, index);
+
+ /* Only increase the latency if we decreas the clock */
+ if ((value >= min_cycle_time) && (value < new_cycle_time)) {
+ new_cycle_time = value;
+ new_latency = latency;
+ print_debug_hex8(device);
+ }
+ }
+}
+
diff --git a/util/romcc/tests/simple_test73.c b/util/romcc/tests/simple_test73.c
new file mode 100644
index 0000000000..f9e00cd4f8
--- /dev/null
+++ b/util/romcc/tests/simple_test73.c
@@ -0,0 +1,174 @@
+static const char *addr_of_char(unsigned char ch)
+{
+ static const char byte[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ };
+ return byte + ch;
+}
+
+static void console_tx_byte(unsigned char ch)
+{
+ asm volatile(
+ "int $0x80"
+ :
+ : "a" (4), "b" (1), "c" (addr_of_char(ch)), "d" (1));
+}
+
+static void console_tx_string(const char *str)
+{
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ console_tx_byte(ch);
+ }
+}
+
+
+
+static int smbus_read_byte(unsigned device, unsigned address)
+{
+ static const unsigned char dimm[] = {
+0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
+0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
+0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+
+0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
+0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
+0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+ return dimm[(device << 8) + address];
+}
+
+#define SMBUS_MEM_DEVICE_START 0x00
+#define SMBUS_MEM_DEVICE_END 0x00
+#define SMBUS_MEM_DEVICE_INC 1
+
+
+static void spd_set_memclk(void)
+{
+ /* Compute the minimum cycle time for these dimms */
+ unsigned min_cycle_time, min_latency;
+ unsigned device;
+ unsigned value;
+
+ value = 0x50;
+ min_cycle_time = 0x75;
+ min_latency = 2;
+ device = 0;
+
+ /* Compute the least latency with the fastest clock supported
+ * by both the memory controller and the dimms.
+ */
+ for(device = SMBUS_MEM_DEVICE_START;
+ device <= SMBUS_MEM_DEVICE_END;
+ device += SMBUS_MEM_DEVICE_INC)
+ {
+ int new_cycle_time, new_latency;
+ int index;
+ int latencies;
+ int latency;
+
+ /* First find the supported CAS latencies
+ * Byte 18 for DDR SDRAM is interpreted:
+ * bit 0 == CAS Latency = 1.0
+ * bit 1 == CAS Latency = 1.5
+ * bit 2 == CAS Latency = 2.0
+ * bit 3 == CAS Latency = 2.5
+ * bit 4 == CAS Latency = 3.0
+ * bit 5 == CAS Latency = 3.5
+ * bit 6 == TBD
+ * bit 7 == TBD
+ */
+ new_cycle_time = 0xa0;
+ new_latency = 5;
+
+ latencies = smbus_read_byte(device, 18);
+
+ /* Compute the lowest cas latency supported */
+ latency = __builtin_bsr(latencies) -2;
+
+ /* Loop through and find a fast clock with a low latency */
+ for(index = 0; index < 3; index++, latency++) {
+ int value;
+ if ((latency < 2) || (latency > 4) ||
+ (!(latencies & (1 << latency)))) {
+ continue;
+ }
+ value = smbus_read_byte(device, index);
+ if (value < 0) continue;
+
+ /* Only increase the latency if we decreas the clock */
+ if ((value >= min_cycle_time) && (value < new_cycle_time)) {
+ new_cycle_time = value;
+ new_latency = latency;
+ console_tx_byte(device);
+
+ }
+ }
+ console_tx_string("Transmitting this string causes problems\n");
+ /* Does min_latency need to be increased? */
+ if (new_cycle_time > min_cycle_time) {
+ min_cycle_time = new_cycle_time;
+ }
+ /* Does min_cycle_time need to be increased? */
+ if (new_latency > min_latency) {
+ min_latency = new_latency;
+ }
+ }
+}