summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorEric Biederman <ebiederm@xmission.com>2003-06-10 21:22:07 +0000
committerEric Biederman <ebiederm@xmission.com>2003-06-10 21:22:07 +0000
commit6aa31cc754744a83177ea922e71c6bdf02cad5df (patch)
tree00fc8a3cc81f367240eb5ac5a627841d1bb0a1a0 /util
parentdc18ef018d080f050de9e28be913f544d3009cb2 (diff)
- Update romcc to version 0.27 and add more tests.
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@865 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util')
-rw-r--r--util/romcc/Makefile25
-rw-r--r--util/romcc/romcc.c4688
-rw-r--r--util/romcc/tests/hello_world2.c127
-rw-r--r--util/romcc/tests/ldscript.ld20
-rw-r--r--util/romcc/tests/raminit_test.c17
-rw-r--r--util/romcc/tests/raminit_test2.c19
-rw-r--r--util/romcc/tests/raminit_test3.c1076
-rw-r--r--util/romcc/tests/simple_test21.c6
-rw-r--r--util/romcc/tests/simple_test22.c306
-rw-r--r--util/romcc/tests/simple_test23.c18
-rw-r--r--util/romcc/tests/simple_test24.c16
-rw-r--r--util/romcc/tests/simple_test25.c109
-rw-r--r--util/romcc/tests/simple_test26.c109
-rw-r--r--util/romcc/tests/simple_test27.c133
-rw-r--r--util/romcc/tests/simple_test28.c24
-rw-r--r--util/romcc/tests/simple_test29.c37
-rw-r--r--util/romcc/tests/simple_test30.c1087
-rw-r--r--util/romcc/tests/simple_test6.c2
18 files changed, 6763 insertions, 1056 deletions
diff --git a/util/romcc/Makefile b/util/romcc/Makefile
index eb84ceec29..ad209a5247 100644
--- a/util/romcc/Makefile
+++ b/util/romcc/Makefile
@@ -1,5 +1,5 @@
-VERSION:=0.23
-RELEASE_DATE:=08 May 2003
+VERSION:=0.27
+RELEASE_DATE:=10 June 2003
PACKAGE:=romcc
@@ -35,8 +35,19 @@ TESTS=\
simple_test18.c \
simple_test19.c \
simple_test20.c \
+ simple_test21.c \
+ simple_test22.c \
+ simple_test23.c \
+ simple_test24.c \
+ simple_test25.c \
+ simple_test26.c \
+ simple_test27.c \
+ simple_test28.c \
+ simple_test29.c \
+ simple_test30.c \
raminit_test.c \
- raminit_test2.c
+ raminit_test2.c \
+ raminit_test3.c
TEST_SRCS:=$(patsubst %, tests/%, $(TESTS))
TEST_ASM:=$(patsubst %.c, tests/%.S, $(TESTS))
@@ -44,13 +55,13 @@ TEST_OBJ:=$(patsubst %.c, tests/%.o, $(TESTS))
TEST_ELF:=$(patsubst %.c, tests/%.elf, $(TESTS))
$(TEST_ASM): %.S: %.c romcc
- export ALLOC_CHECK_=2; ./romcc -O $< > $@
+ export ALLOC_CHECK_=2; ./romcc -O -o $@ $< > $*.debug
$(TEST_OBJ): %.o: %.S
as $< -o $@
-$(TEST_ELF): %.elf: %.o
- ld -Ttext 0x1000 $< -o $@
+$(TEST_ELF): %.elf: %.o tests/ldscript.ld
+ ld -T tests/ldscript.ld $< -o $@
test: $(TEST_ELF)
@@ -61,5 +72,5 @@ echo:
echo "TEST_ELF=$(TEST_ELF)"
clean:
- rm -f romcc core $(TEST_ASM) $(TEST_OBJ) $(TEST_ELF)
+ rm -f romcc core $(TEST_ASM) $(TEST_OBJ) $(TEST_ELF) tests/*.debug tests/*.debug2
diff --git a/util/romcc/romcc.c b/util/romcc/romcc.c
index 386aa06b81..255b6d4995 100644
--- a/util/romcc/romcc.c
+++ b/util/romcc/romcc.c
@@ -15,11 +15,7 @@
#define DEBUG_ERROR_MESSAGES 0
#define DEBUG_COLOR_GRAPH 0
#define DEBUG_SCC 0
-#define X86_4_8BIT_GPRS 1
-
-#warning "FIXME static constant variables"
-#warning "FIXME enable pointers"
-#warning "FIXME enable string constants"
+#define DEBUG_CONSISTENCY 1
/* Control flow graph of a loop without goto.
*
@@ -306,7 +302,7 @@ struct token {
*/
#define OP_ADDRCONST 52
/* For OP_ADDRCONST ->type holds the type.
- * RHS(0) holds the reference to the static variable.
+ * MISC(0) holds the reference to the static variable.
* ->u.cval holds an offset from that value.
*/
@@ -327,9 +323,16 @@ struct token {
*/
#define OP_PIECE 63
/* OP_PIECE returns one piece of a instruction that returns a structure.
- * RHS(0) is the instruction
+ * MISC(0) is the instruction
* u.cval is the LHS piece of the instruction to return.
*/
+#define OP_ASM 64
+/* OP_ASM holds a sequence of assembly instructions, the result
+ * of a C asm directive.
+ * RHS(x) holds input value x to the assembly sequence.
+ * LHS(x) holds the output value x from the assembly sequence.
+ * u.blob holds the string of assembly instructions.
+ */
#define OP_DEREF 65
/* OP_DEREF generates an lvalue from a pointer.
@@ -415,7 +418,7 @@ struct token {
*/
#define OP_SDECL 85
-/* OP_VAR is a triple that establishes a variable of static
+/* OP_SDECL is a triple that establishes a variable of static
* storage duration.
* ->use is a list of statements that use the variable.
* MISC(0) holds the initializer expression.
@@ -483,6 +486,7 @@ struct op_info {
#define IMPURE 2
#define PURE_BITS(FLAGS) ((FLAGS) & 0x3)
#define DEF 4
+#define BLOCK 8 /* Triple stores the current block */
unsigned char lhs, rhs, misc, targ;
};
@@ -495,107 +499,108 @@ struct op_info {
.targ = (TARG), \
}
static const struct op_info table_ops[] = {
-[OP_SMUL ] = OP( 0, 2, 0, 0, PURE | DEF, "smul"),
-[OP_UMUL ] = OP( 0, 2, 0, 0, PURE | DEF, "umul"),
-[OP_SDIV ] = OP( 0, 2, 0, 0, PURE | DEF, "sdiv"),
-[OP_UDIV ] = OP( 0, 2, 0, 0, PURE | DEF, "udiv"),
-[OP_SMOD ] = OP( 0, 2, 0, 0, PURE | DEF, "smod"),
-[OP_UMOD ] = OP( 0, 2, 0, 0, PURE | DEF, "umod"),
-[OP_ADD ] = OP( 0, 2, 0, 0, PURE | DEF, "add"),
-[OP_SUB ] = OP( 0, 2, 0, 0, PURE | DEF, "sub"),
-[OP_SL ] = OP( 0, 2, 0, 0, PURE | DEF, "sl"),
-[OP_USR ] = OP( 0, 2, 0, 0, PURE | DEF, "usr"),
-[OP_SSR ] = OP( 0, 2, 0, 0, PURE | DEF, "ssr"),
-[OP_AND ] = OP( 0, 2, 0, 0, PURE | DEF, "and"),
-[OP_XOR ] = OP( 0, 2, 0, 0, PURE | DEF, "xor"),
-[OP_OR ] = OP( 0, 2, 0, 0, PURE | DEF, "or"),
-[OP_POS ] = OP( 0, 1, 0, 0, PURE | DEF, "pos"),
-[OP_NEG ] = OP( 0, 1, 0, 0, PURE | DEF, "neg"),
-[OP_INVERT ] = OP( 0, 1, 0, 0, PURE | DEF, "invert"),
-
-[OP_EQ ] = OP( 0, 2, 0, 0, PURE | DEF, "eq"),
-[OP_NOTEQ ] = OP( 0, 2, 0, 0, PURE | DEF, "noteq"),
-[OP_SLESS ] = OP( 0, 2, 0, 0, PURE | DEF, "sless"),
-[OP_ULESS ] = OP( 0, 2, 0, 0, PURE | DEF, "uless"),
-[OP_SMORE ] = OP( 0, 2, 0, 0, PURE | DEF, "smore"),
-[OP_UMORE ] = OP( 0, 2, 0, 0, PURE | DEF, "umore"),
-[OP_SLESSEQ ] = OP( 0, 2, 0, 0, PURE | DEF, "slesseq"),
-[OP_ULESSEQ ] = OP( 0, 2, 0, 0, PURE | DEF, "ulesseq"),
-[OP_SMOREEQ ] = OP( 0, 2, 0, 0, PURE | DEF, "smoreeq"),
-[OP_UMOREEQ ] = OP( 0, 2, 0, 0, PURE | DEF, "umoreeq"),
-[OP_LFALSE ] = OP( 0, 1, 0, 0, PURE | DEF, "lfalse"),
-[OP_LTRUE ] = OP( 0, 1, 0, 0, PURE | DEF, "ltrue"),
-
-[OP_LOAD ] = OP( 0, 1, 0, 0, IMPURE | DEF, "load"),
-[OP_STORE ] = OP( 1, 1, 0, 0, IMPURE, "store"),
-
-[OP_NOOP ] = OP( 0, 0, 0, 0, PURE, "noop"),
-
-[OP_INTCONST ] = OP( 0, 0, 0, 0, PURE, "intconst"),
+[OP_SMUL ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "smul"),
+[OP_UMUL ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "umul"),
+[OP_SDIV ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "sdiv"),
+[OP_UDIV ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "udiv"),
+[OP_SMOD ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "smod"),
+[OP_UMOD ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "umod"),
+[OP_ADD ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "add"),
+[OP_SUB ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "sub"),
+[OP_SL ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "sl"),
+[OP_USR ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "usr"),
+[OP_SSR ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "ssr"),
+[OP_AND ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "and"),
+[OP_XOR ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "xor"),
+[OP_OR ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "or"),
+[OP_POS ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK , "pos"),
+[OP_NEG ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK , "neg"),
+[OP_INVERT ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK , "invert"),
+
+[OP_EQ ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "eq"),
+[OP_NOTEQ ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "noteq"),
+[OP_SLESS ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "sless"),
+[OP_ULESS ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "uless"),
+[OP_SMORE ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "smore"),
+[OP_UMORE ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "umore"),
+[OP_SLESSEQ ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "slesseq"),
+[OP_ULESSEQ ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "ulesseq"),
+[OP_SMOREEQ ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "smoreeq"),
+[OP_UMOREEQ ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK , "umoreeq"),
+[OP_LFALSE ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK , "lfalse"),
+[OP_LTRUE ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK , "ltrue"),
+
+[OP_LOAD ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "load"),
+[OP_STORE ] = OP( 1, 1, 0, 0, IMPURE | BLOCK , "store"),
+
+[OP_NOOP ] = OP( 0, 0, 0, 0, PURE | BLOCK, "noop"),
+
+[OP_INTCONST ] = OP( 0, 0, 0, 0, PURE | DEF, "intconst"),
[OP_BLOBCONST ] = OP( 0, 0, 0, 0, PURE, "blobconst"),
-[OP_ADDRCONST ] = OP( 0, 1, 0, 0, PURE, "addrconst"),
-
-[OP_WRITE ] = OP( 1, 1, 0, 0, PURE, "write"),
-[OP_READ ] = OP( 0, 1, 0, 0, PURE | DEF, "read"),
-[OP_COPY ] = OP( 0, 1, 0, 0, PURE | DEF, "copy"),
-[OP_PIECE ] = OP( 0, 1, 0, 0, PURE | DEF, "piece"),
-[OP_DEREF ] = OP( 0, 1, 0, 0, 0 | DEF, "deref"),
-[OP_DOT ] = OP( 0, 1, 0, 0, 0 | DEF, "dot"),
-
-[OP_VAL ] = OP( 0, 1, 1, 0, 0 | DEF, "val"),
-[OP_LAND ] = OP( 0, 2, 0, 0, 0 | DEF, "land"),
-[OP_LOR ] = OP( 0, 2, 0, 0, 0 | DEF, "lor"),
-[OP_COND ] = OP( 0, 3, 0, 0, 0 | DEF, "cond"),
-[OP_COMMA ] = OP( 0, 2, 0, 0, 0 | DEF, "comma"),
+[OP_ADDRCONST ] = OP( 0, 0, 1, 0, PURE | DEF, "addrconst"),
+
+[OP_WRITE ] = OP( 1, 1, 0, 0, PURE | BLOCK, "write"),
+[OP_READ ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "read"),
+[OP_COPY ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "copy"),
+[OP_PIECE ] = OP( 0, 0, 1, 0, PURE | DEF, "piece"),
+[OP_ASM ] = OP(-1, -1, 0, 0, IMPURE, "asm"),
+[OP_DEREF ] = OP( 0, 1, 0, 0, 0 | DEF | BLOCK, "deref"),
+[OP_DOT ] = OP( 0, 1, 0, 0, 0 | DEF | BLOCK, "dot"),
+
+[OP_VAL ] = OP( 0, 1, 1, 0, 0 | DEF | BLOCK, "val"),
+[OP_LAND ] = OP( 0, 2, 0, 0, 0 | DEF | BLOCK, "land"),
+[OP_LOR ] = OP( 0, 2, 0, 0, 0 | DEF | BLOCK, "lor"),
+[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, "call"),
+[OP_CALL ] = OP(-1, -1, 1, 0, 0 | BLOCK, "call"),
/* The sizes of OP_CALL and OP_VAL_VEC depend upon context */
-[OP_VAL_VEC ] = OP( 0, -1, 0, 0, 0, "valvec"),
+[OP_VAL_VEC ] = OP( 0, -1, 0, 0, 0 | BLOCK, "valvec"),
[OP_LIST ] = OP( 0, 1, 1, 0, 0 | DEF, "list"),
/* The number of targets for OP_BRANCH depends on context */
-[OP_BRANCH ] = OP( 0, -1, 0, 1, PURE, "branch"),
-[OP_LABEL ] = OP( 0, 0, 0, 0, PURE, "label"),
-[OP_ADECL ] = OP( 0, 0, 0, 0, PURE, "adecl"),
-[OP_SDECL ] = OP( 0, 0, 1, 0, PURE, "sdecl"),
+[OP_BRANCH ] = OP( 0, -1, 0, 1, PURE | BLOCK, "branch"),
+[OP_LABEL ] = OP( 0, 0, 0, 0, PURE | BLOCK, "label"),
+[OP_ADECL ] = OP( 0, 0, 0, 0, PURE | BLOCK, "adecl"),
+[OP_SDECL ] = OP( 0, 0, 1, 0, PURE | BLOCK, "sdecl"),
/* The number of RHS elements of OP_PHI depend upon context */
-[OP_PHI ] = OP( 0, -1, 1, 0, PURE | DEF, "phi"),
-
-[OP_CMP ] = OP( 0, 2, 0, 0, PURE | DEF, "cmp"),
-[OP_TEST ] = OP( 0, 1, 0, 0, PURE | DEF, "test"),
-[OP_SET_EQ ] = OP( 0, 1, 0, 0, PURE | DEF, "set_eq"),
-[OP_SET_NOTEQ ] = OP( 0, 1, 0, 0, PURE | DEF, "set_noteq"),
-[OP_SET_SLESS ] = OP( 0, 1, 0, 0, PURE | DEF, "set_sless"),
-[OP_SET_ULESS ] = OP( 0, 1, 0, 0, PURE | DEF, "set_uless"),
-[OP_SET_SMORE ] = OP( 0, 1, 0, 0, PURE | DEF, "set_smore"),
-[OP_SET_UMORE ] = OP( 0, 1, 0, 0, PURE | DEF, "set_umore"),
-[OP_SET_SLESSEQ] = OP( 0, 1, 0, 0, PURE | DEF, "set_slesseq"),
-[OP_SET_ULESSEQ] = OP( 0, 1, 0, 0, PURE | DEF, "set_ulesseq"),
-[OP_SET_SMOREEQ] = OP( 0, 1, 0, 0, PURE | DEF, "set_smoreq"),
-[OP_SET_UMOREEQ] = OP( 0, 1, 0, 0, PURE | DEF, "set_umoreq"),
-[OP_JMP ] = OP( 0, 0, 0, 1, PURE, "jmp"),
-[OP_JMP_EQ ] = OP( 0, 1, 0, 1, PURE, "jmp_eq"),
-[OP_JMP_NOTEQ ] = OP( 0, 1, 0, 1, PURE, "jmp_noteq"),
-[OP_JMP_SLESS ] = OP( 0, 1, 0, 1, PURE, "jmp_sless"),
-[OP_JMP_ULESS ] = OP( 0, 1, 0, 1, PURE, "jmp_uless"),
-[OP_JMP_SMORE ] = OP( 0, 1, 0, 1, PURE, "jmp_smore"),
-[OP_JMP_UMORE ] = OP( 0, 1, 0, 1, PURE, "jmp_umore"),
-[OP_JMP_SLESSEQ] = OP( 0, 1, 0, 1, PURE, "jmp_slesseq"),
-[OP_JMP_ULESSEQ] = OP( 0, 1, 0, 1, PURE, "jmp_ulesseq"),
-[OP_JMP_SMOREEQ] = OP( 0, 1, 0, 1, PURE, "jmp_smoreq"),
-[OP_JMP_UMOREEQ] = OP( 0, 1, 0, 1, PURE, "jmp_umoreq"),
-
-[OP_INB ] = OP( 0, 1, 0, 0, IMPURE | DEF, "__inb"),
-[OP_INW ] = OP( 0, 1, 0, 0, IMPURE | DEF, "__inw"),
-[OP_INL ] = OP( 0, 1, 0, 0, IMPURE | DEF, "__inl"),
-[OP_OUTB ] = OP( 0, 2, 0, 0, IMPURE, "__outb"),
-[OP_OUTW ] = OP( 0, 2, 0, 0, IMPURE, "__outw"),
-[OP_OUTL ] = OP( 0, 2, 0, 0, IMPURE, "__outl"),
-[OP_BSF ] = OP( 0, 1, 0, 0, PURE | DEF, "__bsf"),
-[OP_BSR ] = OP( 0, 1, 0, 0, PURE | DEF, "__bsr"),
-[OP_RDMSR ] = OP( 2, 1, 0, 0, IMPURE, "__rdmsr"),
-[OP_WRMSR ] = OP( 0, 3, 0, 0, IMPURE, "__wrmsr"),
-[OP_HLT ] = OP( 0, 0, 0, 0, IMPURE, "__hlt"),
+[OP_PHI ] = OP( 0, -1, 1, 0, PURE | DEF | BLOCK, "phi"),
+
+[OP_CMP ] = OP( 0, 2, 0, 0, PURE | DEF | BLOCK, "cmp"),
+[OP_TEST ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "test"),
+[OP_SET_EQ ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_eq"),
+[OP_SET_NOTEQ ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_noteq"),
+[OP_SET_SLESS ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_sless"),
+[OP_SET_ULESS ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_uless"),
+[OP_SET_SMORE ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_smore"),
+[OP_SET_UMORE ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_umore"),
+[OP_SET_SLESSEQ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_slesseq"),
+[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_INB ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "__inb"),
+[OP_INW ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "__inw"),
+[OP_INL ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "__inl"),
+[OP_OUTB ] = OP( 0, 2, 0, 0, IMPURE| BLOCK, "__outb"),
+[OP_OUTW ] = OP( 0, 2, 0, 0, IMPURE| BLOCK, "__outw"),
+[OP_OUTL ] = OP( 0, 2, 0, 0, IMPURE| BLOCK, "__outl"),
+[OP_BSF ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "__bsf"),
+[OP_BSR ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "__bsr"),
+[OP_RDMSR ] = OP( 2, 1, 0, 0, IMPURE | BLOCK, "__rdmsr"),
+[OP_WRMSR ] = OP( 0, 3, 0, 0, IMPURE | BLOCK, "__wrmsr"),
+[OP_HLT ] = OP( 0, 0, 0, 0, IMPURE | BLOCK, "__hlt"),
};
#undef OP
#define OP_MAX (sizeof(table_ops)/sizeof(table_ops[0]))
@@ -612,6 +617,7 @@ static const char *tops(int index)
return table_ops[index].name;
}
+struct asm_info;
struct triple;
struct block;
struct triple_set {
@@ -628,7 +634,8 @@ struct triple {
struct triple *next, *prev;
struct triple_set *use;
struct type *type;
- short op;
+ unsigned char op;
+ unsigned char template_id;
unsigned short sizes;
#define TRIPLE_LHS(SIZES) (((SIZES) >> 0) & 0x0f)
#define TRIPLE_RHS(SIZES) (((SIZES) >> 4) & 0x0f)
@@ -653,7 +660,9 @@ struct triple {
#define TARG(PTR,INDEX) ((PTR)->param[TRIPLE_TARG_OFF((PTR)->sizes) + (INDEX)])
#define MISC(PTR,INDEX) ((PTR)->param[TRIPLE_MISC_OFF((PTR)->sizes) + (INDEX)])
unsigned id; /* A scratch value and finally the register */
-#define TRIPLE_FLAG_FLATTENED 1
+#define TRIPLE_FLAG_FLATTENED (1 << 31)
+#define TRIPLE_FLAG_PRE_SPLIT (1 << 30)
+#define TRIPLE_FLAG_POST_SPLIT (1 << 29)
const char *filename;
int line;
int col;
@@ -662,10 +671,24 @@ struct triple {
struct block *block;
void *blob;
struct hash_entry *field;
+ struct asm_info *ainfo;
} u;
struct triple *param[2];
};
+struct reg_info {
+ unsigned reg;
+ unsigned regcm;
+};
+struct ins_template {
+ struct reg_info lhs[MAX_LHS + 1], rhs[MAX_RHS + 1];
+};
+
+struct asm_info {
+ struct ins_template tmpl;
+ char *str;
+};
+
struct block_set {
struct block_set *next;
struct block *member;
@@ -714,6 +737,8 @@ struct hash_entry {
#define HASH_TABLE_SIZE 2048
struct compile_state {
+ const char *ofilename;
+ FILE *output;
struct triple *vars;
struct file_state *file;
struct token token[4];
@@ -727,6 +752,7 @@ struct compile_state {
struct triple *main_function;
struct block *first_block, *last_block;
int last_vertex;
+ int cpu;
int debug;
int optimize;
};
@@ -818,23 +844,27 @@ struct type {
#define MAX_REGISTERS 75
#define MAX_REG_EQUIVS 16
+#define REGISTER_BITS 28
+#define MAX_VIRT_REGISTERS (1<<REGISTER_BITS)
+#define TEMPLATE_BITS 6
+#define MAX_TEMPLATES (1<<TEMPLATE_BITS)
#define MAX_REGC 12
#define REG_UNSET 0
+#define REG_UNNEEDED 1
+#define REG_VIRT0 (MAX_REGISTERS + 0)
+#define REG_VIRT1 (MAX_REGISTERS + 1)
+#define REG_VIRT2 (MAX_REGISTERS + 2)
+#define REG_VIRT3 (MAX_REGISTERS + 3)
+#define REG_VIRT4 (MAX_REGISTERS + 4)
+#define REG_VIRT5 (MAX_REGISTERS + 5)
/* Provision for 8 register classes */
-#define REGC_MASK ((1 << MAX_REGC) - 1)
-#define ID_REG_CLASSES(ID) ((ID) & REGC_MASK)
-#define ID_REG(ID) ((ID) >> MAX_REGC)
-#define MK_REG_ID(REG, CLASSES) (((REG) << MAX_REGC) | ((CLASSES) & REGC_MASK))
-
-static unsigned alloc_virtual_reg(void)
-{
- static unsigned virtual_reg = MAX_REGISTERS;
- virtual_reg += 1;
- return virtual_reg;
-}
+#define REG_MASK (MAX_VIRT_REGISTERS -1)
+#define ID_REG(ID) ((ID) & REG_MASK)
+#define SET_REG(ID, REG) ((ID) = (((ID) & ~REG_MASK) | ((REG) & REG_MASK)))
static unsigned arch_reg_regcm(struct compile_state *state, int reg);
+static unsigned arch_regcm_normalize(struct compile_state *state, unsigned regcm);
static void arch_reg_equivs(
struct compile_state *state, unsigned *equiv, int reg);
static int arch_select_free_register(
@@ -843,6 +873,18 @@ static unsigned arch_regc_size(struct compile_state *state, int class);
static int arch_regcm_intersect(unsigned regcm1, unsigned regcm2);
static unsigned arch_type_to_regcm(struct compile_state *state, struct type *type);
static const char *arch_reg_str(int reg);
+static struct reg_info arch_reg_constraint(
+ struct compile_state *state, struct type *type, const char *constraint);
+static struct reg_info arch_reg_clobber(
+ struct compile_state *state, const char *clobber);
+static struct reg_info arch_reg_lhs(struct compile_state *state,
+ struct triple *ins, int index);
+static struct reg_info arch_reg_rhs(struct compile_state *state,
+ struct triple *ins, int index);
+static struct triple *transform_to_arch_instruction(
+ struct compile_state *state, struct triple *ins);
+
+
#define DEBUG_ABORT_ON_ERROR 0x0001
#define DEBUG_INTERMEDIATE_CODE 0x0002
@@ -854,10 +896,19 @@ static const char *arch_reg_str(int reg);
#define DEBUG_INTERFERENCE 0x0080
#define DEBUG_ARCH_CODE 0x0100
#define DEBUG_CODE_ELIMINATION 0x0200
+#define DEBUG_INSERTED_COPIES 0x0400
#define GLOBAL_SCOPE_DEPTH 1
-static void compile_file(struct compile_state *old_state, char *filename, int local);
+static void compile_file(struct compile_state *old_state, const char *filename, int local);
+
+static void do_cleanup(struct compile_state *state)
+{
+ if (state->output) {
+ fclose(state->output);
+ unlink(state->ofilename);
+ }
+}
static int get_col(struct file_state *file)
{
@@ -898,10 +949,14 @@ static void __internal_error(struct compile_state *state, struct triple *ptr,
va_list args;
va_start(args, fmt);
loc(stderr, state, ptr);
+ if (ptr) {
+ fprintf(stderr, "%p %s ", ptr, tops(ptr->op));
+ }
fprintf(stderr, "Internal compiler error: ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
+ do_cleanup(state);
abort();
}
@@ -929,6 +984,7 @@ static void __error(struct compile_state *state, struct triple *ptr,
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
+ do_cleanup(state);
if (state->debug & DEBUG_ABORT_ON_ERROR) {
abort();
}
@@ -960,7 +1016,6 @@ static void __warning(struct compile_state *state, struct triple *ptr,
#endif
#define FINISHME() warning(state, 0, "FINISHME @ %s.%s:%d", __FILE__, __func__, __LINE__)
-
static void valid_op(struct compile_state *state, int op)
{
char *fmt = "invalid op: %d";
@@ -1065,6 +1120,9 @@ static void use_triple(struct triple *used, struct triple *user)
static void unuse_triple(struct triple *used, struct triple *unuser)
{
struct triple_set *use, **ptr;
+ if (!used) {
+ return;
+ }
ptr = &used->use;
while(*ptr) {
use = *ptr;
@@ -1133,7 +1191,7 @@ static struct triple zero_triple = {
static unsigned short triple_sizes(struct compile_state *state,
- int op, struct type *type, int rhs_wanted)
+ int op, struct type *type, int lhs_wanted, int rhs_wanted)
{
int lhs, rhs, misc, targ;
valid_op(state, op);
@@ -1165,6 +1223,10 @@ static unsigned short triple_sizes(struct compile_state *state,
else if ((op == OP_BRANCH) || (op == OP_PHI)) {
rhs = rhs_wanted;
}
+ else if (op == OP_ASM) {
+ rhs = rhs_wanted;
+ lhs = lhs_wanted;
+ }
if ((rhs < 0) || (rhs > MAX_RHS)) {
internal_error(state, 0, "bad rhs");
}
@@ -1181,12 +1243,12 @@ static unsigned short triple_sizes(struct compile_state *state,
}
static struct triple *alloc_triple(struct compile_state *state,
- int op, struct type *type, int rhs,
+ int op, struct type *type, int lhs, int rhs,
const char *filename, int line, int col)
{
size_t size, sizes, extra_count, min_count;
struct triple *ret;
- sizes = triple_sizes(state, op, type, rhs);
+ sizes = triple_sizes(state, op, type, lhs, rhs);
min_count = sizeof(ret->param)/sizeof(ret->param[0]);
extra_count = TRIPLE_SIZE(sizes);
@@ -1208,17 +1270,19 @@ static struct triple *alloc_triple(struct compile_state *state,
struct triple *dup_triple(struct compile_state *state, struct triple *src)
{
struct triple *dup;
- int src_rhs;
+ int src_lhs, src_rhs, src_size;
+ src_lhs = TRIPLE_LHS(src->sizes);
src_rhs = TRIPLE_RHS(src->sizes);
- dup = alloc_triple(state, src->op, src->type, src_rhs,
+ src_size = TRIPLE_SIZE(src->sizes);
+ dup = alloc_triple(state, src->op, src->type, src_lhs, src_rhs,
src->filename, src->line, src->col);
memcpy(dup, src, sizeof(*src));
- memcpy(dup->param, src->param, src_rhs * sizeof(src->param[0]));
+ memcpy(dup->param, src->param, src_size * sizeof(src->param[0]));
return dup;
}
static struct triple *new_triple(struct compile_state *state,
- int op, struct type *type, int rhs)
+ int op, struct type *type, int lhs, int rhs)
{
struct triple *ret;
const char *filename;
@@ -1231,7 +1295,7 @@ static struct triple *new_triple(struct compile_state *state,
line = state->file->line;
col = get_col(state->file);
}
- ret = alloc_triple(state, op, type, rhs,
+ ret = alloc_triple(state, op, type, lhs, rhs,
filename, line, col);
return ret;
}
@@ -1242,7 +1306,7 @@ static struct triple *build_triple(struct compile_state *state,
{
struct triple *ret;
size_t count;
- ret = alloc_triple(state, op, type, -1, filename, line, col);
+ ret = alloc_triple(state, op, type, -1, -1, filename, line, col);
count = TRIPLE_SIZE(ret->sizes);
if (count > 0) {
ret->param[0] = left;
@@ -1258,7 +1322,7 @@ static struct triple *triple(struct compile_state *state,
{
struct triple *ret;
size_t count;
- ret = new_triple(state, op, type, -1);
+ ret = new_triple(state, op, type, -1, -1);
count = TRIPLE_SIZE(ret->sizes);
if (count >= 1) {
ret->param[0] = left;
@@ -1273,7 +1337,7 @@ 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, test?1:0);
+ ret = new_triple(state, OP_BRANCH, &void_type, -1, test?1:0);
if (test) {
RHS(ret, 0) = test;
}
@@ -1306,16 +1370,50 @@ static void insert_triple(struct compile_state *state,
}
}
+static int triple_stores_block(struct compile_state *state, struct triple *ins)
+{
+ /* This function is used to determine if u.block
+ * is utilized to store the current block number.
+ */
+ int stores_block;
+ valid_ins(state, ins);
+ stores_block = (table_ops[ins->op].flags & BLOCK) == BLOCK;
+ return stores_block;
+}
+
+static struct block *block_of_triple(struct compile_state *state,
+ struct triple *ins)
+{
+ struct triple *first;
+ first = RHS(state->main_function, 0);
+ while(ins != first && !triple_stores_block(state, ins)) {
+ if (ins == ins->prev) {
+ internal_error(state, 0, "ins == ins->prev?");
+ }
+ ins = ins->prev;
+ }
+ if (!triple_stores_block(state, ins)) {
+ internal_error(state, ins, "Cannot find block");
+ }
+ return ins->u.block;
+}
+
static struct triple *pre_triple(struct compile_state *state,
struct triple *base,
int op, struct type *type, struct triple *left, struct triple *right)
{
- /* Careful this assumes it can do the easy thing to get the block */
+ struct block *block;
struct triple *ret;
+ block = block_of_triple(state, base);
ret = build_triple(state, op, type, left, right,
base->filename, base->line, base->col);
- ret->u.block = base->u.block;
+ if (triple_stores_block(state, ret)) {
+ ret->u.block = block;
+ }
insert_triple(state, base, ret);
+ if (block->first == base) {
+ block->first = ret;
+ }
return ret;
}
@@ -1323,12 +1421,18 @@ static struct triple *post_triple(struct compile_state *state,
struct triple *base,
int op, struct type *type, struct triple *left, struct triple *right)
{
- /* Careful this assumes it can do the easy thing to get the block */
+ struct block *block;
struct triple *ret;
+ block = block_of_triple(state, base);
ret = build_triple(state, op, type, left, right,
base->filename, base->line, base->col);
- ret->u.block = base->u.block;
+ if (triple_stores_block(state, ret)) {
+ ret->u.block = block;
+ }
insert_triple(state, base->next, ret);
+ if (block->last == base) {
+ block->last = ret;
+ }
return ret;
}
@@ -1343,22 +1447,21 @@ static struct triple *label(struct compile_state *state)
static void display_triple(FILE *fp, struct triple *ins)
{
if (ins->op == OP_INTCONST) {
- fprintf(fp, "(%p) %3d %-10s 0x%08lx @ %s:%d.%d\n",
- ins, ID_REG(ins->id), tops(ins->op), ins->u.cval,
+ fprintf(fp, "(%p) %3d %-2d %-10s <0x%08lx> @ %s:%d.%d\n",
+ ins, ID_REG(ins->id), ins->template_id, tops(ins->op),
+ ins->u.cval,
ins->filename, ins->line, ins->col);
}
- else if (ins->op == OP_SDECL) {
- fprintf(fp, "(%p) %3d %-10s %-10p @ %s:%d.%d\n",
- ins, ID_REG(ins->id), tops(ins->op), MISC(ins, 0),
+ else if (ins->op == OP_ADDRCONST) {
+ fprintf(fp, "(%p) %3d %-2d %-10s %-10p <0x%08lx> @ %s:%d.%d\n",
+ ins, ID_REG(ins->id), ins->template_id, tops(ins->op),
+ MISC(ins, 0), ins->u.cval,
ins->filename, ins->line, ins->col);
-#if 0
- print_ins(state, MISC(ins, 0));
-#endif
}
else {
int i, count;
- fprintf(fp, "(%p) %3d %-10s",
- ins, ID_REG(ins->id), tops(ins->op));
+ fprintf(fp, "(%p) %3d %-2d %-10s",
+ ins, ID_REG(ins->id), ins->template_id, tops(ins->op));
count = TRIPLE_SIZE(ins->sizes);
for(i = 0; i < count; i++) {
fprintf(fp, " %-10p", ins->param[i]);
@@ -1448,11 +1551,66 @@ static struct triple **triple_misc(struct compile_state *state,
return triple_iter(state, TRIPLE_MISC(ins->sizes), &MISC(ins,0),
ins, last);
}
+
static struct triple **triple_targ(struct compile_state *state,
struct triple *ins, struct triple **last)
{
- return triple_iter(state, TRIPLE_TARG(ins->sizes), &TARG(ins,0),
- ins, last);
+ size_t count;
+ struct triple **ret, **vector;
+ ret = 0;
+ count = TRIPLE_TARG(ins->sizes);
+ vector = &TARG(ins, 0);
+ if (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;
+ }
+ }
+ return ret;
+}
+
+
+static void verify_use(struct compile_state *state,
+ struct triple *user, struct triple *used)
+{
+ int size, i;
+ size = TRIPLE_SIZE(user->sizes);
+ for(i = 0; i < size; i++) {
+ if (user->param[i] == used) {
+ break;
+ }
+ }
+ if (triple_is_branch(state, user)) {
+ if (user->next == used) {
+ i = -1;
+ }
+ }
+ if (i == size) {
+ internal_error(state, user, "%s(%p) does not use %s(%p)",
+ tops(user->op), user, tops(used->op), used);
+ }
+}
+
+static int find_rhs_use(struct compile_state *state,
+ struct triple *user, struct triple *used)
+{
+ struct triple **param;
+ int size, i;
+ verify_use(state, user, used);
+ size = TRIPLE_RHS(user->sizes);
+ param = &RHS(user, 0);
+ for(i = 0; i < size; i++) {
+ if (param[i] == used) {
+ return i;
+ }
+ }
+ return -1;
}
static void free_triple(struct compile_state *state, struct triple *ptr)
@@ -1486,6 +1644,12 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
unuse_triple(*expr, ptr);
}
}
+ expr = triple_misc(state, ptr, 0);
+ for(; expr; expr = triple_misc(state, ptr, expr)) {
+ if (*expr) {
+ unuse_triple(*expr, ptr);
+ }
+ }
expr = triple_targ(state, ptr, 0);
for(; expr; expr = triple_targ(state, ptr, expr)) {
if (*expr) {
@@ -1507,6 +1671,12 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
*expr = &zero_triple;
}
}
+ expr = triple_misc(state, set->member, 0);
+ for(; expr; expr = triple_misc(state, set->member, expr)) {
+ if (*expr == ptr) {
+ *expr = &zero_triple;
+ }
+ }
expr = triple_targ(state, set->member, 0);
for(; expr; expr = triple_targ(state, set->member, expr)) {
if (*expr == ptr) {
@@ -1916,8 +2086,10 @@ static void register_keywords(struct compile_state *state)
hash_keyword(state, "unsigned", TOK_UNSIGNED);
hash_keyword(state, "void", TOK_VOID);
hash_keyword(state, "volatile", TOK_VOLATILE);
+ hash_keyword(state, "__volatile__", TOK_VOLATILE);
hash_keyword(state, "while", TOK_WHILE);
hash_keyword(state, "asm", TOK_ASM);
+ hash_keyword(state, "__asm__", TOK_ASM);
hash_keyword(state, "__attribute__", TOK_ATTRIBUTE);
hash_keyword(state, "__alignof__", TOK_ALIGNOF);
}
@@ -3186,10 +3358,10 @@ static char *include_paths[] = {
0
};
-static void compile_file(struct compile_state *state, char *filename, int local)
+static void compile_file(struct compile_state *state, const char *filename, int local)
{
char cwd[4096];
- char *subdir, *base;
+ const char *subdir, *base;
int subdir_len;
struct file_state *file;
char *basename;
@@ -3325,7 +3497,7 @@ static struct triple *variable(struct compile_state *state, struct type *type)
struct type *field;
struct triple **vector;
ulong_t index;
- result = new_triple(state, OP_VAL_VEC, type, -1);
+ result = new_triple(state, OP_VAL_VEC, type, -1, -1);
vector = &result->param[0];
field = type->left;
@@ -3853,7 +4025,7 @@ static struct triple *integral_promotion(
static void arithmetic(struct compile_state *state, struct triple *def)
{
if (!TYPE_ARITHMETIC(def->type->type)) {
- error(state, def, "arithmetic type expexted");
+ error(state, 0, "arithmetic type expexted");
}
}
@@ -4015,7 +4187,8 @@ static struct triple *do_mk_addr_expr(struct compile_state *state,
error(state, expr, "address of auto variables not supported");
}
else if (expr->op == OP_SDECL) {
- result = triple(state, OP_ADDRCONST, type, expr, 0);
+ result = triple(state, OP_ADDRCONST, type, 0, 0);
+ MISC(result, 0) = expr;
result->u.cval = offset;
}
else if (expr->op == OP_DEREF) {
@@ -4105,10 +4278,13 @@ static struct triple *read_expr(struct compile_state *state, struct triple *def)
#warning "CHECK_ME is this the right place to transform arrays to pointers?"
if ((def->type->type & TYPE_MASK) == TYPE_ARRAY) {
struct type *type;
+ struct triple *result;
type = new_type(
TYPE_POINTER | (def->type->type & QUAL_MASK),
def->type->left, 0);
- return triple(state, OP_ADDRCONST, type, def, 0);
+ result = triple(state, OP_ADDRCONST, type, 0, 0);
+ MISC(result, 0) = def;
+ return result;
}
if (is_in_reg(state, def)) {
op = OP_READ;
@@ -4204,6 +4380,9 @@ static struct triple *init_expr(
error(state, 0, "Incompatible types in inializer");
}
MISC(dest, 0) = rval;
+ insert_triple(state, dest, rval);
+ rval->id |= TRIPLE_FLAG_FLATTENED;
+ use_triple(MISC(dest, 0), dest);
}
return def;
}
@@ -4309,7 +4488,7 @@ static struct triple *cond_expr(
}
/* Cleanup and invert the test */
test = lfalse_expr(state, read_expr(state, test));
- def = new_triple(state, OP_COND, result_type, 3);
+ def = new_triple(state, OP_COND, result_type, 0, 3);
def->param[0] = test;
def->param[1] = left;
def->param[2] = right;
@@ -4514,20 +4693,14 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc)
ofirst = old = RHS(ofunc, 0);
do {
struct triple *new;
- int old_rhs;
+ int old_lhs, old_rhs;
+ old_lhs = TRIPLE_LHS(old->sizes);
old_rhs = TRIPLE_RHS(old->sizes);
- new = alloc_triple(state, old->op, old->type, old_rhs,
+ new = alloc_triple(state, old->op, old->type, old_lhs, old_rhs,
old->filename, old->line, old->col);
- if (IS_CONST_OP(new->op)) {
+ if (!triple_stores_block(state, new)) {
memcpy(&new->u, &old->u, sizeof(new->u));
}
-#warning "WISHLIST find a way to handle SDECL without a special case..."
- /* The problem is that I don't flatten the misc field,
- * so I cannot look the value the misc field should have.
- */
- else if (new->op == OP_SDECL) {
- MISC(new, 0) = MISC(old, 0);
- }
if (!nfirst) {
RHS(nfunc, 0) = nfirst = new;
}
@@ -4702,6 +4875,8 @@ static struct triple *flatten(
}
break;
case OP_BLOBCONST:
+ insert_triple(state, first, ptr);
+ ptr->id |= TRIPLE_FLAG_FLATTENED;
ptr = triple(state, OP_SDECL, ptr->type, ptr, 0);
use_triple(MISC(ptr, 0), ptr);
break;
@@ -4721,7 +4896,12 @@ static struct triple *flatten(
}
break;
}
+ case OP_ADDRCONST:
case OP_SDECL:
+ case OP_PIECE:
+ MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
+ use_triple(MISC(ptr, 0), ptr);
+ break;
case OP_ADECL:
break;
default:
@@ -4825,9 +5005,9 @@ static struct triple *mk_add_expr(
left = right;
right = tmp;
}
- result_type = ptr_arithmetic_result(state, left, right);
left = read_expr(state, left);
right = read_expr(state, right);
+ result_type = ptr_arithmetic_result(state, left, right);
if (is_pointer(left)) {
right = triple(state,
is_signed(right->type)? OP_SMUL : OP_UMUL,
@@ -4958,7 +5138,7 @@ static int constants_equal(struct compile_state *state,
break;
}
case OP_ADDRCONST:
- if ((RHS(left, 0) == RHS(right, 0)) &&
+ if ((MISC(left, 0) == MISC(right, 0)) &&
(left->u.cval == right->u.cval)) {
equal = 1;
}
@@ -5144,8 +5324,8 @@ static void mkaddr_const(struct compile_state *state,
{
wipe_ins(state, ins);
ins->op = OP_ADDRCONST;
- ins->sizes = TRIPLE_SIZES(0, 1, 0, 0);
- RHS(ins, 0) = sdecl;
+ ins->sizes = TRIPLE_SIZES(0, 0, 1, 0);
+ MISC(ins, 0) = sdecl;
ins->u.cval = value;
use_triple(sdecl, ins);
}
@@ -5174,7 +5354,7 @@ static void flatten_structures(struct compile_state *state)
op = ins->op;
def = RHS(ins, 0);
- next = alloc_triple(state, OP_VAL_VEC, ins->type, -1,
+ next = alloc_triple(state, OP_VAL_VEC, ins->type, -1, -1,
ins->filename, ins->line, ins->col);
vector = &RHS(next, 0);
@@ -5208,7 +5388,7 @@ static void flatten_structures(struct compile_state *state)
op = ins->op;
src = RHS(ins, 0);
dst = LHS(ins, 0);
- next = alloc_triple(state, OP_VAL_VEC, ins->type, -1,
+ next = alloc_triple(state, OP_VAL_VEC, ins->type, -1, -1,
ins->filename, ins->line, ins->col);
vector = &RHS(next, 0);
@@ -5251,7 +5431,7 @@ static void flatten_structures(struct compile_state *state)
*/
ins = first;
do {
- ins->id = 0;
+ ins->id &= ~TRIPLE_FLAG_FLATTENED;
if ((ins->type->type & TYPE_MASK) == TYPE_STRUCT) {
internal_error(state, 0, "STRUCT_TYPE remains?");
}
@@ -5463,7 +5643,7 @@ static void simplify_add(struct compile_state *state, struct triple *ins)
else /* op == OP_ADDRCONST */ {
struct triple *sdecl;
ulong_t left, right;
- sdecl = RHS(RHS(ins, 0), 0);
+ sdecl = MISC(RHS(ins, 0), 0);
left = RHS(ins, 0)->u.cval;
right = RHS(ins, 1)->u.cval;
mkaddr_const(state, ins, sdecl, left + right);
@@ -5489,7 +5669,7 @@ static void simplify_sub(struct compile_state *state, struct triple *ins)
else /* op == OP_ADDRCONST */ {
struct triple *sdecl;
ulong_t left, right;
- sdecl = RHS(RHS(ins, 0), 0);
+ sdecl = MISC(RHS(ins, 0), 0);
left = RHS(ins, 0)->u.cval;
right = RHS(ins, 1)->u.cval;
mkaddr_const(state, ins, sdecl, left - right);
@@ -5817,8 +5997,8 @@ static void simplify_copy(struct compile_state *state, struct triple *ins)
{
struct triple *sdecl;
ulong_t offset;
- sdecl = RHS(ins, 0);
- offset = ins->u.cval;
+ sdecl = MISC(RHS(ins, 0), 0);
+ offset = RHS(ins, 0)->u.cval;
mkaddr_const(state, ins, sdecl, offset);
break;
}
@@ -6031,6 +6211,7 @@ static const simplify_t table_simplify[] = {
[OP_READ ] = simplify_noop,
[OP_COPY ] = simplify_copy,
[OP_PIECE ] = simplify_noop,
+[OP_ASM ] = simplify_noop,
[OP_DOT ] = simplify_noop,
[OP_VAL_VEC ] = simplify_noop,
@@ -6158,7 +6339,7 @@ static void register_builtin_function(struct compile_state *state,
result = flatten(state, first, variable(state, rtype));
}
MISC(def, 0) = result;
- work = new_triple(state, op, rtype, parameters);
+ work = new_triple(state, op, rtype, -1, parameters);
for(i = 0, arg = first->next; i < parameters; i++, arg = arg->next) {
RHS(work, i) = read_expr(state, arg);
}
@@ -6171,7 +6352,7 @@ static void register_builtin_function(struct compile_state *state,
if (rtype->elements != TRIPLE_LHS(work->sizes)) {
internal_error(state, 0, "Invalid result type");
}
- val = new_triple(state, OP_VAL_VEC, rtype, -1);
+ val = new_triple(state, OP_VAL_VEC, rtype, -1, -1);
for(i = 0; i < rtype->elements; i++) {
struct triple *piece;
atype = param;
@@ -6321,7 +6502,7 @@ 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);
+ def = new_triple(state, OP_CALL, func->type, -1, -1);
def->type = type;
pvals = TRIPLE_RHS(def->sizes);
@@ -6694,7 +6875,6 @@ static struct triple *cast_expr(struct compile_state *state)
eat(state, TOK_RPAREN);
def = read_expr(state, cast_expr(state));
def = triple(state, OP_COPY, type, def, 0);
-#warning "FIXME do I need an OP_CAST expr to be semantically correct here?"
}
else {
def = unary_expr(state);
@@ -7047,8 +7227,6 @@ static struct triple *assignment_expr(struct compile_state *state)
case TOK_TIMESEQ:
case TOK_DIVEQ:
case TOK_MODEQ:
- case TOK_PLUSEQ:
- case TOK_MINUSEQ:
lvalue(state, left);
arithmetic(state, left);
eat(state, tok);
@@ -7061,13 +7239,23 @@ static struct triple *assignment_expr(struct compile_state *state)
case TOK_TIMESEQ: op = sign? OP_SMUL : OP_UMUL; break;
case TOK_DIVEQ: op = sign? OP_SDIV : OP_UDIV; break;
case TOK_MODEQ: op = sign? OP_SMOD : OP_UMOD; break;
- case TOK_PLUSEQ: op = OP_ADD; break;
- case TOK_MINUSEQ: op = OP_SUB; break;
}
def = write_expr(state, left,
triple(state, op, left->type,
read_expr(state, left), right));
break;
+ case TOK_PLUSEQ:
+ lvalue(state, left);
+ eat(state, TOK_PLUSEQ);
+ def = write_expr(state, left,
+ mk_add_expr(state, left, assignment_expr(state)));
+ break;
+ case TOK_MINUSEQ:
+ lvalue(state, left);
+ eat(state, TOK_MINUSEQ);
+ def = write_expr(state, left,
+ mk_sub_expr(state, left, assignment_expr(state)));
+ break;
case TOK_SLEQ:
case TOK_SREQ:
case TOK_ANDEQ:
@@ -7400,8 +7588,151 @@ static void default_statement(struct compile_state *state, struct triple *first)
static void asm_statement(struct compile_state *state, struct triple *first)
{
- FINISHME();
- error(state, 0, "FIXME finish asm_statement");
+ struct asm_info *info;
+ struct {
+ struct triple *constraint;
+ struct triple *expr;
+ } out_param[MAX_LHS], in_param[MAX_RHS], clob_param[MAX_LHS];
+ struct triple *def, *asm_str;
+ int out, in, clobbers, more, colons, i;
+
+ eat(state, TOK_ASM);
+ /* For now ignore the qualifiers */
+ switch(peek(state)) {
+ case TOK_CONST:
+ eat(state, TOK_CONST);
+ break;
+ case TOK_VOLATILE:
+ eat(state, TOK_VOLATILE);
+ break;
+ }
+ eat(state, TOK_LPAREN);
+ asm_str = string_constant(state);
+
+ colons = 0;
+ out = in = clobbers = 0;
+ /* Outputs */
+ if ((colons == 0) && (peek(state) == TOK_COLON)) {
+ eat(state, TOK_COLON);
+ colons++;
+ more = (peek(state) == TOK_LIT_STRING);
+ while(more) {
+ struct triple *var;
+ struct triple *constraint;
+ more = 0;
+ if (out > MAX_LHS) {
+ error(state, 0, "Maximum output count exceeded.");
+ }
+ constraint = string_constant(state);
+ eat(state, TOK_LPAREN);
+ var = conditional_expr(state);
+ eat(state, TOK_RPAREN);
+
+ lvalue(state, var);
+ out_param[out].constraint = constraint;
+ out_param[out].expr = var;
+ if (peek(state) == TOK_COMMA) {
+ eat(state, TOK_COMMA);
+ more = 1;
+ }
+ out++;
+ }
+ }
+ /* Inputs */
+ if ((colons == 1) && (peek(state) == TOK_COLON)) {
+ eat(state, TOK_COLON);
+ colons++;
+ more = (peek(state) == TOK_LIT_STRING);
+ while(more) {
+ struct triple *val;
+ struct triple *constraint;
+ more = 0;
+ if (in > MAX_RHS) {
+ error(state, 0, "Maximum input count exceeded.");
+ }
+ constraint = string_constant(state);
+ eat(state, TOK_LPAREN);
+ val = conditional_expr(state);
+ eat(state, TOK_RPAREN);
+
+ in_param[in].constraint = constraint;
+ in_param[in].expr = val;
+ if (peek(state) == TOK_COMMA) {
+ eat(state, TOK_COMMA);
+ more = 1;
+ }
+ in++;
+ }
+ }
+
+ /* Clobber */
+ if ((colons == 2) && (peek(state) == TOK_COLON)) {
+ eat(state, TOK_COLON);
+ colons++;
+ more = (peek(state) == TOK_LIT_STRING);
+ while(more) {
+ struct triple *clobber;
+ more = 0;
+ if ((clobbers + out) > MAX_LHS) {
+ error(state, 0, "Maximum clobber limit exceeded.");
+ }
+ clobber = string_constant(state);
+ eat(state, TOK_RPAREN);
+
+ clob_param[clobbers].constraint = clobber;
+ if (peek(state) == TOK_COMMA) {
+ eat(state, TOK_COMMA);
+ more = 1;
+ }
+ clobbers++;
+ }
+ }
+ eat(state, TOK_RPAREN);
+ eat(state, TOK_SEMI);
+
+
+ info = xcmalloc(sizeof(*info), "asm_info");
+ info->str = asm_str->u.blob;
+ free_triple(state, asm_str);
+
+ def = new_triple(state, OP_ASM, &void_type, clobbers + out, in);
+ def->u.ainfo = info;
+ for(i = 0; i < in; i++) {
+ struct triple *constraint;
+ constraint = in_param[i].constraint;
+ info->tmpl.rhs[i] = arch_reg_constraint(state,
+ in_param[i].expr->type, constraint->u.blob);
+
+ RHS(def, i) = read_expr(state,in_param[i].expr);
+ free_triple(state, constraint);
+ }
+ flatten(state, first, def);
+ for(i = 0; i < out; i++) {
+ struct triple *piece;
+ struct triple *constraint;
+ constraint = out_param[i].constraint;
+ info->tmpl.lhs[i] = arch_reg_constraint(state,
+ out_param[i].expr->type, constraint->u.blob);
+
+ piece = triple(state, OP_PIECE, out_param[i].expr->type, def, 0);
+ piece->u.cval = i;
+ LHS(def, i) = piece;
+ flatten(state, first,
+ write_expr(state, out_param[i].expr, piece));
+ free_triple(state, constraint);
+ }
+ for(; i - out < clobbers; i++) {
+ struct triple *piece;
+ struct triple *constraint;
+ constraint = clob_param[i - out].constraint;
+ info->tmpl.lhs[i] = arch_reg_clobber(state, constraint->u.blob);
+
+ piece = triple(state, OP_PIECE, &void_type, def, 0);
+ piece->u.cval = i;
+ LHS(def, i) = piece;
+ flatten(state, first, piece);
+ free_triple(state, constraint);
+ }
}
@@ -8664,7 +8995,7 @@ static struct block *basic_block(struct compile_state *state,
}
block->last = ptr;
/* If ptr->u is not used remember where the baic block is */
- if (!is_const(ptr)) {
+ if (triple_stores_block(state, ptr)) {
ptr->u.block = block;
}
if (ptr->op == OP_BRANCH) {
@@ -8724,8 +9055,9 @@ static void print_block(
struct compile_state *state, struct block *block, void *arg)
{
struct triple *ptr;
+ FILE *fp = arg;
- printf("\nblock: %p (%d), %p<-%p %p<-%p\n",
+ fprintf(fp, "\nblock: %p (%d), %p<-%p %p<-%p\n",
block,
block->vertex,
block->left,
@@ -8733,13 +9065,13 @@ static void print_block(
block->right,
block->right && block->right->use?block->right->use->member : 0);
if (block->first->op == OP_LABEL) {
- printf("%p:\n", block->first);
+ fprintf(fp, "%p:\n", block->first);
}
for(ptr = block->first; ; ptr = ptr->next) {
struct triple_set *user;
int op = ptr->op;
- if (!IS_CONST_OP(op)) {
+ if (triple_stores_block(state, ptr)) {
if (ptr->u.block != block) {
internal_error(state, ptr,
"Wrong block pointer: %p\n",
@@ -8755,7 +9087,13 @@ static void print_block(
}
}
}
- display_triple(stdout, ptr);
+ display_triple(fp, ptr);
+
+#if 0
+ for(user = ptr->use; user; user = user->next) {
+ fprintf(fp, "use: %p\n", user->member);
+ }
+#endif
/* Sanity checks... */
valid_ins(state, ptr);
@@ -8763,7 +9101,7 @@ static void print_block(
struct triple *use;
use = user->member;
valid_ins(state, use);
- if (!IS_CONST_OP(user->member->op) &&
+ if (triple_stores_block(state, user->member) &&
!user->member->u.block) {
internal_error(state, user->member,
"Use %p not in a block?",
@@ -8774,37 +9112,42 @@ static void print_block(
if (ptr == block->last)
break;
}
- printf("\n");
+ fprintf(fp,"\n");
}
-static void print_blocks(struct compile_state *state)
+static void print_blocks(struct compile_state *state, FILE *fp)
{
- printf("--------------- blocks ---------------\n");
- walk_blocks(state, print_block, 0);
+ fprintf(fp, "--------------- blocks ---------------\n");
+ walk_blocks(state, print_block, fp);
}
static void prune_nonblock_triples(struct compile_state *state)
{
struct block *block;
- struct triple *first, *ins;
+ struct triple *first, *ins, *next;
/* Delete the triples not in a basic block */
first = RHS(state->main_function, 0);
block = 0;
ins = first;
do {
+ next = ins->next;
if (ins->op == OP_LABEL) {
block = ins->u.block;
}
- ins = ins->next;
if (!block) {
- release_triple(state, ins->prev);
+ release_triple(state, ins);
}
+ ins = next;
} while(ins != first);
}
static void setup_basic_blocks(struct compile_state *state)
{
+ if (!triple_stores_block(state, RHS(state->main_function, 0)) ||
+ !triple_stores_block(state, RHS(state->main_function,0)->prev)) {
+ internal_error(state, 0, "ins will not store block?");
+ }
/* Find the basic blocks */
state->last_vertex = 0;
state->first_block = basic_block(state, RHS(state->main_function,0));
@@ -8821,7 +9164,7 @@ static void setup_basic_blocks(struct compile_state *state)
use_block(state->first_block, state->last_block);
/* If we are debugging print what I have just done */
if (state->debug & DEBUG_BASIC_BLOCKS) {
- print_blocks(state);
+ print_blocks(state, stdout);
print_control_flow(state);
}
}
@@ -8904,7 +9247,7 @@ static void free_basic_blocks(struct compile_state *state)
first = RHS(state->main_function, 0);
ins = first;
do {
- if (!is_const(ins)) {
+ if (triple_stores_block(state, ins)) {
ins->u.block = 0;
}
ins = ins->next;
@@ -9304,33 +9647,26 @@ static void find_block_ipdomf(struct compile_state *state, struct block *block)
}
}
-static int print_dominated(
- struct compile_state *state, struct block *block, int vertex)
+static void print_dominated(
+ struct compile_state *state, struct block *block, void *arg)
{
struct block_set *user;
+ FILE *fp = arg;
- if (!block || (block->vertex != vertex + 1)) {
- return vertex;
- }
- vertex += 1;
-
- printf("%d:", block->vertex);
+ fprintf(fp, "%d:", block->vertex);
for(user = block->idominates; user; user = user->next) {
- printf(" %d", user->member->vertex);
+ fprintf(fp, " %d", user->member->vertex);
if (user->member->idom != block) {
internal_error(state, user->member->first, "bad idom");
}
}
- printf("\n");
- vertex = print_dominated(state, block->left, vertex);
- vertex = print_dominated(state, block->right, vertex);
- return vertex;
+ fprintf(fp,"\n");
}
-static void print_dominators(struct compile_state *state)
+static void print_dominators(struct compile_state *state, FILE *fp)
{
- printf("\ndominates\n");
- print_dominated(state, state->first_block, 0);
+ fprintf(fp, "\ndominates\n");
+ walk_blocks(state, print_dominated, fp);
}
@@ -9369,7 +9705,7 @@ static void analyze_idominators(struct compile_state *state)
find_block_domf(state, state->first_block);
/* If debuging print the print what I have just found */
if (state->debug & DEBUG_FDOMINATORS) {
- print_dominators(state);
+ print_dominators(state, stdout);
print_dominance_frontiers(state);
print_control_flow(state);
}
@@ -9377,34 +9713,26 @@ static void analyze_idominators(struct compile_state *state)
-static int print_ipdominated(
- struct compile_state *state, struct block *block, int vertex)
+static void print_ipdominated(
+ struct compile_state *state, struct block *block, void *arg)
{
struct block_set *user;
+ FILE *fp = arg;
- if (!block || (block->vertex != vertex + 1)) {
- return vertex;
- }
- vertex += 1;
-
- printf("%d:", block->vertex);
+ fprintf(fp, "%d:", block->vertex);
for(user = block->ipdominates; user; user = user->next) {
- printf(" %d", user->member->vertex);
+ fprintf(fp, " %d", user->member->vertex);
if (user->member->ipdom != block) {
internal_error(state, user->member->first, "bad ipdom");
}
}
- printf("\n");
- for(user = block->use; user; user = user->next) {
- vertex = print_ipdominated(state, user->member, vertex);
- }
- return vertex;
+ fprintf(fp, "\n");
}
-static void print_ipdominators(struct compile_state *state)
+static void print_ipdominators(struct compile_state *state, FILE *fp)
{
- printf("\nipdominates\n");
- print_ipdominated(state, state->last_block, 0);
+ fprintf(fp, "\nipdominates\n");
+ walk_blocks(state, print_ipdominated, fp);
}
static int print_pfrontiers(
@@ -9442,12 +9770,63 @@ static void analyze_ipdominators(struct compile_state *state)
find_block_ipdomf(state, state->last_block);
/* If debuging print the print what I have just found */
if (state->debug & DEBUG_RDOMINATORS) {
- print_ipdominators(state);
+ print_ipdominators(state, stdout);
print_ipdominance_frontiers(state);
print_control_flow(state);
}
}
+static int bdominates(struct compile_state *state,
+ struct block *dom, struct block *sub)
+{
+ while(sub && (sub != dom)) {
+ sub = sub->idom;
+ }
+ return sub == dom;
+}
+
+static int tdominates(struct compile_state *state,
+ struct triple *dom, struct triple *sub)
+{
+ struct block *bdom, *bsub;
+ int result;
+ bdom = block_of_triple(state, dom);
+ bsub = block_of_triple(state, sub);
+ if (bdom != bsub) {
+ result = bdominates(state, bdom, bsub);
+ }
+ else {
+ struct triple *ins;
+ ins = sub;
+ while((ins != bsub->first) && (ins != dom)) {
+ ins = ins->prev;
+ }
+ result = (ins == dom);
+ }
+ return result;
+}
+
+static int tdistance(struct compile_state *state,
+ struct triple *dom, struct triple *sub)
+{
+ int count;
+ struct block *bdom, *bsub;
+ if (!tdominates(state, dom, sub)) {
+ internal_error(state, 0, "dom does not dom sub");
+ }
+ bdom = block_of_triple(state, dom);
+ bsub = block_of_triple(state, sub);
+ count = 0;
+ for(; bsub != bdom; (bsub = bsub->idom), sub = bsub->last) {
+ for(; sub != bsub->first; sub = sub->prev) {
+ count++;
+ }
+ }
+ for(; sub != dom; sub = sub->prev) {
+ count++;
+ }
+ return count;
+}
static void insert_phi_operations(struct compile_state *state)
{
@@ -9505,7 +9884,7 @@ static void insert_phi_operations(struct compile_state *state)
in_edges = front->users;
/* Insert a phi function for this variable */
phi = alloc_triple(
- state, OP_PHI, var->type, in_edges,
+ state, OP_PHI, var->type, -1, in_edges,
front->first->filename,
front->first->line,
front->first->col);
@@ -9560,6 +9939,9 @@ static void fixup_block_phi_variables(
if (ptr->op == OP_PHI) {
struct triple *var, *val, **slot;
var = MISC(ptr, 0);
+ if (!var) {
+ internal_error(state, ptr, "no var???");
+ }
/* Find the current value of the variable */
val = var->use->member;
if ((val->op == OP_WRITE) || (val->op == OP_READ)) {
@@ -9715,13 +10097,51 @@ static void transform_to_ssa_form(struct compile_state *state)
insert_phi_operations(state);
#if 0
printf("@%s:%d\n", __FILE__, __LINE__);
- print_blocks(state);
+ print_blocks(state, stdout);
#endif
rename_block_variables(state, state->first_block);
prune_block_variables(state, state->first_block);
}
+static void clear_vertex(
+ struct compile_state *state, struct block *block, void *arg)
+{
+ block->vertex = 0;
+}
+
+static void mark_live_block(
+ struct compile_state *state, struct block *block, int *next_vertex)
+{
+ /* See if this is a block that has not been marked */
+ if (block->vertex != 0) {
+ return;
+ }
+ block->vertex = *next_vertex;
+ *next_vertex += 1;
+ if (triple_is_branch(state, block->last)) {
+ struct triple **targ;
+ targ = triple_targ(state, block->last, 0);
+ for(; targ; targ = triple_targ(state, block->last, targ)) {
+ if (!*targ) {
+ continue;
+ }
+ if (!triple_stores_block(state, *targ)) {
+ internal_error(state, 0, "bad targ");
+ }
+ mark_live_block(state, (*targ)->u.block, next_vertex);
+ }
+ }
+ else if (block->last->next != RHS(state->main_function, 0)) {
+ struct triple *ins;
+ ins = block->last->next;
+ if (!triple_stores_block(state, ins)) {
+ internal_error(state, 0, "bad block start");
+ }
+ mark_live_block(state, ins->u.block, next_vertex);
+ }
+}
+
static void transform_from_ssa_form(struct compile_state *state)
{
/* To get out of ssa form we insert moves on the incoming
@@ -9729,6 +10149,12 @@ static void transform_from_ssa_form(struct compile_state *state)
*/
struct triple *first;
struct triple *phi, *next;
+ int next_vertex;
+
+ /* Walk the control flow to see which blocks remain alive */
+ walk_blocks(state, clear_vertex, 0);
+ next_vertex = 1;
+ mark_live_block(state, state->first_block, &next_vertex);
/* Walk all of the operations to find the phi functions */
first = RHS(state->main_function, 0);
@@ -9737,7 +10163,8 @@ static void transform_from_ssa_form(struct compile_state *state)
struct block *block;
struct triple **slot;
struct triple *var, *read;
- int edge;
+ struct triple_set *use, *use_next;
+ int edge, used;
next = phi->next;
if (phi->op != OP_PHI) {
continue;
@@ -9745,6 +10172,24 @@ static void transform_from_ssa_form(struct compile_state *state)
block = phi->u.block;
slot = &RHS(phi, 0);
+ /* Forget uses from code in dead blocks */
+ for(use = phi->use; use; use = use_next) {
+ struct block *ublock;
+ struct triple **expr;
+ use_next = use->next;
+ ublock = block_of_triple(state, use->member);
+ if ((use->member == phi) || (ublock->vertex != 0)) {
+ continue;
+ }
+ expr = triple_rhs(state, use->member, 0);
+ for(; expr; expr = triple_rhs(state, use->member, expr)) {
+ if (*expr == phi) {
+ *expr = 0;
+ }
+ }
+ unuse_triple(phi, use->member);
+ }
+
/* A variable to replace the phi function */
var = post_triple(state, phi, OP_ADECL, phi->type, 0,0);
/* A read of the single value that is set into the variable */
@@ -9762,22 +10207,309 @@ static void transform_from_ssa_form(struct compile_state *state)
struct triple *val;
eblock = set->member;
val = slot[edge];
+ slot[edge] = 0;
unuse_triple(val, phi);
- if (val == phi) {
+ if (!val || (val == &zero_triple) ||
+ (block->vertex == 0) || (eblock->vertex == 0) ||
+ (val == phi) || (val == read)) {
continue;
}
-
+
move = post_triple(state,
val, OP_WRITE, phi->type, var, val);
use_triple(val, move);
use_triple(var, move);
+ }
+ /* See if there are any writers of var */
+ used = 0;
+ for(use = var->use; use; use = use->next) {
+ struct triple **expr;
+ expr = triple_lhs(state, use->member, 0);
+ for(; expr; expr = triple_lhs(state, use->member, expr)) {
+ if (*expr == var) {
+ used = 1;
+ }
+ }
+ }
+ /* If var is not used free it */
+ if (!used) {
+ unuse_triple(var, read);
+ free_triple(state, read);
+ free_triple(state, var);
}
+
+ /* Release the phi function */
release_triple(state, phi);
}
}
+
+/*
+ * Register conflict resolution
+ * =========================================================
+ */
+
+static struct reg_info find_def_color(
+ struct compile_state *state, struct triple *def)
+{
+ struct triple_set *set;
+ struct reg_info info;
+ info.reg = REG_UNSET;
+ info.regcm = 0;
+ if (!triple_is_def(state, def)) {
+ return info;
+ }
+ info = arch_reg_lhs(state, def, 0);
+ if (info.reg >= MAX_REGISTERS) {
+ info.reg = REG_UNSET;
+ }
+ for(set = def->use; set; set = set->next) {
+ struct reg_info tinfo;
+ int i;
+ i = find_rhs_use(state, set->member, def);
+ if (i < 0) {
+ continue;
+ }
+ tinfo = arch_reg_rhs(state, set->member, i);
+ if (tinfo.reg >= MAX_REGISTERS) {
+ tinfo.reg = REG_UNSET;
+ }
+ if ((tinfo.reg != REG_UNSET) &&
+ (info.reg != REG_UNSET) &&
+ (tinfo.reg != info.reg)) {
+ internal_error(state, def, "register conflict");
+ }
+ if ((info.regcm & tinfo.regcm) == 0) {
+ internal_error(state, def, "regcm conflict %x & %x == 0",
+ info.regcm, tinfo.regcm);
+ }
+ if (info.reg == REG_UNSET) {
+ info.reg = tinfo.reg;
+ }
+ info.regcm &= tinfo.regcm;
+ }
+ if (info.reg >= MAX_REGISTERS) {
+ internal_error(state, def, "register out of range");
+ }
+ return info;
+}
+
+static struct reg_info find_lhs_pre_color(
+ struct compile_state *state, struct triple *ins, int index)
+{
+ struct reg_info info;
+ int zlhs, zrhs, i;
+ zrhs = TRIPLE_RHS(ins->sizes);
+ zlhs = TRIPLE_LHS(ins->sizes);
+ if (!zlhs && triple_is_def(state, ins)) {
+ zlhs = 1;
+ }
+ if (index >= zlhs) {
+ internal_error(state, ins, "Bad lhs %d", index);
+ }
+ info = arch_reg_lhs(state, ins, index);
+ for(i = 0; i < zrhs; i++) {
+ struct reg_info rinfo;
+ rinfo = arch_reg_rhs(state, ins, i);
+ if ((info.reg == rinfo.reg) &&
+ (rinfo.reg >= MAX_REGISTERS)) {
+ struct reg_info tinfo;
+ tinfo = find_lhs_pre_color(state, RHS(ins, index), 0);
+ info.reg = tinfo.reg;
+ info.regcm &= tinfo.regcm;
+ break;
+ }
+ }
+ if (info.reg >= MAX_REGISTERS) {
+ info.reg = REG_UNSET;
+ }
+ return info;
+}
+
+static struct reg_info find_rhs_post_color(
+ struct compile_state *state, struct triple *ins, int index);
+
+static struct reg_info find_lhs_post_color(
+ struct compile_state *state, struct triple *ins, int index)
+{
+ struct triple_set *set;
+ struct reg_info info;
+ struct triple *lhs;
+#if 0
+ fprintf(stderr, "find_lhs_post_color(%p, %d)\n",
+ ins, index);
+#endif
+ if ((index == 0) && triple_is_def(state, ins)) {
+ lhs = ins;
+ }
+ else if (index < TRIPLE_LHS(ins->sizes)) {
+ lhs = LHS(ins, index);
+ }
+ else {
+ internal_error(state, ins, "Bad lhs %d", index);
+ lhs = 0;
+ }
+ info = arch_reg_lhs(state, ins, index);
+ if (info.reg >= MAX_REGISTERS) {
+ info.reg = REG_UNSET;
+ }
+ for(set = lhs->use; set; set = set->next) {
+ struct reg_info rinfo;
+ struct triple *user;
+ int zrhs, i;
+ user = set->member;
+ zrhs = TRIPLE_RHS(user->sizes);
+ for(i = 0; i < zrhs; i++) {
+ if (RHS(user, i) != lhs) {
+ continue;
+ }
+ rinfo = find_rhs_post_color(state, user, i);
+ if ((info.reg != REG_UNSET) &&
+ (rinfo.reg != REG_UNSET) &&
+ (info.reg != rinfo.reg)) {
+ internal_error(state, ins, "register conflict");
+ }
+ if ((info.regcm & rinfo.regcm) == 0) {
+ internal_error(state, ins, "regcm conflict %x & %x == 0",
+ info.regcm, rinfo.regcm);
+ }
+ if (info.reg == REG_UNSET) {
+ info.reg = rinfo.reg;
+ }
+ info.regcm &= rinfo.regcm;
+ }
+ }
+#if 0
+ fprintf(stderr, "find_lhs_post_color(%p, %d) -> ( %d, %x)\n",
+ ins, index, info.reg, info.regcm);
+#endif
+ return info;
+}
+
+static struct reg_info find_rhs_post_color(
+ struct compile_state *state, struct triple *ins, int index)
+{
+ struct reg_info info, rinfo;
+ int zlhs, i;
+#if 0
+ fprintf(stderr, "find_rhs_post_color(%p, %d)\n",
+ ins, index);
+#endif
+ rinfo = arch_reg_rhs(state, ins, index);
+ zlhs = TRIPLE_LHS(ins->sizes);
+ if (!zlhs && triple_is_def(state, ins)) {
+ zlhs = 1;
+ }
+ info = rinfo;
+ if (info.reg >= MAX_REGISTERS) {
+ info.reg = REG_UNSET;
+ }
+ for(i = 0; i < zlhs; i++) {
+ struct reg_info linfo;
+ linfo = arch_reg_lhs(state, ins, i);
+ if ((linfo.reg == rinfo.reg) &&
+ (linfo.reg >= MAX_REGISTERS)) {
+ struct reg_info tinfo;
+ tinfo = find_lhs_post_color(state, ins, i);
+ if (tinfo.reg >= MAX_REGISTERS) {
+ tinfo.reg = REG_UNSET;
+ }
+ info.regcm &= linfo.reg;
+ info.regcm &= tinfo.regcm;
+ if (info.reg != REG_UNSET) {
+ internal_error(state, ins, "register conflict");
+ }
+ if (info.regcm == 0) {
+ internal_error(state, ins, "regcm conflict");
+ }
+ info.reg = tinfo.reg;
+ }
+ }
+#if 0
+ fprintf(stderr, "find_rhs_post_color(%p, %d) -> ( %d, %x)\n",
+ ins, index, info.reg, info.regcm);
+#endif
+ return info;
+}
+
+static struct reg_info find_lhs_color(
+ struct compile_state *state, struct triple *ins, int index)
+{
+ struct reg_info pre, post, info;
+#if 0
+ fprintf(stderr, "find_lhs_color(%p, %d)\n",
+ ins, index);
+#endif
+ pre = find_lhs_pre_color(state, ins, index);
+ post = find_lhs_post_color(state, ins, index);
+ if ((pre.reg != post.reg) &&
+ (pre.reg != REG_UNSET) &&
+ (post.reg != REG_UNSET)) {
+ internal_error(state, ins, "register conflict");
+ }
+ info.regcm = pre.regcm & post.regcm;
+ info.reg = pre.reg;
+ if (info.reg == REG_UNSET) {
+ info.reg = post.reg;
+ }
+#if 0
+ fprintf(stderr, "find_lhs_color(%p, %d) -> ( %d, %x)\n",
+ ins, index, info.reg, info.regcm);
+#endif
+ return info;
+}
+
+static struct triple *post_copy(struct compile_state *state, struct triple *ins)
+{
+ struct triple_set *entry, *next;
+ struct triple *out;
+ struct reg_info info, rinfo;
+
+ info = arch_reg_lhs(state, ins, 0);
+ out = post_triple(state, ins, OP_COPY, ins->type, ins, 0);
+ use_triple(RHS(out, 0), out);
+ /* Get the users of ins to use out instead */
+ for(entry = ins->use; entry; entry = next) {
+ int i;
+ next = entry->next;
+ if (entry->member == out) {
+ continue;
+ }
+ i = find_rhs_use(state, entry->member, ins);
+ if (i < 0) {
+ continue;
+ }
+ rinfo = arch_reg_rhs(state, entry->member, i);
+ if ((info.reg == REG_UNNEEDED) && (rinfo.reg == REG_UNNEEDED)) {
+ continue;
+ }
+ replace_rhs_use(state, ins, out, entry->member);
+ }
+ transform_to_arch_instruction(state, out);
+ return out;
+}
+
+static struct triple *pre_copy(
+ struct compile_state *state, struct triple *ins, int index)
+{
+ /* Carefully insert enough operations so that I can
+ * enter any operation with a GPR32.
+ */
+ struct triple *in;
+ struct triple **expr;
+ expr = &RHS(ins, index);
+ in = pre_triple(state, ins, OP_COPY, (*expr)->type, *expr, 0);
+ unuse_triple(*expr, ins);
+ *expr = in;
+ use_triple(RHS(in, 0), in);
+ use_triple(in, ins);
+ transform_to_arch_instruction(state, in);
+ return in;
+}
+
+
static void insert_copies_to_phi(struct compile_state *state)
{
/* To get out of ssa form we insert moves on the incoming
@@ -9796,10 +10528,7 @@ static void insert_copies_to_phi(struct compile_state *state)
if (phi->op != OP_PHI) {
continue;
}
- if (ID_REG(phi->id) == REG_UNSET) {
- phi->id = MK_REG_ID(alloc_virtual_reg(),
- ID_REG_CLASSES(phi->id));
- }
+ phi->id |= TRIPLE_FLAG_POST_SPLIT;
block = phi->u.block;
slot = &RHS(phi, 0);
/* Walk all of the incoming edges/blocks and insert moves.
@@ -9819,7 +10548,7 @@ static void insert_copies_to_phi(struct compile_state *state)
move = build_triple(state, OP_COPY, phi->type, val, 0,
val->filename, val->line, val->col);
move->u.block = eblock;
- move->id = phi->id;
+ move->id |= TRIPLE_FLAG_PRE_SPLIT;
use_triple(val, move);
slot[edge] = move;
@@ -9850,6 +10579,7 @@ static void insert_copies_to_phi(struct compile_state *state)
if (eblock->last == ptr) {
eblock->last = move;
}
+ transform_to_arch_instruction(state, move);
}
}
}
@@ -10070,10 +10800,6 @@ static int use_in(struct compile_state *state, struct reg_block *rb)
break;
}
}
- /* If the triple is not a definition skip it. */
- if (!triple_is_def(state, ptr)) {
- continue;
- }
/* If I still have a valid rhs add it to in */
change |= in_triple(rb, rhs);
}
@@ -10163,22 +10889,33 @@ static void walk_variable_lifetimes(struct compile_state *state,
}
/* Walk through the basic block calculating live */
for(done = 0, ptr = block->last; !done; ptr = prev) {
- struct triple **expr;
+ struct triple **expr, *result;
prev = ptr->prev;
done = (ptr == block->first);
+
+ /* Ensure the current definition is in live */
+ if (triple_is_def(state, ptr)) {
+ do_triple_set(&live, ptr, 0);
+ }
+
+ /* Inform the callback function of what is
+ * going on.
+ */
+ result = cb(state, blocks, live, rb, ptr, arg);
/* Remove the current definition from live */
do_triple_unset(&live, ptr);
-
+
/* If the current instruction was deleted continue */
- if (!cb(state, blocks, live, rb, ptr, arg)) {
+ if (!result) {
if (block->last == ptr) {
block->last = prev;
}
continue;
}
+
/* Add the current uses to live.
*
* It is safe to skip phi functions because they do
@@ -10197,15 +10934,6 @@ static void walk_variable_lifetimes(struct compile_state *state,
}
do_triple_set(&live, *expr, 0);
}
- expr = triple_lhs(state, ptr, 0);
- for(;expr; expr = triple_lhs(state, ptr, expr)) {
- /* If the triple is not a definition skip it. */
- if (!*expr || !triple_is_def(state, *expr)) {
- continue;
- }
- do_triple_set(&live, *expr, 0);
- }
-
}
/* Free live */
for(entry = live; entry; entry = next) {
@@ -10327,6 +11055,10 @@ static void eliminate_inefectual_code(struct compile_state *state)
expr = triple_lhs(state, dt->triple, expr);
awaken(state, dtriple, expr, &work_list_tail);
} while(expr);
+ do {
+ expr = triple_misc(state, dt->triple, expr);
+ awaken(state, dtriple, expr, &work_list_tail);
+ } while(expr);
/* Wake up the forward control dependencies */
do {
expr = triple_targ(state, dt->triple, expr);
@@ -10358,13 +11090,164 @@ static void eliminate_inefectual_code(struct compile_state *state)
}
+static void insert_mandatory_copies(struct compile_state *state)
+{
+ struct triple *ins, *first;
+
+ /* The object is with a minimum of inserted copies,
+ * to resolve in fundamental register conflicts between
+ * register value producers and consumers.
+ * Theoretically we may be greater than minimal when we
+ * are inserting copies before instructions but that
+ * case should be rare.
+ */
+ first = RHS(state->main_function, 0);
+ ins = first;
+ do {
+ struct triple_set *entry, *next;
+ struct triple *tmp;
+ struct reg_info info;
+ unsigned reg, regcm;
+ int do_post_copy, do_pre_copy;
+ tmp = 0;
+ if (!triple_is_def(state, ins)) {
+ goto next;
+ }
+ /* Find the architecture specific color information */
+ info = arch_reg_lhs(state, ins, 0);
+ if (info.reg >= MAX_REGISTERS) {
+ info.reg = REG_UNSET;
+ }
+
+ reg = REG_UNSET;
+ regcm = arch_type_to_regcm(state, ins->type);
+ do_post_copy = do_pre_copy = 0;
+
+ /* Walk through the uses of ins and check for conflicts */
+ for(entry = ins->use; entry; entry = next) {
+ struct reg_info rinfo;
+ int i;
+ next = entry->next;
+ i = find_rhs_use(state, entry->member, ins);
+ if (i < 0) {
+ continue;
+ }
+
+ /* Find the users color requirements */
+ rinfo = arch_reg_rhs(state, entry->member, i);
+ if (rinfo.reg >= MAX_REGISTERS) {
+ rinfo.reg = REG_UNSET;
+ }
+
+ /* See if I need a pre_copy */
+ if (rinfo.reg != REG_UNSET) {
+ if ((reg != REG_UNSET) && (reg != rinfo.reg)) {
+ do_pre_copy = 1;
+ }
+ reg = rinfo.reg;
+ }
+ regcm &= rinfo.regcm;
+ regcm = arch_regcm_normalize(state, regcm);
+ if (regcm == 0) {
+ do_pre_copy = 1;
+ }
+ }
+ do_post_copy =
+ !do_pre_copy &&
+ (((info.reg != REG_UNSET) &&
+ (reg != REG_UNSET) &&
+ (info.reg != reg)) ||
+ ((info.regcm & regcm) == 0));
+
+ reg = info.reg;
+ regcm = info.regcm;
+ /* Walk through the uses of insert and do a pre_copy or see if a post_copy is warranted */
+ for(entry = ins->use; entry; entry = next) {
+ struct reg_info rinfo;
+ int i;
+ next = entry->next;
+ i = find_rhs_use(state, entry->member, ins);
+ if (i < 0) {
+ continue;
+ }
+
+ /* Find the users color requirements */
+ rinfo = arch_reg_rhs(state, entry->member, i);
+ if (rinfo.reg >= MAX_REGISTERS) {
+ rinfo.reg = REG_UNSET;
+ }
+
+ /* Now see if it is time to do the pre_copy */
+ if (rinfo.reg != REG_UNSET) {
+ if (((reg != REG_UNSET) && (reg != rinfo.reg)) ||
+ ((regcm & rinfo.regcm) == 0) ||
+ /* Don't let a mandatory coalesce sneak
+ * into a operation that is marked to prevent
+ * coalescing.
+ */
+ ((reg != REG_UNNEEDED) &&
+ ((ins->id & TRIPLE_FLAG_POST_SPLIT) ||
+ (entry->member->id & TRIPLE_FLAG_PRE_SPLIT)))
+ ) {
+ if (do_pre_copy) {
+ struct triple *user;
+ user = entry->member;
+ if (RHS(user, i) != ins) {
+ internal_error(state, user, "bad rhs");
+ }
+ tmp = pre_copy(state, user, i);
+ continue;
+ } else {
+ do_post_copy = 1;
+ }
+ }
+ reg = rinfo.reg;
+ }
+ if ((regcm & rinfo.regcm) == 0) {
+ if (do_pre_copy) {
+ struct triple *user;
+ user = entry->member;
+ if (RHS(user, i) != ins) {
+ internal_error(state, user, "bad rhs");
+ }
+ tmp = pre_copy(state, user, i);
+ continue;
+ } else {
+ do_post_copy = 1;
+ }
+ }
+ regcm &= rinfo.regcm;
+
+ }
+ if (do_post_copy) {
+ struct reg_info pre, post;
+ tmp = post_copy(state, ins);
+ pre = arch_reg_lhs(state, ins, 0);
+ post = arch_reg_lhs(state, tmp, 0);
+ if ((pre.reg == post.reg) && (pre.regcm == post.regcm)) {
+ internal_error(state, tmp, "useless copy");
+ }
+ }
+ next:
+ ins = ins->next;
+ } while(ins != first);
+}
+
+
struct live_range_edge;
+struct live_range_def;
struct live_range {
struct live_range_edge *edges;
- struct triple *def;
+ struct live_range_def *defs;
+/* Note. The list pointed to by defs is kept in order.
+ * That is baring splits in the flow control
+ * defs dominates defs->next wich dominates defs->next->next
+ * etc.
+ */
unsigned color;
unsigned classes;
unsigned degree;
+ unsigned length;
struct live_range *group_next, **group_prev;
};
@@ -10373,6 +11256,14 @@ struct live_range_edge {
struct live_range *node;
};
+struct live_range_def {
+ struct live_range_def *next;
+ struct live_range_def *prev;
+ struct live_range *lr;
+ struct triple *def;
+ unsigned orig_id;
+};
+
#define LRE_HASH_SIZE 2048
struct lre_hash {
struct lre_hash *next;
@@ -10384,10 +11275,14 @@ struct lre_hash {
struct reg_state {
struct lre_hash *hash[LRE_HASH_SIZE];
struct reg_block *blocks;
+ struct live_range_def *lrd;
struct live_range *lr;
struct live_range *low, **low_tail;
struct live_range *high, **high_tail;
+ unsigned defs;
unsigned ranges;
+ int passes, max_passes;
+#define MAX_ALLOCATION_PASSES 100
};
@@ -10431,6 +11326,9 @@ static void reg_fill_used(struct compile_state *state, char *used, int reg)
{
unsigned equivs[MAX_REG_EQUIVS];
int i;
+ if (reg == REG_UNNEEDED) {
+ return;
+ }
arch_reg_equivs(state, equivs, reg);
for(i = 0; (i < MAX_REG_EQUIVS) && equivs[i] != REG_UNSET; i++) {
used[equivs[i]] = 1;
@@ -10438,6 +11336,20 @@ static void reg_fill_used(struct compile_state *state, char *used, int reg)
return;
}
+static void reg_inc_used(struct compile_state *state, char *used, int reg)
+{
+ unsigned equivs[MAX_REG_EQUIVS];
+ int i;
+ if (reg == REG_UNNEEDED) {
+ return;
+ }
+ arch_reg_equivs(state, equivs, reg);
+ for(i = 0; (i < MAX_REG_EQUIVS) && equivs[i] != REG_UNSET; i++) {
+ used[equivs[i]] += 1;
+ }
+ return;
+}
+
static unsigned int hash_live_edge(
struct live_range *left, struct live_range *right)
{
@@ -10613,104 +11525,264 @@ static void different_colored(
{
struct live_range *lr;
struct triple **expr;
- lr = &rstate->lr[ins->id];
+ lr = rstate->lrd[ins->id].lr;
expr = triple_rhs(state, ins, 0);
for(;expr; expr = triple_rhs(state, ins, expr)) {
struct live_range *lr2;
if (!*expr || (*expr == parent) || (*expr == ins)) {
continue;
}
- lr2 = &rstate->lr[(*expr)->id];
+ lr2 = rstate->lrd[(*expr)->id].lr;
if (lr->color == lr2->color) {
internal_error(state, ins, "live range too big");
}
}
}
+
+static struct live_range *coalesce_ranges(
+ struct compile_state *state, struct reg_state *rstate,
+ struct live_range *lr1, struct live_range *lr2)
+{
+ struct live_range_def *head, *mid1, *mid2, *end, *lrd;
+ unsigned color;
+ unsigned classes;
+ if (lr1 == lr2) {
+ return lr1;
+ }
+ if (!lr1->defs || !lr2->defs) {
+ internal_error(state, 0,
+ "cannot coalese dead live ranges");
+ }
+ if ((lr1->color == REG_UNNEEDED) ||
+ (lr2->color == REG_UNNEEDED)) {
+ internal_error(state, 0,
+ "cannot coalesce live ranges without a possible color");
+ }
+ if ((lr1->color != lr2->color) &&
+ (lr1->color != REG_UNSET) &&
+ (lr2->color != REG_UNSET)) {
+ internal_error(state, lr1->defs->def,
+ "cannot coalesce live ranges of different colors");
+ }
+ color = lr1->color;
+ if (color == REG_UNSET) {
+ color = lr2->color;
+ }
+ classes = lr1->classes & lr2->classes;
+ if (!classes) {
+ internal_error(state, lr1->defs->def,
+ "cannot coalesce live ranges with dissimilar register classes");
+ }
+ /* 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
+ * them.
+ */
+ if ((lr1->defs->prev->def->op == OP_PHI) ||
+ ((lr2->defs->prev->def->op != OP_PHI) &&
+ tdominates(state, lr2->defs->def, lr1->defs->def))) {
+ struct live_range *tmp;
+ tmp = lr1;
+ lr1 = lr2;
+ lr2 = tmp;
+ }
+#if 0
+ if (lr1->defs->orig_id & TRIPLE_FLAG_POST_SPLIT) {
+ fprintf(stderr, "lr1 post\n");
+ }
+ if (lr1->defs->orig_id & TRIPLE_FLAG_PRE_SPLIT) {
+ fprintf(stderr, "lr1 pre\n");
+ }
+ if (lr2->defs->orig_id & TRIPLE_FLAG_POST_SPLIT) {
+ fprintf(stderr, "lr2 post\n");
+ }
+ if (lr2->defs->orig_id & TRIPLE_FLAG_PRE_SPLIT) {
+ fprintf(stderr, "lr2 pre\n");
+ }
+#endif
+#if 0
+ fprintf(stderr, "coalesce color1(%p): %3d color2(%p) %3d\n",
+ lr1->defs->def,
+ lr1->color,
+ lr2->defs->def,
+ lr2->color);
+#endif
+
+ lr1->classes = classes;
+ /* Append lr2 onto lr1 */
+#warning "FIXME should this be a merge instead of a splice?"
+ head = lr1->defs;
+ mid1 = lr1->defs->prev;
+ mid2 = lr2->defs;
+ end = lr2->defs->prev;
+
+ head->prev = end;
+ end->next = head;
+
+ mid1->next = mid2;
+ mid2->prev = mid1;
+
+ /* Fixup the live range in the added live range defs */
+ lrd = head;
+ do {
+ lrd->lr = lr1;
+ lrd = lrd->next;
+ } while(lrd != head);
+
+ /* Mark lr2 as free. */
+ lr2->defs = 0;
+ lr2->color = REG_UNNEEDED;
+ lr2->classes = 0;
+
+ if (!lr1->defs) {
+ internal_error(state, 0, "lr1->defs == 0 ?");
+ }
+
+ lr1->color = color;
+ lr1->classes = classes;
+
+ return lr1;
+}
+
+static struct live_range_def *live_range_head(
+ struct compile_state *state, struct live_range *lr,
+ struct live_range_def *last)
+{
+ struct live_range_def *result;
+ result = 0;
+ if (last == 0) {
+ result = lr->defs;
+ }
+ else if (!tdominates(state, lr->defs->def, last->next->def)) {
+ result = last->next;
+ }
+ return result;
+}
+
+static struct live_range_def *live_range_end(
+ struct compile_state *state, struct live_range *lr,
+ struct live_range_def *last)
+{
+ struct live_range_def *result;
+ result = 0;
+ if (last == 0) {
+ result = lr->defs->prev;
+ }
+ else if (!tdominates(state, last->prev->def, lr->defs->prev->def)) {
+ result = last->prev;
+ }
+ return result;
+}
+
+
static void initialize_live_ranges(
struct compile_state *state, struct reg_state *rstate)
{
struct triple *ins, *first;
- size_t size;
- int i;
+ size_t count, size;
+ int i, j;
first = RHS(state->main_function, 0);
- /* First count how many live ranges I will need.
+ /* First count how many instructions I have.
+ */
+ count = count_triples(state);
+ /* Potentially I need one live range definitions for each
+ * instruction, plus an extra for the split routines.
*/
- rstate->ranges = count_triples(state);
- size = sizeof(rstate->lr[0]) * (rstate->ranges + 1);
- rstate->lr = xcmalloc(size, "live_range");
+ rstate->defs = count + 1;
+ /* Potentially I need one live range for each instruction
+ * plus an extra for the dummy live range.
+ */
+ rstate->ranges = count + 1;
+ size = sizeof(rstate->lrd[0]) * rstate->defs;
+ rstate->lrd = xcmalloc(size, "live_range_def");
+ size = sizeof(rstate->lr[0]) * rstate->ranges;
+ rstate->lr = xcmalloc(size, "live_range");
+
/* Setup the dummy live range */
rstate->lr[0].classes = 0;
rstate->lr[0].color = REG_UNSET;
- rstate->lr[0].def = 0;
- i = 0;
+ rstate->lr[0].defs = 0;
+ i = j = 0;
ins = first;
do {
- unsigned color, classes;
- /* Find the architecture specific color information */
- color = ID_REG(ins->id);
- classes = ID_REG_CLASSES(ins->id);
- if ((color != REG_UNSET) && (color < MAX_REGISTERS)) {
- classes = arch_reg_regcm(state, color);
- }
-
- /* If the triple is a variable definition give it a live range. */
+ /* If the triple is a variable give it a live range */
if (triple_is_def(state, ins)) {
+ struct reg_info info;
+ /* Find the architecture specific color information */
+ info = find_def_color(state, ins);
+
i++;
- ins->id = i;
- rstate->lr[i].def = ins;
- rstate->lr[i].color = color;
- rstate->lr[i].classes = classes;
+ rstate->lr[i].defs = &rstate->lrd[j];
+ rstate->lr[i].color = info.reg;
+ rstate->lr[i].classes = info.regcm;
rstate->lr[i].degree = 0;
- if (!classes) {
- internal_error(state, ins,
- "live range without a class");
- }
- }
+ rstate->lrd[j].lr = &rstate->lr[i];
+ }
/* Otherwise give the triple the dummy live range. */
else {
- ins->id = 0;
+ rstate->lrd[j].lr = &rstate->lr[0];
}
+
+ /* Initalize the live_range_def */
+ rstate->lrd[j].next = &rstate->lrd[j];
+ rstate->lrd[j].prev = &rstate->lrd[j];
+ rstate->lrd[j].def = ins;
+ rstate->lrd[j].orig_id = ins->id;
+ ins->id = j;
+
+ j++;
ins = ins->next;
} while(ins != first);
rstate->ranges = i;
+ rstate->defs -= 1;
+
/* Make a second pass to handle achitecture specific register
* constraints.
*/
ins = first;
do {
- struct live_range *lr;
- lr = &rstate->lr[ins->id];
- if (lr->color != REG_UNSET) {
- struct triple **expr;
- /* This assumes the virtual register is only
- * used by one input operation.
- */
- expr = triple_rhs(state, ins, 0);
- for(;expr; expr = triple_rhs(state, ins, expr)) {
- struct live_range *lr2;
- if (!*expr || (ins == *expr)) {
+ int zlhs, zrhs, i, j;
+ if (ins->id > rstate->defs) {
+ internal_error(state, ins, "bad id");
+ }
+
+ /* Walk through the template of ins and coalesce live ranges */
+ zlhs = TRIPLE_LHS(ins->sizes);
+ if ((zlhs == 0) && triple_is_def(state, ins)) {
+ zlhs = 1;
+ }
+ zrhs = TRIPLE_RHS(ins->sizes);
+
+ for(i = 0; i < zlhs; i++) {
+ struct reg_info linfo;
+ struct live_range_def *lhs;
+ linfo = arch_reg_lhs(state, ins, i);
+ if (linfo.reg < MAX_REGISTERS) {
+ continue;
+ }
+ if (triple_is_def(state, ins)) {
+ lhs = &rstate->lrd[ins->id];
+ } else {
+ lhs = &rstate->lrd[LHS(ins, i)->id];
+ }
+ for(j = 0; j < zrhs; j++) {
+ struct reg_info rinfo;
+ struct live_range_def *rhs;
+ rinfo = arch_reg_rhs(state, ins, j);
+ if (rinfo.reg < MAX_REGISTERS) {
continue;
}
- lr2 = &rstate->lr[(*expr)->id];
- if (lr->color == lr2->color) {
- different_colored(state, rstate,
- ins, *expr);
- (*expr)->id = ins->id;
-
+ rhs = &rstate->lrd[RHS(ins, i)->id];
+ if (rinfo.reg == linfo.reg) {
+ coalesce_ranges(state, rstate,
+ lhs->lr, rhs->lr);
}
}
}
ins = ins->next;
} while(ins != first);
-
- /* Make a third pass and forget the virtual registers */
- for(i = 1; i <= rstate->ranges; i++) {
- if (rstate->lr[i].color >= MAX_REGISTERS) {
- rstate->lr[i].color = REG_UNSET;
- }
- }
}
static struct triple *graph_ins(
@@ -10722,14 +11794,14 @@ static struct triple *graph_ins(
struct live_range *def;
struct triple_reg_set *entry;
- /* If the triple does not start a live range
+ /* If the triple is not a definition
* we do not have a definition to add to
* the interference graph.
*/
- if (ins->id <= 0) {
+ if (!triple_is_def(state, ins)) {
return ins;
}
- def = &rstate->lr[ins->id];
+ def = rstate->lrd[ins->id].lr;
/* Create an edge between ins and everything that is
* alive, unless the live_range cannot share
@@ -10737,7 +11809,13 @@ static struct triple *graph_ins(
*/
for(entry = live; entry; entry = entry->next) {
struct live_range *lr;
- lr= &rstate->lr[entry->member->id];
+ if ((entry->member->id < 0) || (entry->member->id > rstate->defs)) {
+ internal_error(state, 0, "bad entry?");
+ }
+ lr = rstate->lrd[entry->member->id].lr;
+ if (def == lr) {
+ continue;
+ }
if (!arch_regcm_intersect(def->classes, lr->classes)) {
continue;
}
@@ -10755,8 +11833,19 @@ static struct triple *print_interference_ins(
struct reg_state *rstate = arg;
struct live_range *lr;
- lr = &rstate->lr[ins->id];
+ lr = rstate->lrd[ins->id].lr;
display_triple(stdout, ins);
+
+ if (lr->defs) {
+ struct live_range_def *lrd;
+ printf(" range:");
+ lrd = lr->defs;
+ do {
+ printf(" %-10p", lrd->def);
+ lrd = lrd->next;
+ } while(lrd != lr->defs);
+ printf("\n");
+ }
if (live) {
struct triple_reg_set *entry;
printf(" live:");
@@ -10767,9 +11856,15 @@ static struct triple *print_interference_ins(
}
if (lr->edges) {
struct live_range_edge *entry;
- printf(" edges:");
+ printf(" edges:");
for(entry = lr->edges; entry; entry = entry->next) {
- printf(" %-10p", entry->node->def);
+ struct live_range_def *lrd;
+ lrd = entry->node->defs;
+ do {
+ printf(" %-10p", lrd->def);
+ lrd = lrd->next;
+ } while(lrd != entry->node->defs);
+ printf("|");
}
printf("\n");
}
@@ -10779,6 +11874,517 @@ static struct triple *print_interference_ins(
return ins;
}
+static int coalesce_live_ranges(
+ struct compile_state *state, struct reg_state *rstate)
+{
+ /* At the point where a value is moved from one
+ * register to another that value requires two
+ * registers, thus increasing register pressure.
+ * Live range coaleescing reduces the register
+ * pressure by keeping a value in one register
+ * longer.
+ *
+ * In the case of a phi function all paths leading
+ * into it must be allocated to the same register
+ * otherwise the phi function may not be removed.
+ *
+ * Forcing a value to stay in a single register
+ * for an extended period of time does have
+ * limitations when applied to non homogenous
+ * register pool.
+ *
+ * The two cases I have identified are:
+ * 1) Two forced register assignments may
+ * collide.
+ * 2) Registers may go unused because they
+ * are only good for storing the value
+ * and not manipulating it.
+ *
+ * Because of this I need to split live ranges,
+ * even outside of the context of coalesced live
+ * ranges. The need to split live ranges does
+ * impose some constraints on live range coalescing.
+ *
+ * - Live ranges may not be coalesced across phi
+ * functions. This creates a 2 headed live
+ * range that cannot be sanely split.
+ *
+ * - phi functions (coalesced in initialize_live_ranges)
+ * are handled as pre split live ranges so we will
+ * never attempt to split them.
+ */
+ int coalesced;
+ int i;
+
+ coalesced = 0;
+ for(i = 0; i <= rstate->ranges; i++) {
+ struct live_range *lr1;
+ struct live_range_def *lrd1;
+ lr1 = &rstate->lr[i];
+ if (!lr1->defs) {
+ continue;
+ }
+ lrd1 = live_range_end(state, lr1, 0);
+ for(; lrd1; lrd1 = live_range_end(state, lr1, lrd1)) {
+ struct triple_set *set;
+ if (lrd1->def->op != OP_COPY) {
+ continue;
+ }
+ /* Skip copies that are the result of a live range split. */
+ if (lrd1->orig_id & TRIPLE_FLAG_POST_SPLIT) {
+ continue;
+ }
+ for(set = lrd1->def->use; set; set = set->next) {
+ struct live_range_def *lrd2;
+ struct live_range *lr2, *res;
+
+ lrd2 = &rstate->lrd[set->member->id];
+
+ /* Don't coalesce with instructions
+ * that are the result of a live range
+ * split.
+ */
+ if (lrd2->orig_id & TRIPLE_FLAG_PRE_SPLIT) {
+ continue;
+ }
+ lr2 = rstate->lrd[set->member->id].lr;
+ if (lr1 == lr2) {
+ continue;
+ }
+ if ((lr1->color != lr2->color) &&
+ (lr1->color != REG_UNSET) &&
+ (lr2->color != REG_UNSET)) {
+ continue;
+ }
+ if ((lr1->classes & lr2->classes) == 0) {
+ continue;
+ }
+
+ if (interfere(rstate, lr1, lr2)) {
+ continue;
+ }
+
+ res = coalesce_ranges(state, rstate, lr1, lr2);
+ coalesced += 1;
+ if (res != lr1) {
+ goto next;
+ }
+ }
+ }
+ next:
+ }
+ return coalesced;
+}
+
+
+struct coalesce_conflict {
+ struct triple *ins;
+ int index;
+};
+static struct triple *spot_coalesce_conflict(struct compile_state *state,
+ struct reg_block *blocks, struct triple_reg_set *live,
+ struct reg_block *rb, struct triple *ins, void *arg)
+{
+ struct coalesce_conflict *conflict = arg;
+ int zlhs, zrhs, i, j;
+ int found;
+
+ /* See if we have a mandatory coalesce operation between
+ * a lhs and a rhs value. If so and the rhs value is also
+ * alive then this triple needs to be pre copied. Otherwise
+ * we would have two definitions in the same live range simultaneously
+ * alive.
+ */
+ found = -1;
+ zlhs = TRIPLE_LHS(ins->sizes);
+ if ((zlhs == 0) && triple_is_def(state, ins)) {
+ zlhs = 1;
+ }
+ zrhs = TRIPLE_RHS(ins->sizes);
+ for(i = 0; (i < zlhs) && (found == -1); i++) {
+ struct reg_info linfo;
+ linfo = arch_reg_lhs(state, ins, i);
+ if (linfo.reg < MAX_REGISTERS) {
+ continue;
+ }
+ for(j = 0; (j < zrhs) && (found == -1); j++) {
+ struct reg_info rinfo;
+ struct triple *rhs;
+ struct triple_reg_set *set;
+ rinfo = arch_reg_rhs(state, ins, j);
+ if (rinfo.reg != linfo.reg) {
+ continue;
+ }
+ rhs = RHS(ins, j);
+ for(set = live; set && (found == -1); set = set->next) {
+ if (set->member == rhs) {
+ found = j;
+ }
+ }
+ }
+ }
+ /* Only update conflict if we are the least dominated conflict */
+ if ((found != -1) &&
+ (!conflict->ins || tdominates(state, ins, conflict->ins))) {
+ conflict->ins = ins;
+ conflict->index = found;
+ }
+ return ins;
+}
+
+static void resolve_coalesce_conflict(
+ struct compile_state *state, struct coalesce_conflict *conflict)
+{
+ struct triple *copy;
+ copy = pre_copy(state, conflict->ins, conflict->index);
+ copy->id |= TRIPLE_FLAG_PRE_SPLIT;
+}
+
+
+static struct triple *spot_tangle(struct compile_state *state,
+ struct reg_block *blocks, struct triple_reg_set *live,
+ struct reg_block *rb, struct triple *ins, void *arg)
+{
+ struct triple **tangle = arg;
+ char used[MAX_REGISTERS];
+ struct triple_reg_set *set;
+
+ /* Find out which registers have multiple uses at this point */
+ memset(used, 0, sizeof(used));
+ for(set = live; set; set = set->next) {
+ struct reg_info info;
+ info = find_lhs_color(state, set->member, 0);
+ if (info.reg == REG_UNSET) {
+ continue;
+ }
+ reg_inc_used(state, used, info.reg);
+ }
+
+ /* Now find the least dominated definition of a register in
+ * conflict I have seen so far.
+ */
+ for(set = live; set; set = set->next) {
+ struct reg_info info;
+ info = find_lhs_color(state, set->member, 0);
+ if (used[info.reg] < 2) {
+ continue;
+ }
+ if (!*tangle || tdominates(state, set->member, *tangle)) {
+ *tangle = set->member;
+ }
+ }
+ return ins;
+}
+
+static void resolve_tangle(struct compile_state *state, struct triple *tangle)
+{
+ struct reg_info info, uinfo;
+ struct triple_set *set, *next;
+ struct triple *copy;
+
+#if 0
+ fprintf(stderr, "Resolving tangle: %p\n", tangle);
+ print_blocks(state, stderr);
+#endif
+ info = find_lhs_color(state, tangle, 0);
+#if 0
+ fprintf(stderr, "color: %d\n", info.reg);
+#endif
+ for(set = tangle->use; set; set = next) {
+ struct triple *user;
+ int i, zrhs;
+ next = set->next;
+ user = set->member;
+ zrhs = TRIPLE_RHS(user->sizes);
+ for(i = 0; i < zrhs; i++) {
+ if (RHS(user, i) != tangle) {
+ continue;
+ }
+ uinfo = find_rhs_post_color(state, user, i);
+#if 0
+ fprintf(stderr, "%p rhs %d color: %d\n",
+ user, i, uinfo.reg);
+#endif
+ if (uinfo.reg == info.reg) {
+ copy = pre_copy(state, user, i);
+ copy->id |= TRIPLE_FLAG_PRE_SPLIT;
+ }
+ }
+ }
+ uinfo = find_lhs_pre_color(state, tangle, 0);
+#if 0
+ fprintf(stderr, "pre color: %d\n", uinfo.reg);
+#endif
+ if (uinfo.reg == info.reg) {
+ copy = post_copy(state, tangle);
+ copy->id |= TRIPLE_FLAG_PRE_SPLIT;
+ }
+}
+
+
+struct least_conflict {
+ struct reg_state *rstate;
+ struct live_range *ref_range;
+ struct triple *ins;
+ struct triple_reg_set *live;
+ size_t count;
+};
+static struct triple *least_conflict(struct compile_state *state,
+ struct reg_block *blocks, struct triple_reg_set *live,
+ struct reg_block *rb, struct triple *ins, void *arg)
+{
+ struct least_conflict *conflict = arg;
+ struct live_range_edge *edge;
+ struct triple_reg_set *set;
+ size_t count;
+
+#warning "FIXME handle instructions with left hand sides..."
+ /* Only instructions that introduce a new definition
+ * can be the conflict instruction.
+ */
+ if (!triple_is_def(state, ins)) {
+ return ins;
+ }
+
+ /* See if live ranges at this instruction are a
+ * strict subset of the live ranges that are in conflict.
+ */
+ count = 0;
+ for(set = live; set; set = set->next) {
+ struct live_range *lr;
+ lr = conflict->rstate->lrd[set->member->id].lr;
+ for(edge = conflict->ref_range->edges; edge; edge = edge->next) {
+ if (edge->node == lr) {
+ break;
+ }
+ }
+ if (!edge && (lr != conflict->ref_range)) {
+ return ins;
+ }
+ count++;
+ }
+ if (count <= 1) {
+ return ins;
+ }
+
+ /* See if there is an uncolored member in this subset.
+ */
+ for(set = live; set; set = set->next) {
+ struct live_range *lr;
+ lr = conflict->rstate->lrd[set->member->id].lr;
+ if (lr->color == REG_UNSET) {
+ break;
+ }
+ }
+ if (!set && (conflict->ref_range != REG_UNSET)) {
+ return ins;
+ }
+
+
+ /* Find the instruction with the largest possible subset of
+ * conflict ranges and that dominates any other instruction
+ * with an equal sized set of conflicting ranges.
+ */
+ if ((count > conflict->count) ||
+ ((count == conflict->count) &&
+ tdominates(state, ins, conflict->ins))) {
+ struct triple_reg_set *next;
+ /* Remember the canidate instruction */
+ conflict->ins = ins;
+ conflict->count = count;
+ /* Free the old collection of live registers */
+ for(set = conflict->live; set; set = next) {
+ next = set->next;
+ do_triple_unset(&conflict->live, set->member);
+ }
+ conflict->live = 0;
+ /* Rember the registers that are alive but do not feed
+ * into or out of conflict->ins.
+ */
+ for(set = live; set; set = set->next) {
+ struct triple **expr;
+ if (set->member == ins) {
+ goto next;
+ }
+ expr = triple_rhs(state, ins, 0);
+ for(;expr; expr = triple_rhs(state, ins, expr)) {
+ if (*expr == set->member) {
+ goto next;
+ }
+ }
+ expr = triple_lhs(state, ins, 0);
+ for(; expr; expr = triple_lhs(state, ins, expr)) {
+ if (*expr == set->member) {
+ goto next;
+ }
+ }
+ do_triple_set(&conflict->live, set->member, set->new);
+ next:
+ }
+ }
+ return ins;
+}
+
+static void find_range_conflict(struct compile_state *state,
+ struct reg_state *rstate, char *used, struct live_range *ref_range,
+ struct least_conflict *conflict)
+{
+ /* there are 3 kinds ways conflicts can occure.
+ * 1) the life time of 2 values simply overlap.
+ * 2) the 2 values feed into the same instruction.
+ * 3) the 2 values feed into a phi function.
+ */
+
+ /* find the instruction where the problematic conflict comes
+ * into existance. that the instruction where all of
+ * the values are alive, and among such instructions it is
+ * the least dominated one.
+ *
+ * a value is alive an an instruction if either;
+ * 1) the value defintion dominates the instruction and there
+ * is a use at or after that instrction
+ * 2) the value definition feeds into a phi function in the
+ * same block as the instruction. and the phi function
+ * is at or after the instruction.
+ */
+ memset(conflict, 0, sizeof(*conflict));
+ conflict->rstate = rstate;
+ conflict->ref_range = ref_range;
+ conflict->ins = 0;
+ conflict->count = 0;
+ conflict->live = 0;
+ walk_variable_lifetimes(state, rstate->blocks, least_conflict, conflict);
+
+ if (!conflict->ins) {
+ internal_error(state, 0, "No conflict ins?");
+ }
+ if (!conflict->live) {
+ internal_error(state, 0, "No conflict live?");
+ }
+ return;
+}
+
+static struct triple *split_constrained_range(struct compile_state *state,
+ struct reg_state *rstate, char *used, struct least_conflict *conflict)
+{
+ unsigned constrained_size;
+ struct triple *new, *constrained;
+ struct triple_reg_set *cset;
+ /* Find a range that is having problems because it is
+ * artificially constrained.
+ */
+ constrained_size = ~0;
+ constrained = 0;
+ new = 0;
+ for(cset = conflict->live; cset; cset = cset->next) {
+ struct triple_set *set;
+ struct reg_info info;
+ unsigned classes;
+ unsigned cur_size, size;
+ /* Skip the live range that starts with conflict->ins */
+ if (cset->member == conflict->ins) {
+ continue;
+ }
+ /* Find how many registers this value can potentially
+ * be assigned to.
+ */
+ classes = arch_type_to_regcm(state, cset->member->type);
+ size = regc_max_size(state, classes);
+
+ /* Find how many registers we allow this value to
+ * be assigned to.
+ */
+ info = arch_reg_lhs(state, cset->member, 0);
+#warning "FIXME do I need a call to arch_reg_rhs around here somewhere?"
+ if ((info.reg == REG_UNSET) || (info.reg >= MAX_REGISTERS)) {
+ cur_size = regc_max_size(state, info.regcm);
+ } else {
+ cur_size = 1;
+ }
+ /* If this live_range feeds into conflict->ins
+ * splitting it is unlikely to help.
+ */
+ for(set = cset->member->use; set; set = set->next) {
+ if (set->member == conflict->ins) {
+ goto next;
+ }
+ }
+
+ /* If there is no difference between potential and
+ * actual register count there is nothing to do.
+ */
+ if (cur_size >= size) {
+ continue;
+ }
+ /* Of the constrained registers deal with the
+ * most constrained one first.
+ */
+ if (!constrained ||
+ (size < constrained_size)) {
+ constrained = cset->member;
+ constrained_size = size;
+ }
+ next:
+ }
+ if (constrained) {
+ new = post_copy(state, constrained);
+ new->id |= TRIPLE_FLAG_POST_SPLIT;
+ }
+ return new;
+}
+
+static int split_ranges(
+ struct compile_state *state, struct reg_state *rstate,
+ char *used, struct live_range *range)
+{
+ struct triple *new;
+
+ if ((range->color == REG_UNNEEDED) ||
+ (rstate->passes >= rstate->max_passes)) {
+ return 0;
+ }
+ new = 0;
+ /* If I can't allocate a register something needs to be split */
+ if (arch_select_free_register(state, used, range->classes) == REG_UNSET) {
+ struct least_conflict conflict;
+
+ /* Find where in the set of registers the conflict
+ * actually occurs.
+ */
+ find_range_conflict(state, rstate, used, range, &conflict);
+
+ /* If a range has been artifically constrained split it */
+ new = split_constrained_range(state, rstate, used, &conflict);
+
+ if (!new) {
+ /* Ideally I would split the live range that will not be used
+ * for the longest period of time in hopes that this will
+ * (a) allow me to spill a register or
+ * (b) allow me to place a value in another register.
+ *
+ * So far I don't have a test case for this, the resolving
+ * of mandatory constraints has solved all of my
+ * know issues. So I have choosen not to write any
+ * code until I cat get a better feel for cases where
+ * it would be useful to have.
+ *
+ */
+#warning "WISHLIST implement live range splitting..."
+ return 0;
+ }
+ }
+ if (new) {
+ rstate->lrd[rstate->defs].orig_id = new->id;
+ new->id = rstate->defs;
+ rstate->defs++;
+#if 0
+ fprintf(stderr, "new: %p\n", new);
+#endif
+ return 1;
+ }
+ return 0;
+}
+
#if DEBUG_COLOR_GRAPH > 1
#define cgdebug_printf(...) fprintf(stdout, __VA_ARGS__)
#define cgdebug_flush() fflush(stdout)
@@ -10790,19 +12396,17 @@ static struct triple *print_interference_ins(
#define cgdebug_flush()
#endif
-static void select_free_color(struct compile_state *state,
+
+static int select_free_color(struct compile_state *state,
struct reg_state *rstate, struct live_range *range)
{
struct triple_set *entry;
- struct live_range *phi;
+ struct live_range_def *lrd;
+ struct live_range_def *phi;
struct live_range_edge *edge;
char used[MAX_REGISTERS];
struct triple **expr;
- /* If a color is already assigned don't change it */
- if (range->color != REG_UNSET) {
- return;
- }
/* Instead of doing just the trivial color select here I try
* a few extra things because a good color selection will help reduce
* copies.
@@ -10835,39 +12439,74 @@ static void select_free_color(struct compile_state *state,
}
#endif
+#warning "FIXME detect conflicts caused by the source and destination being the same register"
+
+ /* If a color is already assigned see if it will work */
+ if (range->color != REG_UNSET) {
+ struct live_range_def *lrd;
+ if (!used[range->color]) {
+ return 1;
+ }
+ for(edge = range->edges; edge; edge = edge->next) {
+ if (edge->node->color != range->color) {
+ continue;
+ }
+ warning(state, edge->node->defs->def, "edge: ");
+ lrd = edge->node->defs;
+ do {
+ warning(state, lrd->def, " %p %s",
+ lrd->def, tops(lrd->def->op));
+ lrd = lrd->next;
+ } while(lrd != edge->node->defs);
+ }
+ lrd = range->defs;
+ warning(state, range->defs->def, "def: ");
+ do {
+ warning(state, lrd->def, " %p %s",
+ lrd->def, tops(lrd->def->op));
+ lrd = lrd->next;
+ } while(lrd != range->defs);
+ internal_error(state, range->defs->def,
+ "live range with already used color %s",
+ arch_reg_str(range->color));
+ }
+
/* If I feed into an expression reuse it's color.
* This should help remove copies in the case of 2 register instructions
* and phi functions.
*/
phi = 0;
- entry = range->def->use;
- for(;(range->color == REG_UNSET) && entry; entry = entry->next) {
- struct live_range *lr;
- lr = &rstate->lr[entry->member->id];
- if (entry->member->id == 0) {
- continue;
- }
- if (!phi && (lr->def->op == OP_PHI) &&
- !interfere(rstate, range, lr)) {
- phi = lr;
- }
- if ((lr->color == REG_UNSET) ||
- ((lr->classes & range->classes) == 0) ||
- (used[lr->color])) {
- continue;
- }
- if (interfere(rstate, range, lr)) {
- continue;
+ lrd = live_range_end(state, range, 0);
+ for(; (range->color == REG_UNSET) && lrd ; lrd = live_range_end(state, range, lrd)) {
+ entry = lrd->def->use;
+ for(;(range->color == REG_UNSET) && entry; entry = entry->next) {
+ struct live_range_def *insd;
+ insd = &rstate->lrd[entry->member->id];
+ if (insd->lr->defs == 0) {
+ continue;
+ }
+ if (!phi && (insd->def->op == OP_PHI) &&
+ !interfere(rstate, range, insd->lr)) {
+ phi = insd;
+ }
+ if ((insd->lr->color == REG_UNSET) ||
+ ((insd->lr->classes & range->classes) == 0) ||
+ (used[insd->lr->color])) {
+ continue;
+ }
+ if (interfere(rstate, range, insd->lr)) {
+ continue;
+ }
+ range->color = insd->lr->color;
}
- range->color = lr->color;
}
- /* If I feed into a phi function reuse it's color of the color
+ /* If I feed into a phi function reuse it's color or the color
* of something else that feeds into the phi function.
*/
if (phi) {
- if (phi->color != REG_UNSET) {
- if (used[phi->color]) {
- range->color = phi->color;
+ if (phi->lr->color != REG_UNSET) {
+ if (used[phi->lr->color]) {
+ range->color = phi->lr->color;
}
}
else {
@@ -10877,7 +12516,7 @@ static void select_free_color(struct compile_state *state,
if (!*expr) {
continue;
}
- lr = &rstate->lr[(*expr)->id];
+ lr = rstate->lrd[(*expr)->id].lr;
if ((lr->color == REG_UNSET) ||
((lr->classes & range->classes) == 0) ||
(used[lr->color])) {
@@ -10891,14 +12530,15 @@ static void select_free_color(struct compile_state *state,
}
}
/* If I don't interfere with a rhs node reuse it's color */
- if (range->color == REG_UNSET) {
- expr = triple_rhs(state, range->def, 0);
- for(; expr; expr = triple_rhs(state, range->def, expr)) {
+ lrd = live_range_head(state, range, 0);
+ for(; (range->color == REG_UNSET) && lrd ; lrd = live_range_head(state, range, lrd)) {
+ expr = triple_rhs(state, lrd->def, 0);
+ for(; expr; expr = triple_rhs(state, lrd->def, expr)) {
struct live_range *lr;
if (!*expr) {
continue;
}
- lr = &rstate->lr[(*expr)->id];
+ lr = rstate->lrd[(*expr)->id].lr;
if ((lr->color == -1) ||
((lr->classes & range->classes) == 0) ||
(used[lr->color])) {
@@ -10920,33 +12560,40 @@ static void select_free_color(struct compile_state *state,
}
if (range->color == REG_UNSET) {
int i;
+ if (split_ranges(state, rstate, used, range)) {
+ return 0;
+ }
for(edge = range->edges; edge; edge = edge->next) {
if (edge->node->color == REG_UNSET) {
continue;
}
- warning(state, edge->node->def, "reg %s",
+ warning(state, edge->node->defs->def, "reg %s",
arch_reg_str(edge->node->color));
}
- warning(state, range->def, "classes: %x",
+ warning(state, range->defs->def, "classes: %x",
range->classes);
for(i = 0; i < MAX_REGISTERS; i++) {
if (used[i]) {
- warning(state, range->def, "used: %s",
+ warning(state, range->defs->def, "used: %s",
arch_reg_str(i));
}
}
#if DEBUG_COLOR_GRAPH < 2
- error(state, range->def, "too few registers");
+ error(state, range->defs->def, "too few registers");
#else
- internal_error(state, range->def, "too few registers");
+ internal_error(state, range->defs->def, "too few registers");
#endif
}
range->classes = arch_reg_regcm(state, range->color);
- return;
+ if (range->color == -1) {
+ internal_error(state, range->defs->def, "select_free_color did not?");
+ }
+ return 1;
}
-static void color_graph(struct compile_state *state, struct reg_state *rstate)
+static int color_graph(struct compile_state *state, struct reg_state *rstate)
{
+ int colored;
struct live_range_edge *edge;
struct live_range *range;
if (rstate->low) {
@@ -10984,7 +12631,7 @@ static void color_graph(struct compile_state *state, struct reg_state *rstate)
}
}
else {
- return;
+ return 1;
}
cgdebug_printf(" %d\n", range - rstate->lr);
range->group_prev = 0;
@@ -11015,16 +12662,16 @@ static void color_graph(struct compile_state *state, struct reg_state *rstate)
}
node->degree -= 1;
}
- color_graph(state, rstate);
- cgdebug_printf("Coloring %d @%s:%d.%d:",
- range - rstate->lr,
- range->def->filename, range->def->line, range->def->col);
- cgdebug_flush();
- select_free_color(state, rstate, range);
- if (range->color == -1) {
- internal_error(state, range->def, "select_free_color did not?");
+ colored = color_graph(state, rstate);
+ if (colored) {
+ cgdebug_printf("Coloring %d @%s:%d.%d:",
+ range - rstate->lr,
+ range->def->filename, range->def->line, range->def->col);
+ cgdebug_flush();
+ colored = select_free_color(state, rstate, range);
+ cgdebug_printf(" %s\n", arch_reg_str(range->color));
}
- cgdebug_printf(" %s\n", arch_reg_str(range->color));
+ return colored;
}
static void verify_colors(struct compile_state *state, struct reg_state *rstate)
@@ -11037,11 +12684,11 @@ static void verify_colors(struct compile_state *state, struct reg_state *rstate)
ins = first;
do {
if (triple_is_def(state, ins)) {
- if ((ins->id < 0) || (ins->id > rstate->ranges)) {
+ if ((ins->id < 0) || (ins->id > rstate->defs)) {
internal_error(state, ins,
- "triple without a live range");
+ "triple without a live range def");
}
- lr = &rstate->lr[ins->id];
+ lr = rstate->lrd[ins->id].lr;
if (lr->color == REG_UNSET) {
internal_error(state, ins,
"triple without a color");
@@ -11071,12 +12718,12 @@ static void color_triples(struct compile_state *state, struct reg_state *rstate)
first = RHS(state->main_function, 0);
ins = first;
do {
- if ((ins->id < 0) || (ins->id > rstate->ranges)) {
+ if ((ins->id < 0) || (ins->id > rstate->defs)) {
internal_error(state, ins,
"triple without a live range");
}
- lr = &rstate->lr[ins->id];
- ins->id = MK_REG_ID(lr->color, 0);
+ lr = rstate->lrd[ins->id].lr;
+ SET_REG(ins->id, lr->color);
ins = ins->next;
} while (ins != first);
}
@@ -11141,9 +12788,9 @@ static void print_interference_block(
int op;
op = ptr->op;
done = (ptr == block->last);
- lr = &rstate->lr[ptr->id];
+ lr = rstate->lrd[ptr->id].lr;
- if (!IS_CONST_OP(op)) {
+ if (triple_stores_block(state, ptr)) {
if (ptr->u.block != block) {
internal_error(state, ptr,
"Wrong block pointer: %p",
@@ -11152,8 +12799,6 @@ static void print_interference_block(
}
if (op == OP_ADECL) {
for(user = ptr->use; user; user = user->next) {
- struct live_range *lr;
- lr = &rstate->lr[user->member->id];
if (!user->member->u.block) {
internal_error(state, user->member,
"Use %p not in a block?",
@@ -11163,21 +12808,41 @@ static void print_interference_block(
}
}
id = ptr->id;
- ptr->id = MK_REG_ID(lr->color, 0);
+ SET_REG(ptr->id, lr->color);
display_triple(stdout, ptr);
ptr->id = id;
+ if (triple_is_def(state, ptr) && (lr->defs == 0)) {
+ internal_error(state, ptr, "lr has no defs!");
+ }
+
+ if (lr->defs) {
+ struct live_range_def *lrd;
+ printf(" range:");
+ lrd = lr->defs;
+ do {
+ printf(" %-10p", lrd->def);
+ lrd = lrd->next;
+ } while(lrd != lr->defs);
+ printf("\n");
+ }
if (lr->edges > 0) {
struct live_range_edge *edge;
- printf(" ");
+ printf(" edges:");
for(edge = lr->edges; edge; edge = edge->next) {
- printf(" %-10p", edge->node->def);
+ struct live_range_def *lrd;
+ lrd = edge->node->defs;
+ do {
+ printf(" %-10p", lrd->def);
+ lrd = lrd->next;
+ } while(lrd != edge->node->defs);
+ printf("|");
}
printf("\n");
}
/* Do a bunch of sanity checks */
valid_ins(state, ptr);
- if ((ptr->id < 0) || (ptr->id > rstate->ranges)) {
+ if ((ptr->id < 0) || (ptr->id > rstate->defs)) {
internal_error(state, ptr, "Invalid triple id: %d",
ptr->id);
}
@@ -11186,12 +12851,12 @@ static void print_interference_block(
struct live_range *ulr;
use = user->member;
valid_ins(state, use);
- if ((use->id < 0) || (use->id > rstate->ranges)) {
+ if ((use->id < 0) || (use->id > rstate->defs)) {
internal_error(state, use, "Invalid triple id: %d",
use->id);
}
- ulr = &rstate->lr[user->member->id];
- if (!IS_CONST_OP(user->member->op) &&
+ ulr = rstate->lrd[user->member->id].lr;
+ if (triple_stores_block(state, user->member) &&
!user->member->u.block) {
internal_error(state, user->member,
"Use %p not in a block?",
@@ -11225,7 +12890,9 @@ static struct live_range *merge_sort_lr(
join_tail = &join;
/* merge the two lists */
while(first && mid) {
- if (first->degree <= mid->degree) {
+ if ((first->degree < mid->degree) ||
+ ((first->degree == mid->degree) &&
+ (first->length < mid->length))) {
pick = first;
first = first->group_next;
if (first) {
@@ -11247,10 +12914,12 @@ static struct live_range *merge_sort_lr(
/* Splice the remaining list */
pick = (first)? first : mid;
*join_tail = pick;
- pick->group_prev = join_tail;
+ if (pick) {
+ pick->group_prev = join_tail;
+ }
}
else {
- if (!first->def) {
+ if (!first->defs) {
first = 0;
}
join = first;
@@ -11258,93 +12927,193 @@ static struct live_range *merge_sort_lr(
return join;
}
+static void ids_from_rstate(struct compile_state *state,
+ struct reg_state *rstate)
+{
+ struct triple *ins, *first;
+ if (!rstate->defs) {
+ return;
+ }
+ /* Display the graph if desired */
+ if (state->debug & DEBUG_INTERFERENCE) {
+ print_blocks(state, stdout);
+ print_control_flow(state);
+ }
+ first = RHS(state->main_function, 0);
+ ins = first;
+ do {
+ if (ins->id) {
+ struct live_range_def *lrd;
+ lrd = &rstate->lrd[ins->id];
+ ins->id = lrd->orig_id;
+ }
+ ins = ins->next;
+ } while(ins != first);
+}
+
+static void cleanup_live_edges(struct reg_state *rstate)
+{
+ int i;
+ /* Free the edges on each node */
+ for(i = 1; i <= rstate->ranges; i++) {
+ remove_live_edges(rstate, &rstate->lr[i]);
+ }
+}
+
+static void cleanup_rstate(struct compile_state *state, struct reg_state *rstate)
+{
+ cleanup_live_edges(rstate);
+ xfree(rstate->lrd);
+ xfree(rstate->lr);
+
+ /* Free the variable lifetime information */
+ if (rstate->blocks) {
+ free_variable_lifetimes(state, rstate->blocks);
+ }
+ rstate->defs = 0;
+ rstate->ranges = 0;
+ rstate->lrd = 0;
+ rstate->lr = 0;
+ rstate->blocks = 0;
+}
+
static void allocate_registers(struct compile_state *state)
{
struct reg_state rstate;
- struct live_range **point, **next;
- int i;
+ int colored;
/* Clear out the reg_state */
memset(&rstate, 0, sizeof(rstate));
+ rstate.max_passes = MAX_ALLOCATION_PASSES;
- /* Compute the variable lifetimes */
- rstate.blocks = compute_variable_lifetimes(state);
+ do {
+ struct live_range **point, **next;
+ struct triple *tangle;
+ struct coalesce_conflict conflict;
+ int coalesced;
- /* Allocate and initialize the live ranges */
- initialize_live_ranges(state, &rstate);
+ /* Restore ids */
+ ids_from_rstate(state, &rstate);
- /* Compute the interference graph */
- walk_variable_lifetimes(
- state, rstate.blocks, graph_ins, &rstate);
+ do {
+ /* Cleanup the temporary data structures */
+ cleanup_rstate(state, &rstate);
- /* Display the interference graph if desired */
- if (state->debug & DEBUG_INTERFERENCE) {
- printf("\nlive variables by block\n");
- walk_blocks(state, print_interference_block, &rstate);
- printf("\nlive variables by instruction\n");
- walk_variable_lifetimes(
- state, rstate.blocks,
- print_interference_ins, &rstate);
- }
+ /* Compute the variable lifetimes */
+ rstate.blocks = compute_variable_lifetimes(state);
- /* Do not perform coalescing! It is a neat idea but it limits what
- * we can do later. It has no benefits that decrease register pressure.
- * It only decreases instruction count.
- *
- * It might be worth testing this reducing the number of
- * live_ragnes as opposed to splitting them seems to help.
- */
+ /* Find an invalid mandatory live range coalesce */
+ conflict.ins = 0;
+ conflict.index = -1;
+ walk_variable_lifetimes(
+ state, rstate.blocks, spot_coalesce_conflict, &conflict);
+
+ /* If a tangle was found resolve it */
+ if (conflict.ins) {
+ resolve_coalesce_conflict(state, &conflict);
+ }
+ } while(conflict.ins);
- /* Build the groups low and high. But with the nodes
- * first sorted by degree order.
- */
- rstate.low_tail = &rstate.low;
- rstate.high_tail = &rstate.high;
- rstate.high = merge_sort_lr(&rstate.lr[1], &rstate.lr[rstate.ranges]);
- if (rstate.high) {
- rstate.high->group_prev = &rstate.high;
- }
- for(point = &rstate.high; *point; point = &(*point)->group_next)
- ;
- rstate.high_tail = point;
- /* Walk through the high list and move everything that needs
- * to be onto low.
- */
- for(point = &rstate.high; *point; point = next) {
- struct live_range *range;
- next = &(*point)->group_next;
- range = *point;
+ do {
+ /* Cleanup the temporary data structures */
+ cleanup_rstate(state, &rstate);
+
+ /* Compute the variable lifetimes */
+ rstate.blocks = compute_variable_lifetimes(state);
+
+ /* Find two simultaneous uses of the same register */
+ tangle = 0;
+ walk_variable_lifetimes(
+ state, rstate.blocks, spot_tangle, &tangle);
+
+ /* If a tangle was found resolve it */
+ if (tangle) {
+ resolve_tangle(state, tangle);
+ }
+ } while(tangle);
+
+ if (state->debug & DEBUG_INSERTED_COPIES) {
+ printf("After resolve_tangles\n");
+ print_blocks(state, stdout);
+ print_control_flow(state);
+ }
- /* If it has a low degree or it already has a color
- * place the node in low.
+
+ /* Allocate and initialize the live ranges */
+ initialize_live_ranges(state, &rstate);
+
+ do {
+ /* Forget previous live range edge calculations */
+ cleanup_live_edges(&rstate);
+
+ /* Compute the interference graph */
+ walk_variable_lifetimes(
+ state, rstate.blocks, graph_ins, &rstate);
+
+ /* Display the interference graph if desired */
+ if (state->debug & DEBUG_INTERFERENCE) {
+ printf("\nlive variables by block\n");
+ walk_blocks(state, print_interference_block, &rstate);
+ printf("\nlive variables by instruction\n");
+ walk_variable_lifetimes(
+ state, rstate.blocks,
+ print_interference_ins, &rstate);
+ }
+
+ coalesced = coalesce_live_ranges(state, &rstate);
+ } while(coalesced);
+
+ /* Build the groups low and high. But with the nodes
+ * first sorted by degree order.
*/
- if ((range->degree < regc_max_size(state, range->classes)) ||
- (range->color != REG_UNSET)) {
- cgdebug_printf("Lo: %5d degree %5d%s\n",
- range - rstate.lr, range->degree,
- (range->color != REG_UNSET) ? " (colored)": "");
- *range->group_prev = range->group_next;
- if (range->group_next) {
- range->group_next->group_prev = range->group_prev;
- }
- if (&range->group_next == rstate.high_tail) {
- rstate.high_tail = range->group_prev;
- }
- range->group_prev = rstate.low_tail;
- range->group_next = 0;
- *rstate.low_tail = range;
- rstate.low_tail = &range->group_next;
- next = point;
+ rstate.low_tail = &rstate.low;
+ rstate.high_tail = &rstate.high;
+ rstate.high = merge_sort_lr(&rstate.lr[1], &rstate.lr[rstate.ranges]);
+ if (rstate.high) {
+ rstate.high->group_prev = &rstate.high;
}
- else {
- cgdebug_printf("hi: %5d degree %5d%s\n",
- range - rstate.lr, range->degree,
- (range->color != REG_UNSET) ? " (colored)": "");
+ for(point = &rstate.high; *point; point = &(*point)->group_next)
+ ;
+ rstate.high_tail = point;
+ /* Walk through the high list and move everything that needs
+ * to be onto low.
+ */
+ for(point = &rstate.high; *point; point = next) {
+ struct live_range *range;
+ next = &(*point)->group_next;
+ range = *point;
+
+ /* If it has a low degree or it already has a color
+ * place the node in low.
+ */
+ if ((range->degree < regc_max_size(state, range->classes)) ||
+ (range->color != REG_UNSET)) {
+ cgdebug_printf("Lo: %5d degree %5d%s\n",
+ range - rstate.lr, range->degree,
+ (range->color != REG_UNSET) ? " (colored)": "");
+ *range->group_prev = range->group_next;
+ if (range->group_next) {
+ range->group_next->group_prev = range->group_prev;
+ }
+ if (&range->group_next == rstate.high_tail) {
+ rstate.high_tail = range->group_prev;
+ }
+ range->group_prev = rstate.low_tail;
+ range->group_next = 0;
+ *rstate.low_tail = range;
+ rstate.low_tail = &range->group_next;
+ next = point;
+ }
+ else {
+ cgdebug_printf("hi: %5d degree %5d%s\n",
+ range - rstate.lr, range->degree,
+ (range->color != REG_UNSET) ? " (colored)": "");
+ }
}
-
- }
- /* Color the live_ranges */
- color_graph(state, &rstate);
+ /* Color the live_ranges */
+ colored = color_graph(state, &rstate);
+ rstate.passes++;
+ } while (!colored);
/* Verify the graph was properly colored */
verify_colors(state, &rstate);
@@ -11352,15 +13121,8 @@ static void allocate_registers(struct compile_state *state)
/* Move the colors from the graph to the triples */
color_triples(state, &rstate);
- /* Free the edges on each node */
- for(i = 1; i <= rstate.ranges; i++) {
- remove_live_edges(&rstate, &rstate.lr[i]);
- }
- xfree(rstate.lr);
-
- /* Free the variable lifetime information */
- free_variable_lifetimes(state, rstate.blocks);
-
+ /* Cleanup the temporary data structures */
+ cleanup_rstate(state, &rstate);
}
/* Sparce Conditional Constant Propogation
@@ -11369,6 +13131,7 @@ static void allocate_registers(struct compile_state *state)
struct ssa_edge;
struct flow_block;
struct lattice_node {
+ unsigned old_id;
struct triple *def;
struct ssa_edge *out;
struct flow_block *fblock;
@@ -11521,7 +13284,6 @@ static void initialize_scc_state(
ins_index = ssa_edge_index = fblock_index = 0;
ins = first;
do {
- ins->id = 0;
if ((ins->op == OP_LABEL) && (block != ins->u.block)) {
block = ins->u.block;
if (!block) {
@@ -11535,12 +13297,13 @@ static void initialize_scc_state(
{
struct lattice_node *lnode;
ins_index += 1;
- ins->id = ins_index;
lnode = &scc->lattice[ins_index];
lnode->def = ins;
lnode->out = 0;
lnode->fblock = fblock;
lnode->val = ins; /* LATTICE HIGH */
+ lnode->old_id = ins->id;
+ ins->id = ins_index;
}
ins = ins->next;
} while(ins != first);
@@ -11653,13 +13416,6 @@ static void initialize_scc_state(
static void free_scc_state(
struct compile_state *state, struct scc_state *scc)
{
- int i;
- for(i = 0; i < scc->ins_count; i++) {
- if (scc->lattice[i].val &&
- (scc->lattice[i].val != scc->lattice[i].def)) {
- xfree(scc->lattice[i].val);
- }
- }
xfree(scc->flow_blocks);
xfree(scc->ssa_edges);
xfree(scc->lattice);
@@ -11675,16 +13431,62 @@ static struct lattice_node *triple_to_lattice(
return &scc->lattice[ins->id];
}
+static struct triple *preserve_lval(
+ struct compile_state *state, struct lattice_node *lnode)
+{
+ struct triple *old;
+ /* Preserve the original value */
+ if (lnode->val) {
+ old = dup_triple(state, lnode->val);
+ if (lnode->val != lnode->def) {
+ xfree(lnode->val);
+ }
+ lnode->val = 0;
+ } else {
+ old = 0;
+ }
+ return old;
+}
+
+static int lval_changed(struct compile_state *state,
+ struct triple *old, struct lattice_node *lnode)
+{
+ int changed;
+ /* See if the lattice value has changed */
+ changed = 1;
+ if (!old && !lnode->val) {
+ changed = 0;
+ }
+ if (changed && lnode->val && !is_const(lnode->val)) {
+ changed = 0;
+ }
+ if (changed &&
+ lnode->val && old &&
+ (memcmp(lnode->val->param, old->param,
+ TRIPLE_SIZE(lnode->val->sizes) * sizeof(lnode->val->param[0])) == 0) &&
+ (memcmp(&lnode->val->u, &old->u, sizeof(old->u)) == 0)) {
+ changed = 0;
+ }
+ if (old) {
+ xfree(old);
+ }
+ return changed;
+
+}
+
static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
struct lattice_node *lnode)
{
struct lattice_node *tmp;
- struct triple **slot;
+ struct triple **slot, *old;
struct flow_edge *fedge;
int index;
if (lnode->def->op != OP_PHI) {
internal_error(state, lnode->def, "not phi");
}
+ /* Store the original value */
+ old = preserve_lval(state, lnode);
+
/* default to lattice high */
lnode->val = lnode->def;
slot = &RHS(lnode->def, 0);
@@ -11707,7 +13509,8 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
}
/* meet(lattice high, X) = X */
else if (!is_const(lnode->val)) {
- lnode->val = tmp->val;
+ lnode->val = dup_triple(state, tmp->val);
+ lnode->val->type = lnode->def->type;
}
/* meet(const, const) = const or lattice low */
else if (!constants_equal(state, lnode->val, tmp->val)) {
@@ -11717,12 +13520,18 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
break;
}
}
- /* Do I need to update any work lists here? */
#if DEBUG_SCC
fprintf(stderr, "phi: %d -> %s\n",
lnode->def->id,
(!lnode->val)? "lo": is_const(lnode->val)? "const": "hi");
#endif
+ /* If the lattice value has changed update the work lists. */
+ if (lval_changed(state, old, lnode)) {
+ struct ssa_edge *sedge;
+ for(sedge = lnode->out; sedge; sedge = sedge->out_next) {
+ scc_add_sedge(state, scc, sedge);
+ }
+ }
}
static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
@@ -11733,34 +13542,25 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
struct triple **dexpr, **vexpr;
int count, i;
- if (lnode->def->op != OP_STORE) {
- check_lhs(state, lnode->def);
- }
-
/* Store the original value */
- if (lnode->val) {
- old = dup_triple(state, lnode->val);
- if (lnode->val != lnode->def) {
- xfree(lnode->val);
- }
- lnode->val = 0;
+ old = preserve_lval(state, lnode);
- } else {
- old = 0;
- }
/* Reinitialize the value */
lnode->val = scratch = dup_triple(state, lnode->def);
+ scratch->id = lnode->old_id;
scratch->next = scratch;
scratch->prev = scratch;
scratch->use = 0;
count = TRIPLE_SIZE(scratch->sizes);
for(i = 0; i < count; i++) {
- struct lattice_node *tmp;
dexpr = &lnode->def->param[i];
vexpr = &scratch->param[i];
- *vexpr = 0;
- if (*dexpr) {
+ *vexpr = *dexpr;
+ if (((i < TRIPLE_MISC_OFF(scratch->sizes)) ||
+ (i >= TRIPLE_TARG_OFF(scratch->sizes))) &&
+ *dexpr) {
+ struct lattice_node *tmp;
tmp = triple_to_lattice(state, scc, *dexpr);
*vexpr = (tmp->val)? tmp->val : tmp->def;
}
@@ -11795,7 +13595,9 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
if (!is_const(scratch)) {
for(i = 0; i < count; i++) {
dexpr = &lnode->def->param[i];
- if (*dexpr) {
+ if (((i < TRIPLE_MISC_OFF(scratch->sizes)) ||
+ (i >= TRIPLE_TARG_OFF(scratch->sizes))) &&
+ *dexpr) {
struct lattice_node *tmp;
tmp = triple_to_lattice(state, scc, *dexpr);
if (!tmp->val) {
@@ -11817,32 +13619,13 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
!triple_is_pure(state, lnode->val)) {
lnode->val = 0;
}
-#if 1
if (lnode->val &&
(lnode->val->op == OP_SDECL) &&
(lnode->val != lnode->def)) {
internal_error(state, lnode->def, "bad sdecl");
}
-#endif
/* See if the lattice value has changed */
- changed = 1;
- if (!old && !lnode->val) {
- changed = 0;
- }
- if (changed && lnode->val && !is_const(lnode->val)) {
- changed = 0;
- }
- if (changed &&
- lnode->val && old &&
- (lnode->val->op == old->op) &&
- (memcmp(lnode->val->param, old->param,
- count * sizeof(lnode->val->param[0])) == 0) &&
- (memcmp(&lnode->val->u, &old->u, sizeof(old->u)) == 0)) {
- changed = 0;
- }
- if (old) {
- xfree(old);
- }
+ changed = lval_changed(state, old, lnode);
if (lnode->val != scratch) {
xfree(scratch);
}
@@ -11865,7 +13648,7 @@ static void scc_visit_branch(struct compile_state *state, struct scc_state *scc,
fprintf(stderr, " )");
if (TRIPLE_RHS(lnode->def->sizes) > 0) {
fprintf(stderr, " <- %d",
- RHS(lnode->def)->id);
+ RHS(lnode->def, 0)->id);
}
fprintf(stderr, "\n");
}
@@ -11938,6 +13721,8 @@ static void scc_writeback_values(
do {
struct lattice_node *lnode;
lnode = triple_to_lattice(state, scc, ins);
+ /* Restore id */
+ ins->id = lnode->old_id;
#if DEBUG_SCC
if (lnode->val && !is_const(lnode->val)) {
warning(state, lnode->def,
@@ -11952,7 +13737,7 @@ static void scc_writeback_values(
break;
case OP_ADDRCONST:
mkaddr_const(state, ins,
- RHS(lnode->val, 0), lnode->val->u.cval);
+ MISC(lnode->val, 0), lnode->val->u.cval);
break;
default:
/* By default don't copy the changes,
@@ -11961,6 +13746,13 @@ static void scc_writeback_values(
simplify(state, ins);
break;
}
+ if (is_const(lnode->val) &&
+ !constants_equal(state, lnode->val, ins)) {
+ internal_error(state, 0, "constants not equal");
+ }
+ /* Free the lattice nodes */
+ xfree(lnode->val);
+ lnode->val = 0;
}
ins = ins->next;
} while(ins != first);
@@ -12053,8 +13845,163 @@ static void scc_transform(struct compile_state *state)
}
-static void transform_to_arch_instructions(struct compile_state *state);
+static void transform_to_arch_instructions(struct compile_state *state)
+{
+ struct triple *ins, *first;
+ first = RHS(state->main_function, 0);
+ ins = first;
+ do {
+ ins = transform_to_arch_instruction(state, ins);
+ } while(ins != first);
+}
+#if DEBUG_CONSISTENCY
+static void verify_uses(struct compile_state *state)
+{
+ struct triple *first, *ins;
+ struct triple_set *set;
+ first = RHS(state->main_function, 0);
+ ins = first;
+ do {
+ struct triple **expr;
+ expr = triple_rhs(state, ins, 0);
+ for(; expr; expr = triple_rhs(state, ins, expr)) {
+ for(set = *expr?(*expr)->use:0; set; set = set->next) {
+ if (set->member == ins) {
+ break;
+ }
+ }
+ if (!set) {
+ internal_error(state, ins, "rhs not used");
+ }
+ }
+ expr = triple_lhs(state, ins, 0);
+ for(; expr; expr = triple_lhs(state, ins, expr)) {
+ for(set = *expr?(*expr)->use:0; set; set = set->next) {
+ if (set->member == ins) {
+ break;
+ }
+ }
+ if (!set) {
+ internal_error(state, ins, "lhs not used");
+ }
+ }
+ ins = ins->next;
+ } while(ins != first);
+
+}
+static void verify_blocks(struct compile_state *state)
+{
+ struct triple *ins;
+ struct block *block;
+ block = state->first_block;
+ if (!block) {
+ return;
+ }
+ do {
+ for(ins = block->first; ins != block->last->next; ins = ins->next) {
+ if (!triple_stores_block(state, ins)) {
+ continue;
+ }
+ if (ins->u.block != block) {
+ internal_error(state, ins, "inconsitent block specified");
+ }
+ }
+ if (!triple_stores_block(state, block->last->next)) {
+ internal_error(state, block->last->next,
+ "cannot find next block");
+ }
+ block = block->last->next->u.block;
+ if (!block) {
+ internal_error(state, block->last->next,
+ "bad next block");
+ }
+ } while(block != state->first_block);
+}
+
+static void verify_domination(struct compile_state *state)
+{
+ struct triple *first, *ins;
+ struct triple_set *set;
+ if (!state->first_block) {
+ return;
+ }
+
+ first = RHS(state->main_function, 0);
+ ins = first;
+ do {
+ for(set = ins->use; set; set = set->next) {
+ struct triple **expr;
+ if (set->member->op == OP_PHI) {
+ continue;
+ }
+ /* See if the use is on the righ hand side */
+ expr = triple_rhs(state, set->member, 0);
+ for(; expr ; expr = triple_rhs(state, set->member, expr)) {
+ if (*expr == ins) {
+ break;
+ }
+ }
+ if (expr &&
+ !tdominates(state, ins, set->member)) {
+ internal_error(state, set->member,
+ "non dominated rhs use?");
+ }
+ }
+ ins = ins->next;
+ } while(ins != first);
+}
+
+static void verify_piece(struct compile_state *state)
+{
+ struct triple *first, *ins;
+ first = RHS(state->main_function, 0);
+ ins = first;
+ do {
+ struct triple *ptr;
+ int lhs, i;
+ lhs = TRIPLE_LHS(ins->sizes);
+ if ((ins->op == OP_WRITE) || (ins->op == OP_STORE)) {
+ lhs = 0;
+ }
+ for(ptr = ins->next, i = 0; i < lhs; i++, ptr = ptr->next) {
+ if (ptr != LHS(ins, i)) {
+ internal_error(state, ins, "malformed lhs on %s",
+ tops(ins->op));
+ }
+ if (ptr->op != OP_PIECE) {
+ internal_error(state, ins, "bad lhs op %s at %d on %s",
+ tops(ptr->op), i, tops(ins->op));
+ }
+ if (ptr->u.cval != i) {
+ internal_error(state, ins, "bad u.cval of %d %d expected",
+ ptr->u.cval, i);
+ }
+ }
+ ins = ins->next;
+ } while(ins != first);
+}
+static void verify_ins_colors(struct compile_state *state)
+{
+ struct triple *first, *ins;
+
+ first = RHS(state->main_function, 0);
+ ins = first;
+ do {
+ ins = ins->next;
+ } while(ins != first);
+}
+static void verify_consistency(struct compile_state *state)
+{
+ verify_uses(state);
+ verify_blocks(state);
+ verify_domination(state);
+ verify_piece(state);
+ verify_ins_colors(state);
+}
+#else
+#define verify_consistency(state) do {} while(0)
+#endif /* DEBUG_USES */
static void optimize(struct compile_state *state)
{
@@ -12066,18 +14013,22 @@ static void optimize(struct compile_state *state)
if (state->debug & DEBUG_TRIPLES) {
print_triples(state);
}
+ verify_consistency(state);
/* Analize the intermediate code */
setup_basic_blocks(state);
analyze_idominators(state);
analyze_ipdominators(state);
/* Transform the code to ssa form */
transform_to_ssa_form(state);
+ verify_consistency(state);
/* Do strength reduction and simple constant optimizations */
if (state->optimize >= 1) {
simplify_all(state);
}
+ verify_consistency(state);
/* Propogate constants throughout the code */
if (state->optimize >= 2) {
+#warning "FIXME fix scc_transform"
scc_transform(state);
transform_from_ssa_form(state);
free_basic_blocks(state);
@@ -12085,31 +14036,47 @@ static void optimize(struct compile_state *state)
analyze_idominators(state);
analyze_ipdominators(state);
transform_to_ssa_form(state);
-
}
+ verify_consistency(state);
#warning "WISHLIST implement single use constants (least possible register pressure)"
#warning "WISHLIST implement induction variable elimination"
-#warning "WISHLIST implement strength reduction"
/* Select architecture instructions and an initial partial
* coloring based on architecture constraints.
*/
transform_to_arch_instructions(state);
+ verify_consistency(state);
if (state->debug & DEBUG_ARCH_CODE) {
printf("After transform_to_arch_instructions\n");
- print_blocks(state);
+ print_blocks(state, stdout);
print_control_flow(state);
}
eliminate_inefectual_code(state);
+ verify_consistency(state);
if (state->debug & DEBUG_CODE_ELIMINATION) {
printf("After eliminate_inefectual_code\n");
- print_blocks(state);
+ 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);
+ print_blocks(state, stdout);
}
if (state->debug & DEBUG_CONTROL_FLOW) {
print_control_flow(state);
@@ -12120,17 +14087,82 @@ static void optimize(struct compile_state *state)
free_basic_blocks(state);
}
+static void print_op_asm(struct compile_state *state,
+ struct triple *ins, FILE *fp)
+{
+ struct asm_info *info;
+ const char *ptr;
+ unsigned lhs, rhs, i;
+ info = ins->u.ainfo;
+ lhs = TRIPLE_LHS(ins->sizes);
+ rhs = TRIPLE_RHS(ins->sizes);
+ /* Don't count the clobbers in lhs */
+ for(i = 0; i < lhs; i++) {
+ if (LHS(ins, i)->type == &void_type) {
+ break;
+ }
+ }
+ lhs = i;
+ fputc('\t', fp);
+ for(ptr = info->str; *ptr; ptr++) {
+ char *next;
+ unsigned long param;
+ struct triple *piece;
+ if (*ptr != '%') {
+ fputc(*ptr, fp);
+ continue;
+ }
+ ptr++;
+ if (*ptr == '%') {
+ fputc('%', fp);
+ continue;
+ }
+ param = strtoul(ptr, &next, 10);
+ if (ptr == next) {
+ error(state, ins, "Invalid asm template");
+ }
+ if (param >= (lhs + rhs)) {
+ error(state, ins, "Invalid param %%%u in asm template",
+ param);
+ }
+ piece = (param < lhs)? LHS(ins, param) : RHS(ins, param - lhs);
+ fprintf(fp, "%s",
+ arch_reg_str(ID_REG(piece->id)));
+ ptr = next;
+ }
+ fputc('\n', fp);
+}
+
+
+/* Only use the low x86 byte registers. This allows me
+ * allocate the entire register when a byte register is used.
+ */
+#define X86_4_8BIT_GPRS 1
+
+/* Recognized x86 cpu variants */
+#define BAD_CPU 0
+#define CPU_I386 1
+#define CPU_P3 2
+#define CPU_P4 3
+#define CPU_K7 4
+#define CPU_K8 5
+
+#define CPU_DEFAULT CPU_I386
+
/* The x86 register classes */
-#define REGC_FLAGS 0
-#define REGC_GPR8 1
-#define REGC_GPR16 2
-#define REGC_GPR32 3
-#define REGC_GPR64 4
-#define REGC_MMX 5
-#define REGC_XMM 6
-#define REGC_GPR32_8 7
-#define REGC_GPR16_8 8
-#define LAST_REGC REGC_GPR16_8
+#define REGC_FLAGS 0
+#define REGC_GPR8 1
+#define REGC_GPR16 2
+#define REGC_GPR32 3
+#define REGC_GPR64 4
+#define REGC_MMX 5
+#define REGC_XMM 6
+#define REGC_GPR32_8 7
+#define REGC_GPR16_8 8
+#define REGC_IMM32 9
+#define REGC_IMM16 10
+#define REGC_IMM8 11
+#define LAST_REGC REGC_IMM8
#if LAST_REGC >= MAX_REGC
#error "MAX_REGC is to low"
#endif
@@ -12145,66 +14177,70 @@ static void optimize(struct compile_state *state)
#define REGCM_XMM (1 << REGC_XMM)
#define REGCM_GPR32_8 (1 << REGC_GPR32_8)
#define REGCM_GPR16_8 (1 << REGC_GPR16_8)
+#define REGCM_IMM32 (1 << REGC_IMM32)
+#define REGCM_IMM16 (1 << REGC_IMM16)
+#define REGCM_IMM8 (1 << REGC_IMM8)
+#define REGCM_ALL ((1 << (LAST_REGC + 1)) - 1)
/* The x86 registers */
-#define REG_EFLAGS 1
+#define REG_EFLAGS 2
#define REGC_FLAGS_FIRST REG_EFLAGS
#define REGC_FLAGS_LAST REG_EFLAGS
-#define REG_AL 2
-#define REG_BL 3
-#define REG_CL 4
-#define REG_DL 5
-#define REG_AH 6
-#define REG_BH 7
-#define REG_CH 8
-#define REG_DH 9
+#define REG_AL 3
+#define REG_BL 4
+#define REG_CL 5
+#define REG_DL 6
+#define REG_AH 7
+#define REG_BH 8
+#define REG_CH 9
+#define REG_DH 10
#define REGC_GPR8_FIRST REG_AL
#if X86_4_8BIT_GPRS
#define REGC_GPR8_LAST REG_DL
#else
#define REGC_GPR8_LAST REG_DH
#endif
-#define REG_AX 10
-#define REG_BX 11
-#define REG_CX 12
-#define REG_DX 13
-#define REG_SI 14
-#define REG_DI 15
-#define REG_BP 16
-#define REG_SP 17
+#define REG_AX 11
+#define REG_BX 12
+#define REG_CX 13
+#define REG_DX 14
+#define REG_SI 15
+#define REG_DI 16
+#define REG_BP 17
+#define REG_SP 18
#define REGC_GPR16_FIRST REG_AX
#define REGC_GPR16_LAST REG_SP
-#define REG_EAX 18
-#define REG_EBX 19
-#define REG_ECX 20
-#define REG_EDX 21
-#define REG_ESI 22
-#define REG_EDI 23
-#define REG_EBP 24
-#define REG_ESP 25
+#define REG_EAX 19
+#define REG_EBX 20
+#define REG_ECX 21
+#define REG_EDX 22
+#define REG_ESI 23
+#define REG_EDI 24
+#define REG_EBP 25
+#define REG_ESP 26
#define REGC_GPR32_FIRST REG_EAX
#define REGC_GPR32_LAST REG_ESP
-#define REG_EDXEAX 26
+#define REG_EDXEAX 27
#define REGC_GPR64_FIRST REG_EDXEAX
#define REGC_GPR64_LAST REG_EDXEAX
-#define REG_MMX0 27
-#define REG_MMX1 28
-#define REG_MMX2 29
-#define REG_MMX3 30
-#define REG_MMX4 31
-#define REG_MMX5 32
-#define REG_MMX6 33
-#define REG_MMX7 34
+#define REG_MMX0 28
+#define REG_MMX1 29
+#define REG_MMX2 30
+#define REG_MMX3 31
+#define REG_MMX4 32
+#define REG_MMX5 33
+#define REG_MMX6 34
+#define REG_MMX7 35
#define REGC_MMX_FIRST REG_MMX0
#define REGC_MMX_LAST REG_MMX7
-#define REG_XMM0 35
-#define REG_XMM1 36
-#define REG_XMM2 37
-#define REG_XMM3 38
-#define REG_XMM4 39
-#define REG_XMM5 40
-#define REG_XMM6 41
-#define REG_XMM7 42
+#define REG_XMM0 36
+#define REG_XMM1 37
+#define REG_XMM2 38
+#define REG_XMM3 39
+#define REG_XMM4 40
+#define REG_XMM5 41
+#define REG_XMM6 42
+#define REG_XMM7 43
#define REGC_XMM_FIRST REG_XMM0
#define REGC_XMM_LAST REG_XMM7
#warning "WISHLIST figure out how to use pinsrw and pextrw to better use extended regs"
@@ -12215,23 +14251,74 @@ static void optimize(struct compile_state *state)
#define REGC_GPR16_8_FIRST REG_AX
#define REGC_GPR16_8_LAST REG_DX
+#define REGC_IMM8_FIRST -1
+#define REGC_IMM8_LAST -1
+#define REGC_IMM16_FIRST -2
+#define REGC_IMM16_LAST -1
+#define REGC_IMM32_FIRST -4
+#define REGC_IMM32_LAST -1
+
#if LAST_REG >= MAX_REGISTERS
#error "MAX_REGISTERS to low"
#endif
+
+static unsigned regc_size[LAST_REGC +1] = {
+ [REGC_FLAGS] = REGC_FLAGS_LAST - REGC_FLAGS_FIRST + 1,
+ [REGC_GPR8] = REGC_GPR8_LAST - REGC_GPR8_FIRST + 1,
+ [REGC_GPR16] = REGC_GPR16_LAST - REGC_GPR16_FIRST + 1,
+ [REGC_GPR32] = REGC_GPR32_LAST - REGC_GPR32_FIRST + 1,
+ [REGC_GPR64] = REGC_GPR64_LAST - REGC_GPR64_FIRST + 1,
+ [REGC_MMX] = REGC_MMX_LAST - REGC_MMX_FIRST + 1,
+ [REGC_XMM] = REGC_XMM_LAST - REGC_XMM_FIRST + 1,
+ [REGC_GPR32_8] = REGC_GPR32_8_LAST - REGC_GPR32_8_FIRST + 1,
+ [REGC_GPR16_8] = REGC_GPR16_8_LAST - REGC_GPR16_8_FIRST + 1,
+ [REGC_IMM32] = 0,
+ [REGC_IMM16] = 0,
+ [REGC_IMM8] = 0,
+};
+
+static const struct {
+ int first, last;
+} regcm_bound[LAST_REGC + 1] = {
+ [REGC_FLAGS] = { REGC_FLAGS_FIRST, REGC_FLAGS_LAST },
+ [REGC_GPR8] = { REGC_GPR8_FIRST, REGC_GPR8_LAST },
+ [REGC_GPR16] = { REGC_GPR16_FIRST, REGC_GPR16_LAST },
+ [REGC_GPR32] = { REGC_GPR32_FIRST, REGC_GPR32_LAST },
+ [REGC_GPR64] = { REGC_GPR64_FIRST, REGC_GPR64_LAST },
+ [REGC_MMX] = { REGC_MMX_FIRST, REGC_MMX_LAST },
+ [REGC_XMM] = { REGC_XMM_FIRST, REGC_XMM_LAST },
+ [REGC_GPR32_8] = { REGC_GPR32_8_FIRST, REGC_GPR32_8_LAST },
+ [REGC_GPR16_8] = { REGC_GPR16_8_FIRST, REGC_GPR16_8_LAST },
+ [REGC_IMM32] = { REGC_IMM32_FIRST, REGC_IMM32_LAST },
+ [REGC_IMM16] = { REGC_IMM16_FIRST, REGC_IMM16_LAST },
+ [REGC_IMM8] = { REGC_IMM8_FIRST, REGC_IMM8_LAST },
+};
+
+static int arch_encode_cpu(const char *cpu)
+{
+ struct cpu {
+ const char *name;
+ int cpu;
+ } cpus[] = {
+ { "i386", CPU_I386 },
+ { "p3", CPU_P3 },
+ { "p4", CPU_P4 },
+ { "k7", CPU_K7 },
+ { "k8", CPU_K8 },
+ { 0, BAD_CPU }
+ };
+ struct cpu *ptr;
+ for(ptr = cpus; ptr->name; ptr++) {
+ if (strcmp(ptr->name, cpu) == 0) {
+ break;
+ }
+ }
+ return ptr->cpu;
+}
+
static unsigned arch_regc_size(struct compile_state *state, int class)
{
- static unsigned regc_size[LAST_REGC +1] = {
- [REGC_FLAGS] = REGC_FLAGS_LAST - REGC_FLAGS_FIRST + 1,
- [REGC_GPR8] = REGC_GPR8_LAST - REGC_GPR8_FIRST + 1,
- [REGC_GPR16] = REGC_GPR16_LAST - REGC_GPR16_FIRST + 1,
- [REGC_GPR32] = REGC_GPR32_LAST - REGC_GPR32_FIRST + 1,
- [REGC_GPR64] = REGC_GPR64_LAST - REGC_GPR64_FIRST + 1,
- [REGC_MMX] = REGC_MMX_LAST - REGC_MMX_FIRST + 1,
- [REGC_XMM] = REGC_XMM_LAST - REGC_XMM_FIRST + 1,
- [REGC_GPR32_8] = REGC_GPR32_8_LAST - REGC_GPR32_8_FIRST + 1,
- [REGC_GPR16_8] = REGC_GPR16_8_LAST - REGC_GPR16_8_FIRST + 1,
- };
if ((class < 0) || (class > LAST_REGC)) {
return 0;
}
@@ -12243,6 +14330,13 @@ static int arch_regcm_intersect(unsigned regcm1, unsigned regcm2)
unsigned gpr_mask = REGCM_GPR8 | REGCM_GPR16_8 | REGCM_GPR16 |
REGCM_GPR32_8 | REGCM_GPR32 | REGCM_GPR64;
+ /* Special case for the immediates */
+ if ((regcm1 & (REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8)) &&
+ ((regcm1 & ~(REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8)) == 0) &&
+ (regcm2 & (REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8)) &&
+ ((regcm2 & ~(REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8)) == 0)) {
+ return 0;
+ }
return (regcm1 & regcm2) ||
((regcm1 & gpr_mask) && (regcm2 & gpr_mask));
}
@@ -12256,23 +14350,63 @@ static void arch_reg_equivs(
*equiv++ = reg;
switch(reg) {
case REG_AL:
+#if X86_4_8BIT_GPRS
+ *equiv++ = REG_AH;
+#endif
+ *equiv++ = REG_AX;
+ *equiv++ = REG_EAX;
+ *equiv++ = REG_EDXEAX;
+ break;
case REG_AH:
+#if X86_4_8BIT_GPRS
+ *equiv++ = REG_AL;
+#endif
*equiv++ = REG_AX;
*equiv++ = REG_EAX;
*equiv++ = REG_EDXEAX;
break;
case REG_BL:
+#if X86_4_8BIT_GPRS
+ *equiv++ = REG_BH;
+#endif
+ *equiv++ = REG_BX;
+ *equiv++ = REG_EBX;
+ break;
+
case REG_BH:
+#if X86_4_8BIT_GPRS
+ *equiv++ = REG_BL;
+#endif
*equiv++ = REG_BX;
*equiv++ = REG_EBX;
break;
case REG_CL:
+#if X86_4_8BIT_GPRS
+ *equiv++ = REG_CH;
+#endif
+ *equiv++ = REG_CX;
+ *equiv++ = REG_ECX;
+ break;
+
case REG_CH:
+#if X86_4_8BIT_GPRS
+ *equiv++ = REG_CL;
+#endif
*equiv++ = REG_CX;
*equiv++ = REG_ECX;
break;
case REG_DL:
+#if X86_4_8BIT_GPRS
+ *equiv++ = REG_DH;
+#endif
+ *equiv++ = REG_DX;
+ *equiv++ = REG_EDX;
+ *equiv++ = REG_EDXEAX;
+ break;
case REG_DH:
+#if X86_4_8BIT_GPRS
+ *equiv++ = REG_DL;
+#endif
*equiv++ = REG_DX;
*equiv++ = REG_EDX;
*equiv++ = REG_EDXEAX;
@@ -12359,28 +14493,63 @@ static void arch_reg_equivs(
*equiv++ = REG_UNSET;
}
+static unsigned arch_avail_mask(struct compile_state *state)
+{
+ unsigned avail_mask;
+ avail_mask = REGCM_GPR8 | REGCM_GPR16_8 | REGCM_GPR16 |
+ REGCM_GPR32 | REGCM_GPR32_8 | REGCM_GPR64 |
+ REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8 | REGCM_FLAGS;
+ switch(state->cpu) {
+ case CPU_P3:
+ case CPU_K7:
+ avail_mask |= REGCM_MMX;
+ break;
+ case CPU_P4:
+ case CPU_K8:
+ avail_mask |= REGCM_MMX | REGCM_XMM;
+ break;
+ }
+#if 0
+ /* Don't enable 8 bit values until I can force both operands
+ * to be 8bits simultaneously.
+ */
+ avail_mask &= ~(REGCM_GPR8 | REGCM_GPR16_8 | REGCM_GPR16);
+#endif
+ return avail_mask;
+}
+
+static unsigned arch_regcm_normalize(struct compile_state *state, unsigned regcm)
+{
+ unsigned mask, result;
+ int class, class2;
+ result = regcm;
+ result &= arch_avail_mask(state);
+
+ for(class = 0, mask = 1; mask; mask <<= 1, class++) {
+ if ((result & mask) == 0) {
+ continue;
+ }
+ if (class > LAST_REGC) {
+ result &= ~mask;
+ }
+ for(class2 = 0; class2 <= LAST_REGC; class2++) {
+ if ((regcm_bound[class2].first >= regcm_bound[class].first) &&
+ (regcm_bound[class2].last <= regcm_bound[class].last)) {
+ result |= (1 << class2);
+ }
+ }
+ }
+ return result;
+}
static unsigned arch_reg_regcm(struct compile_state *state, int reg)
{
- static const struct {
- int first, last;
- } bound[LAST_REGC + 1] = {
- [REGC_FLAGS] = { REGC_FLAGS_FIRST, REGC_FLAGS_LAST },
- [REGC_GPR8] = { REGC_GPR8_FIRST, REGC_GPR8_LAST },
- [REGC_GPR16] = { REGC_GPR16_FIRST, REGC_GPR16_LAST },
- [REGC_GPR32] = { REGC_GPR32_FIRST, REGC_GPR32_LAST },
- [REGC_GPR64] = { REGC_GPR64_FIRST, REGC_GPR64_LAST },
- [REGC_MMX] = { REGC_MMX_FIRST, REGC_MMX_LAST },
- [REGC_XMM] = { REGC_XMM_FIRST, REGC_XMM_LAST },
- [REGC_GPR32_8] = { REGC_GPR32_8_FIRST, REGC_GPR32_8_LAST },
- [REGC_GPR16_8] = { REGC_GPR16_8_FIRST, REGC_GPR16_8_LAST },
- };
unsigned mask;
int class;
mask = 0;
for(class = 0; class <= LAST_REGC; class++) {
- if ((reg >= bound[class].first) &&
- (reg <= bound[class].last)) {
+ if ((reg >= regcm_bound[class].first) &&
+ (reg <= regcm_bound[class].last)) {
mask |= (1 << class);
}
}
@@ -12390,6 +14559,129 @@ static unsigned arch_reg_regcm(struct compile_state *state, int reg)
return mask;
}
+static struct reg_info arch_reg_constraint(
+ struct compile_state *state, struct type *type, const char *constraint)
+{
+ static const struct {
+ char class;
+ unsigned int mask;
+ unsigned int reg;
+ } constraints[] = {
+ { 'r', REGCM_GPR32, REG_UNSET },
+ { 'g', REGCM_GPR32, REG_UNSET },
+ { 'p', REGCM_GPR32, REG_UNSET },
+ { 'q', REGCM_GPR8, REG_UNSET },
+ { 'Q', REGCM_GPR32_8, REG_UNSET },
+ { 'x', REGCM_XMM, REG_UNSET },
+ { 'y', REGCM_MMX, REG_UNSET },
+ { 'a', REGCM_GPR32, REG_EAX },
+ { 'b', REGCM_GPR32, REG_EBX },
+ { 'c', REGCM_GPR32, REG_ECX },
+ { 'd', REGCM_GPR32, REG_EDX },
+ { 'D', REGCM_GPR32, REG_EDI },
+ { 'S', REGCM_GPR32, REG_ESI },
+ { '\0', 0, REG_UNSET },
+ };
+ unsigned int regcm;
+ unsigned int mask, reg;
+ struct reg_info result;
+ const char *ptr;
+ regcm = arch_type_to_regcm(state, type);
+ reg = REG_UNSET;
+ mask = 0;
+ for(ptr = constraint; *ptr; ptr++) {
+ int i;
+ if (*ptr == ' ') {
+ continue;
+ }
+ for(i = 0; constraints[i].class != '\0'; i++) {
+ if (constraints[i].class == *ptr) {
+ break;
+ }
+ }
+ if (constraints[i].class == '\0') {
+ error(state, 0, "invalid register constraint ``%c''", *ptr);
+ break;
+ }
+ if ((constraints[i].mask & regcm) == 0) {
+ error(state, 0, "invalid register class %c specified",
+ *ptr);
+ }
+ mask |= constraints[i].mask;
+ if (constraints[i].reg != REG_UNSET) {
+ if ((reg != REG_UNSET) && (reg != constraints[i].reg)) {
+ error(state, 0, "Only one register may be specified");
+ }
+ reg = constraints[i].reg;
+ }
+ }
+ result.reg = reg;
+ result.regcm = mask;
+ return result;
+}
+
+static struct reg_info arch_reg_clobber(
+ struct compile_state *state, const char *clobber)
+{
+ struct reg_info result;
+ if (strcmp(clobber, "memory") == 0) {
+ result.reg = REG_UNSET;
+ result.regcm = 0;
+ }
+ else if (strcmp(clobber, "%eax") == 0) {
+ result.reg = REG_EAX;
+ result.regcm = REGCM_GPR32;
+ }
+ else if (strcmp(clobber, "%ebx") == 0) {
+ result.reg = REG_EBX;
+ result.regcm = REGCM_GPR32;
+ }
+ else if (strcmp(clobber, "%ecx") == 0) {
+ result.reg = REG_ECX;
+ result.regcm = REGCM_GPR32;
+ }
+ else if (strcmp(clobber, "%edx") == 0) {
+ result.reg = REG_EDX;
+ result.regcm = REGCM_GPR32;
+ }
+ else if (strcmp(clobber, "%esi") == 0) {
+ result.reg = REG_ESI;
+ result.regcm = REGCM_GPR32;
+ }
+ else if (strcmp(clobber, "%edi") == 0) {
+ result.reg = REG_EDI;
+ result.regcm = REGCM_GPR32;
+ }
+ else if (strcmp(clobber, "%ebp") == 0) {
+ result.reg = REG_EBP;
+ result.regcm = REGCM_GPR32;
+ }
+ else if (strcmp(clobber, "%esp") == 0) {
+ result.reg = REG_ESP;
+ result.regcm = REGCM_GPR32;
+ }
+ else if (strcmp(clobber, "cc") == 0) {
+ result.reg = REG_EFLAGS;
+ result.regcm = REGCM_FLAGS;
+ }
+ else if ((strncmp(clobber, "xmm", 3) == 0) &&
+ octdigitp(clobber[3]) && (clobber[4] == '\0')) {
+ result.reg = REG_XMM0 + octdigval(clobber[3]);
+ result.regcm = REGCM_XMM;
+ }
+ else if ((strncmp(clobber, "mmx", 3) == 0) &&
+ octdigitp(clobber[3]) && (clobber[4] == '\0')) {
+ result.reg = REG_MMX0 + octdigval(clobber[3]);
+ result.regcm = REGCM_MMX;
+ }
+ else {
+ error(state, 0, "Invalid register clobber");
+ result.reg = REG_UNSET;
+ result.regcm = 0;
+ }
+ return result;
+}
+
static int do_select_reg(struct compile_state *state,
char *used, int reg, unsigned classes)
{
@@ -12412,9 +14704,6 @@ static int arch_select_free_register(
for(i = REGC_FLAGS_FIRST; (reg == REG_UNSET) && (i <= REGC_FLAGS_LAST); i++) {
reg = do_select_reg(state, used, i, classes);
}
- for(i = REGC_GPR8_FIRST; (reg == REG_UNSET) && (i <= REGC_GPR8_LAST); i++) {
- reg = do_select_reg(state, used, i, classes);
- }
for(i = REGC_GPR32_FIRST; (reg == REG_UNSET) && (i <= REGC_GPR32_LAST); i++) {
reg = do_select_reg(state, used, i, classes);
}
@@ -12427,34 +14716,23 @@ static int arch_select_free_register(
for(i = REGC_GPR16_FIRST; (reg == REG_UNSET) && (i <= REGC_GPR16_LAST); i++) {
reg = do_select_reg(state, used, i, classes);
}
+ for(i = REGC_GPR8_FIRST; (reg == REG_UNSET) && (i <= REGC_GPR8_LAST); i++) {
+ reg = do_select_reg(state, used, i, classes);
+ }
for(i = REGC_GPR64_FIRST; (reg == REG_UNSET) && (i <= REGC_GPR64_LAST); i++) {
reg = do_select_reg(state, used, i, classes);
}
return reg;
}
+
static unsigned arch_type_to_regcm(struct compile_state *state, struct type *type)
{
#warning "FIXME force types smaller (if legal) before I get here"
- int use_mmx = 0;
- int use_sse = 0;
unsigned avail_mask;
unsigned mask;
- avail_mask = REGCM_GPR8 | REGCM_GPR16_8 | REGCM_GPR16 |
- REGCM_GPR32 | REGCM_GPR32_8 | REGCM_GPR64;
-#if 1
- /* Don't enable 8 bit values until I can force both operands
- * to be 8bits simultaneously.
- */
- avail_mask &= ~(REGCM_GPR8 | REGCM_GPR16_8 | REGCM_GPR16);
-#endif
- if (use_mmx) {
- avail_mask |= REGCM_MMX;
- }
- if (use_sse) {
- avail_mask |= REGCM_XMM;
- }
mask = 0;
+ avail_mask = arch_avail_mask(state);
switch(type->type & TYPE_MASK) {
case TYPE_ARRAY:
case TYPE_VOID:
@@ -12463,25 +14741,28 @@ static unsigned arch_type_to_regcm(struct compile_state *state, struct type *typ
case TYPE_CHAR:
case TYPE_UCHAR:
mask = REGCM_GPR8 |
- REGCM_GPR16_8 | REGCM_GPR16 |
+ REGCM_GPR16 | REGCM_GPR16_8 |
REGCM_GPR32 | REGCM_GPR32_8 |
REGCM_GPR64 |
- REGCM_MMX | REGCM_XMM;
+ REGCM_MMX | REGCM_XMM |
+ REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8;
break;
case TYPE_SHORT:
case TYPE_USHORT:
- mask = REGCM_GPR16 | REGCM_GPR16_8 |
+ mask = REGCM_GPR16 | REGCM_GPR16_8 |
REGCM_GPR32 | REGCM_GPR32_8 |
REGCM_GPR64 |
- REGCM_MMX | REGCM_XMM;
+ REGCM_MMX | REGCM_XMM |
+ REGCM_IMM32 | REGCM_IMM16;
break;
case TYPE_INT:
case TYPE_UINT:
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_POINTER:
- mask = REGCM_GPR32 | REGCM_GPR32_8 |
- REGCM_GPR64 | REGCM_MMX | REGCM_XMM;
+ mask = REGCM_GPR32 | REGCM_GPR32_8 |
+ REGCM_GPR64 | REGCM_MMX | REGCM_XMM |
+ REGCM_IMM32;
break;
default:
internal_error(state, 0, "no register class for type");
@@ -12491,121 +14772,304 @@ static unsigned arch_type_to_regcm(struct compile_state *state, struct type *typ
return mask;
}
-static void get_imm32(struct triple *ins, struct triple **expr)
+static int is_imm32(struct triple *imm)
+{
+ return ((imm->op == OP_INTCONST) && (imm->u.cval <= 0xffffffffUL)) ||
+ (imm->op == OP_ADDRCONST);
+
+}
+static int is_imm16(struct triple *imm)
+{
+ return ((imm->op == OP_INTCONST) && (imm->u.cval <= 0xffff));
+}
+static int is_imm8(struct triple *imm)
+{
+ return ((imm->op == OP_INTCONST) && (imm->u.cval <= 0xff));
+}
+
+static int get_imm32(struct triple *ins, struct triple **expr)
{
struct triple *imm;
- if ((*expr)->op != OP_COPY) {
- return;
- }
- imm = RHS((*expr), 0);
+ imm = *expr;
while(imm->op == OP_COPY) {
imm = RHS(imm, 0);
}
- if (imm->op != OP_INTCONST) {
- return;
+ if (!is_imm32(imm)) {
+ return 0;
}
- *expr = imm;
unuse_triple(*expr, ins);
- use_triple(*expr, ins);
+ use_triple(imm, ins);
+ *expr = imm;
+ return 1;
}
-static void get_imm8(struct triple *ins, struct triple **expr)
+static int get_imm8(struct triple *ins, struct triple **expr)
{
struct triple *imm;
- if ((*expr)->op != OP_COPY) {
- return;
- }
- imm = RHS((*expr), 0);
+ imm = *expr;
while(imm->op == OP_COPY) {
imm = RHS(imm, 0);
}
- if (imm->op != OP_INTCONST) {
- return;
- }
- /* For imm8 only a sufficienlty small constant can be used */
- if (imm->u.cval > 0xff) {
- return;
+ if (!is_imm8(imm)) {
+ return 0;
}
- *expr = imm;
unuse_triple(*expr, ins);
- use_triple(*expr, ins);
+ use_triple(imm, ins);
+ *expr = imm;
+ return 1;
}
-static struct triple *pre_copy(struct compile_state *state,
- struct triple *ins, struct triple **expr,
- unsigned reg, unsigned mask)
-{
- /* Carefully insert enough operations so that I can
- * enter any operation with a GPR32.
- */
- struct triple *in;
- /* See if I can directly reach the result from a GPR32 */
- if (mask & (REGCM_GPR32 | REGCM_GPR16 | REGCM_MMX | REGCM_XMM)) {
- in = triple(state, OP_COPY, (*expr)->type, *expr, 0);
- }
- /* If it is a byte value force a earlier copy to a GPR32_8 */
- else if (mask & REGCM_GPR8) {
- struct triple *tmp;
- tmp = triple(state, OP_COPY, (*expr)->type, *expr, 0);
- tmp->filename = ins->filename;
- tmp->line = ins->line;
- tmp->col = ins->col;
- tmp->u.block = ins->u.block;
- tmp->id = MK_REG_ID(REG_UNSET, REGCM_GPR32_8 | REGCM_GPR16_8);
- use_triple(RHS(tmp, 0), tmp);
- insert_triple(state, ins, tmp);
-
- in = triple(state, OP_COPY, tmp->type, tmp, 0);
- }
- else {
- internal_error(state, ins, "bad copy type");
- in = 0;
- }
- in->filename = ins->filename;
- in->line = ins->line;
- in->col = ins->col;
- in->u.block = ins->u.block;
- in->id = MK_REG_ID(reg, mask);
- unuse_triple(*expr, ins);
- *expr = in;
- use_triple(RHS(in, 0), in);
- use_triple(in, ins);
- insert_triple(state, ins, in);
- return in;
-}
+#define TEMPLATE_NOP 0
+#define TEMPLATE_INTCONST8 1
+#define TEMPLATE_INTCONST32 2
+#define TEMPLATE_COPY_REG 3
+#define TEMPLATE_COPY_IMM32 4
+#define TEMPLATE_COPY_IMM16 5
+#define TEMPLATE_COPY_IMM8 6
+#define TEMPLATE_PHI 7
+#define TEMPLATE_STORE8 8
+#define TEMPLATE_STORE16 9
+#define TEMPLATE_STORE32 10
+#define TEMPLATE_LOAD8 11
+#define TEMPLATE_LOAD16 12
+#define TEMPLATE_LOAD32 13
+#define TEMPLATE_BINARY_REG 14
+#define TEMPLATE_BINARY_IMM 15
+#define TEMPLATE_SL_CL 16
+#define TEMPLATE_SL_IMM 17
+#define TEMPLATE_UNARY 18
+#define TEMPLATE_CMP_REG 19
+#define TEMPLATE_CMP_IMM 20
+#define TEMPLATE_TEST 21
+#define TEMPLATE_SET 22
+#define TEMPLATE_JMP 23
+#define TEMPLATE_INB_DX 24
+#define TEMPLATE_INB_IMM 25
+#define TEMPLATE_INW_DX 26
+#define TEMPLATE_INW_IMM 27
+#define TEMPLATE_INL_DX 28
+#define TEMPLATE_INL_IMM 29
+#define TEMPLATE_OUTB_DX 30
+#define TEMPLATE_OUTB_IMM 31
+#define TEMPLATE_OUTW_DX 32
+#define TEMPLATE_OUTW_IMM 33
+#define TEMPLATE_OUTL_DX 34
+#define TEMPLATE_OUTL_IMM 35
+#define TEMPLATE_BSF 36
+#define TEMPLATE_RDMSR 37
+#define TEMPLATE_WRMSR 38
+#define LAST_TEMPLATE TEMPLATE_WRMSR
+#if LAST_TEMPLATE >= MAX_TEMPLATES
+#error "MAX_TEMPLATES to low"
+#endif
-static struct triple *post_copy(struct compile_state *state, struct triple *ins)
-{
- struct triple_set *entry, *next;
- struct triple *out, *label;
- struct block *block;
- label = ins;
- while(label->op != OP_LABEL) {
- label = label->prev;
- }
- block = label->u.block;
- out = triple(state, OP_COPY, ins->type, ins, 0);
- out->filename = ins->filename;
- out->line = ins->line;
- out->col = ins->col;
- out->u.block = block;
- out->id = MK_REG_ID(REG_UNSET,
- arch_type_to_regcm(state, ins->type));
- use_triple(ins, out);
- insert_triple(state, ins->next, out);
- if (block->last == ins) {
- block->last = out;
- }
- /* Get the users of ins to use out instead */
- for(entry = ins->use; entry; entry = next) {
- next = entry->next;
- if (entry->member == out) {
- continue;
- }
- replace_rhs_use(state, ins, out, entry->member);
- }
- return out;
-}
+#define COPY_REGCM (REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8 | REGCM_MMX | REGCM_XMM)
+#define COPY32_REGCM (REGCM_GPR32 | REGCM_MMX | REGCM_XMM)
+
+static struct ins_template templates[] = {
+ [TEMPLATE_NOP] = {},
+ [TEMPLATE_INTCONST8] = {
+ .lhs = { [0] = { REG_UNNEEDED, REGCM_IMM8 } },
+ },
+ [TEMPLATE_INTCONST32] = {
+ .lhs = { [0] = { REG_UNNEEDED, REGCM_IMM32 } },
+ },
+ [TEMPLATE_COPY_REG] = {
+ .lhs = { [0] = { REG_UNSET, COPY_REGCM } },
+ .rhs = { [0] = { REG_UNSET, COPY_REGCM } },
+ },
+ [TEMPLATE_COPY_IMM32] = {
+ .lhs = { [0] = { REG_UNSET, COPY32_REGCM } },
+ .rhs = { [0] = { REG_UNNEEDED, REGCM_IMM32 } },
+ },
+ [TEMPLATE_COPY_IMM16] = {
+ .lhs = { [0] = { REG_UNSET, COPY32_REGCM | REGCM_GPR16 } },
+ .rhs = { [0] = { REG_UNNEEDED, REGCM_IMM16 } },
+ },
+ [TEMPLATE_COPY_IMM8] = {
+ .lhs = { [0] = { REG_UNSET, COPY_REGCM } },
+ .rhs = { [0] = { REG_UNNEEDED, REGCM_IMM8 } },
+ },
+ [TEMPLATE_PHI] = {
+ .lhs = { [0] = { REG_VIRT0, COPY_REGCM } },
+ .rhs = {
+ [ 0] = { REG_VIRT0, COPY_REGCM },
+ [ 1] = { REG_VIRT0, COPY_REGCM },
+ [ 2] = { REG_VIRT0, COPY_REGCM },
+ [ 3] = { REG_VIRT0, COPY_REGCM },
+ [ 4] = { REG_VIRT0, COPY_REGCM },
+ [ 5] = { REG_VIRT0, COPY_REGCM },
+ [ 6] = { REG_VIRT0, COPY_REGCM },
+ [ 7] = { REG_VIRT0, COPY_REGCM },
+ [ 8] = { REG_VIRT0, COPY_REGCM },
+ [ 9] = { REG_VIRT0, COPY_REGCM },
+ [10] = { REG_VIRT0, COPY_REGCM },
+ [11] = { REG_VIRT0, COPY_REGCM },
+ [12] = { REG_VIRT0, COPY_REGCM },
+ [13] = { REG_VIRT0, COPY_REGCM },
+ [14] = { REG_VIRT0, COPY_REGCM },
+ [15] = { REG_VIRT0, COPY_REGCM },
+ }, },
+ [TEMPLATE_STORE8] = {
+ .lhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR8 } },
+ },
+ [TEMPLATE_STORE16] = {
+ .lhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR16 } },
+ },
+ [TEMPLATE_STORE32] = {
+ .lhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ },
+ [TEMPLATE_LOAD8] = {
+ .lhs = { [0] = { REG_UNSET, REGCM_GPR8 } },
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ },
+ [TEMPLATE_LOAD16] = {
+ .lhs = { [0] = { REG_UNSET, REGCM_GPR16 } },
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ },
+ [TEMPLATE_LOAD32] = {
+ .lhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ },
+ [TEMPLATE_BINARY_REG] = {
+ .lhs = { [0] = { REG_VIRT0, REGCM_GPR32 } },
+ .rhs = {
+ [0] = { REG_VIRT0, REGCM_GPR32 },
+ [1] = { REG_UNSET, REGCM_GPR32 },
+ },
+ },
+ [TEMPLATE_BINARY_IMM] = {
+ .lhs = { [0] = { REG_VIRT0, REGCM_GPR32 } },
+ .rhs = {
+ [0] = { REG_VIRT0, REGCM_GPR32 },
+ [1] = { REG_UNNEEDED, REGCM_IMM32 },
+ },
+ },
+ [TEMPLATE_SL_CL] = {
+ .lhs = { [0] = { REG_VIRT0, REGCM_GPR32 } },
+ .rhs = {
+ [0] = { REG_VIRT0, REGCM_GPR32 },
+ [1] = { REG_CL, REGCM_GPR8 },
+ },
+ },
+ [TEMPLATE_SL_IMM] = {
+ .lhs = { [0] = { REG_VIRT0, REGCM_GPR32 } },
+ .rhs = {
+ [0] = { REG_VIRT0, REGCM_GPR32 },
+ [1] = { REG_UNNEEDED, REGCM_IMM8 },
+ },
+ },
+ [TEMPLATE_UNARY] = {
+ .lhs = { [0] = { REG_VIRT0, REGCM_GPR32 } },
+ .rhs = { [0] = { REG_VIRT0, REGCM_GPR32 } },
+ },
+ [TEMPLATE_CMP_REG] = {
+ .lhs = { [0] = { REG_EFLAGS, REGCM_FLAGS } },
+ .rhs = {
+ [0] = { REG_UNSET, REGCM_GPR32 },
+ [1] = { REG_UNSET, REGCM_GPR32 },
+ },
+ },
+ [TEMPLATE_CMP_IMM] = {
+ .lhs = { [0] = { REG_EFLAGS, REGCM_FLAGS } },
+ .rhs = {
+ [0] = { REG_UNSET, REGCM_GPR32 },
+ [1] = { REG_UNNEEDED, REGCM_IMM32 },
+ },
+ },
+ [TEMPLATE_TEST] = {
+ .lhs = { [0] = { REG_EFLAGS, REGCM_FLAGS } },
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ },
+ [TEMPLATE_SET] = {
+ .lhs = { [0] = { REG_UNSET, REGCM_GPR8 } },
+ .rhs = { [0] = { REG_EFLAGS, REGCM_FLAGS } },
+ },
+ [TEMPLATE_JMP] = {
+ .rhs = { [0] = { REG_EFLAGS, REGCM_FLAGS } },
+ },
+ [TEMPLATE_INB_DX] = {
+ .lhs = { [0] = { REG_AL, REGCM_GPR8 } },
+ .rhs = { [0] = { REG_DX, REGCM_GPR16 } },
+ },
+ [TEMPLATE_INB_IMM] = {
+ .lhs = { [0] = { REG_AL, REGCM_GPR8 } },
+ .rhs = { [0] = { REG_UNNEEDED, REGCM_IMM8 } },
+ },
+ [TEMPLATE_INW_DX] = {
+ .lhs = { [0] = { REG_AX, REGCM_GPR16 } },
+ .rhs = { [0] = { REG_DX, REGCM_GPR16 } },
+ },
+ [TEMPLATE_INW_IMM] = {
+ .lhs = { [0] = { REG_AX, REGCM_GPR16 } },
+ .rhs = { [0] = { REG_UNNEEDED, REGCM_IMM8 } },
+ },
+ [TEMPLATE_INL_DX] = {
+ .lhs = { [0] = { REG_EAX, REGCM_GPR32 } },
+ .rhs = { [0] = { REG_DX, REGCM_GPR16 } },
+ },
+ [TEMPLATE_INL_IMM] = {
+ .lhs = { [0] = { REG_EAX, REGCM_GPR32 } },
+ .rhs = { [0] = { REG_UNNEEDED, REGCM_IMM8 } },
+ },
+ [TEMPLATE_OUTB_DX] = {
+ .rhs = {
+ [0] = { REG_AL, REGCM_GPR8 },
+ [1] = { REG_DX, REGCM_GPR16 },
+ },
+ },
+ [TEMPLATE_OUTB_IMM] = {
+ .rhs = {
+ [0] = { REG_AL, REGCM_GPR8 },
+ [1] = { REG_UNNEEDED, REGCM_IMM8 },
+ },
+ },
+ [TEMPLATE_OUTW_DX] = {
+ .rhs = {
+ [0] = { REG_AX, REGCM_GPR16 },
+ [1] = { REG_DX, REGCM_GPR16 },
+ },
+ },
+ [TEMPLATE_OUTW_IMM] = {
+ .rhs = {
+ [0] = { REG_AX, REGCM_GPR16 },
+ [1] = { REG_UNNEEDED, REGCM_IMM8 },
+ },
+ },
+ [TEMPLATE_OUTL_DX] = {
+ .rhs = {
+ [0] = { REG_EAX, REGCM_GPR32 },
+ [1] = { REG_DX, REGCM_GPR16 },
+ },
+ },
+ [TEMPLATE_OUTL_IMM] = {
+ .rhs = {
+ [0] = { REG_EAX, REGCM_GPR32 },
+ [1] = { REG_UNNEEDED, REGCM_IMM8 },
+ },
+ },
+ [TEMPLATE_BSF] = {
+ .lhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ .rhs = { [0] = { REG_UNSET, REGCM_GPR32 } },
+ },
+ [TEMPLATE_RDMSR] = {
+ .lhs = {
+ [0] = { REG_EAX, REGCM_GPR32 },
+ [1] = { REG_EDX, REGCM_GPR32 },
+ },
+ .rhs = { [0] = { REG_ECX, REGCM_GPR32 } },
+ },
+ [TEMPLATE_WRMSR] = {
+ .rhs = {
+ [0] = { REG_ECX, REGCM_GPR32 },
+ [1] = { REG_EAX, REGCM_GPR32 },
+ [2] = { REG_EDX, REGCM_GPR32 },
+ },
+ },
+};
static void fixup_branches(struct compile_state *state,
struct triple *cmp, struct triple *use, int jmp_op)
@@ -12627,10 +15091,19 @@ static void fixup_branches(struct compile_state *state,
branch = entry->member;
test = pre_triple(state, branch,
cmp->op, cmp->type, left, right);
- test->id = MK_REG_ID(REG_EFLAGS, REGCM_FLAGS);
+ test->template_id = TEMPLATE_TEST;
+ if (cmp->op == OP_CMP) {
+ test->template_id = TEMPLATE_CMP_REG;
+ if (get_imm32(test, &RHS(test, 1))) {
+ test->template_id = TEMPLATE_CMP_IMM;
+ }
+ }
+ use_triple(RHS(test, 0), test);
+ use_triple(RHS(test, 1), test);
unuse_triple(RHS(branch, 0), branch);
RHS(branch, 0) = test;
branch->op = jmp_op;
+ branch->template_id = TEMPLATE_JMP;
use_triple(RHS(branch, 0), branch);
}
}
@@ -12639,13 +15112,8 @@ static void fixup_branches(struct compile_state *state,
static void bool_cmp(struct compile_state *state,
struct triple *ins, int cmp_op, int jmp_op, int set_op)
{
- struct block *block;
struct triple_set *entry, *next;
- struct triple *set, *tmp1, *tmp2;
-
-#warning "WISHLIST implement an expression simplifier to reduce the use of set?"
-
- block = ins->u.block;
+ struct triple *set;
/* Put a barrier up before the cmp which preceeds the
* copy instruction. If a set actually occurs this gives
@@ -12654,40 +15122,23 @@ static void bool_cmp(struct compile_state *state,
/* Modify the comparison operator */
ins->op = cmp_op;
- ins->id = MK_REG_ID(REG_EFLAGS, REGCM_FLAGS);
+ ins->template_id = TEMPLATE_TEST;
if (cmp_op == OP_CMP) {
- get_imm32(ins, &RHS(ins, 1));
+ ins->template_id = TEMPLATE_CMP_REG;
+ if (get_imm32(ins, &RHS(ins, 1))) {
+ ins->template_id = TEMPLATE_CMP_IMM;
+ }
}
/* Generate the instruction sequence that will transform the
* result of the comparison into a logical value.
*/
- tmp1 = triple(state, set_op, ins->type, ins, 0);
- tmp1->filename = ins->filename;
- tmp1->line = ins->line;
- tmp1->col = ins->col;
- tmp1->u.block = block;
- tmp1->id = MK_REG_ID(REG_UNSET, REGCM_GPR8);
- use_triple(ins, tmp1);
- insert_triple(state, ins->next, tmp1);
-
- tmp2 = triple(state, OP_COPY, ins->type, tmp1, 0);
- tmp2->filename = ins->filename;
- tmp2->line = ins->line;
- tmp2->col = ins->col;
- tmp2->u.block = block;
- tmp2->id = MK_REG_ID(REG_UNSET,
- REGCM_GPR32 | REGCM_GPR32_8 | REGCM_GPR16 | REGCM_GPR16_8 | REGCM_GPR8);
- use_triple(tmp1, tmp2);
- insert_triple(state, tmp1->next, tmp2);
-
- if (block->last == ins) {
- block->last = tmp2;
- }
+ set = post_triple(state, ins, set_op, ins->type, ins, 0);
+ use_triple(ins, set);
+ set->template_id = TEMPLATE_SET;
- set = tmp2;
for(entry = ins->use; entry; entry = next) {
next = entry->next;
- if (entry->member == tmp1) {
+ if (entry->member == set) {
continue;
}
replace_rhs_use(state, ins, set, entry->member);
@@ -12695,7 +15146,7 @@ static void bool_cmp(struct compile_state *state,
fixup_branches(state, ins, set, jmp_op);
}
-static void verify_lhs(struct compile_state *state, struct triple *ins)
+static struct triple *after_lhs(struct compile_state *state, struct triple *ins)
{
struct triple *next;
int lhs, i;
@@ -12705,10 +15156,89 @@ static void verify_lhs(struct compile_state *state, struct triple *ins)
internal_error(state, ins, "malformed lhs on %s",
tops(ins->op));
}
+ if (next->op != OP_PIECE) {
+ internal_error(state, ins, "bad lhs op %s at %d on %s",
+ tops(next->op), i, tops(ins->op));
+ }
+ if (next->u.cval != i) {
+ internal_error(state, ins, "bad u.cval of %d %d expected",
+ next->u.cval, i);
+ }
}
+ return next;
}
-static void transform_to_arch_instructions(struct compile_state *state)
+struct reg_info arch_reg_lhs(struct compile_state *state, struct triple *ins, int index)
+{
+ struct ins_template *template;
+ struct reg_info result;
+ int zlhs;
+ if (ins->op == OP_PIECE) {
+ index = ins->u.cval;
+ ins = MISC(ins, 0);
+ }
+ zlhs = TRIPLE_LHS(ins->sizes);
+ if (triple_is_def(state, ins)) {
+ zlhs = 1;
+ }
+ if (index >= zlhs) {
+ internal_error(state, ins, "index %d out of range for %s\n",
+ index, tops(ins->op));
+ }
+ switch(ins->op) {
+ case OP_ASM:
+ template = &ins->u.ainfo->tmpl;
+ break;
+ default:
+ if (ins->template_id > LAST_TEMPLATE) {
+ internal_error(state, ins, "bad template number %d",
+ ins->template_id);
+ }
+ template = &templates[ins->template_id];
+ break;
+ }
+ result = template->lhs[index];
+ result.regcm = arch_regcm_normalize(state, result.regcm);
+ if (result.reg != REG_UNNEEDED) {
+ result.regcm &= ~(REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8);
+ }
+ if (result.regcm == 0) {
+ internal_error(state, ins, "lhs %d regcm == 0", index);
+ }
+ return result;
+}
+
+struct reg_info arch_reg_rhs(struct compile_state *state, struct triple *ins, int index)
+{
+ struct reg_info result;
+ struct ins_template *template;
+ if ((index > TRIPLE_RHS(ins->sizes)) ||
+ (ins->op == OP_PIECE)) {
+ internal_error(state, ins, "index %d out of range for %s\n",
+ index, tops(ins->op));
+ }
+ switch(ins->op) {
+ case OP_ASM:
+ template = &ins->u.ainfo->tmpl;
+ break;
+ default:
+ if (ins->template_id > LAST_TEMPLATE) {
+ internal_error(state, ins, "bad template number %d",
+ ins->template_id);
+ }
+ template = &templates[ins->template_id];
+ break;
+ }
+ result = template->rhs[index];
+ result.regcm = arch_regcm_normalize(state, result.regcm);
+ if (result.regcm == 0) {
+ internal_error(state, ins, "rhs %d regcm == 0", index);
+ }
+ return result;
+}
+
+static struct triple *transform_to_arch_instruction(
+ struct compile_state *state, struct triple *ins)
{
/* Transform from generic 3 address instructions
* to archtecture specific instructions.
@@ -12716,235 +15246,221 @@ static void transform_to_arch_instructions(struct compile_state *state)
* Copies are inserted to preserve the register flexibility
* of 3 address instructions.
*/
- struct triple *ins, *first, *next;
- struct triple *in, *in2;
- first = RHS(state->main_function, 0);
- ins = first;
- do {
- next = ins->next;
- ins->id = MK_REG_ID(REG_UNSET, arch_type_to_regcm(state, ins->type));
- switch(ins->op) {
- case OP_INTCONST:
- case OP_ADDRCONST:
- ins->id = 0;
- post_copy(state, ins);
- break;
- case OP_NOOP:
- case OP_SDECL:
- case OP_BLOBCONST:
- case OP_LABEL:
- ins->id = 0;
- break;
- /* instructions that can be used as is */
- case OP_COPY:
- case OP_PHI:
- break;
- case OP_STORE:
- {
- unsigned mask;
- ins->id = 0;
- switch(ins->type->type & TYPE_MASK) {
- case TYPE_CHAR: case TYPE_UCHAR:
- mask = REGCM_GPR8;
- break;
- case TYPE_SHORT: case TYPE_USHORT:
- mask = REGCM_GPR16;
- break;
- case TYPE_INT: case TYPE_UINT:
- case TYPE_LONG: case TYPE_ULONG:
- case TYPE_POINTER:
- mask = REGCM_GPR32;
- break;
- default:
- internal_error(state, ins, "unknown type in store");
- mask = 0;
- break;
- }
- in = pre_copy(state, ins, &RHS(ins, 0), REG_UNSET, mask);
- break;
+ struct triple *next;
+ next = ins->next;
+ switch(ins->op) {
+ case OP_INTCONST:
+ ins->template_id = TEMPLATE_INTCONST32;
+ if (ins->u.cval < 256) {
+ ins->template_id = TEMPLATE_INTCONST8;
}
- case OP_LOAD:
- switch(ins->type->type & TYPE_MASK) {
- case TYPE_CHAR: case TYPE_UCHAR:
- ins->id = MK_REG_ID(REG_UNSET, REGCM_GPR8);
- break;
- case TYPE_SHORT:
- case TYPE_USHORT:
- ins->id = MK_REG_ID(REG_UNSET, REGCM_GPR16);
- break;
- case TYPE_INT:
- case TYPE_UINT:
- case TYPE_LONG:
- case TYPE_ULONG:
- case TYPE_POINTER:
- ins->id = MK_REG_ID(REG_UNSET, REGCM_GPR32);
- break;
- default:
- internal_error(state, ins, "unknown type in load");
- break;
- }
- break;
- case OP_ADD:
- case OP_SUB:
- case OP_AND:
- case OP_XOR:
- case OP_OR:
- get_imm32(ins, &RHS(ins, 1));
- in = pre_copy(state, ins, &RHS(ins, 0),
- alloc_virtual_reg(), ID_REG_CLASSES(ins->id));
- ins->id = in->id;
- break;
- case OP_SL:
- case OP_SSR:
- case OP_USR:
- get_imm8(ins, &RHS(ins, 1));
- in = pre_copy(state, ins, &RHS(ins, 0),
- alloc_virtual_reg(), ID_REG_CLASSES(ins->id));
- ins->id = in->id;
- if (!is_const(RHS(ins, 1))) {
- in2 = pre_copy(state, ins, &RHS(ins, 1),
- REG_CL, REGCM_GPR8);
- }
- break;
- case OP_INVERT:
- case OP_NEG:
- in = pre_copy(state, ins, &RHS(ins, 0),
- alloc_virtual_reg(), ID_REG_CLASSES(ins->id));
- ins->id = in->id;
- break;
- case OP_SMUL:
- get_imm32(ins, &RHS(ins, 1));
- in = pre_copy(state, ins, &RHS(ins, 0),
- alloc_virtual_reg(), ID_REG_CLASSES(ins->id));
- ins->id = in->id;
- if (!is_const(RHS(ins, 1))) {
- in2 = pre_copy(state, ins, &RHS(ins, 1),
- REG_UNSET, REGCM_GPR32);
- }
- break;
- case OP_EQ:
- bool_cmp(state, ins, OP_CMP, OP_JMP_EQ, OP_SET_EQ);
- break;
- case OP_NOTEQ:
- bool_cmp(state, ins, OP_CMP, OP_JMP_NOTEQ, OP_SET_NOTEQ);
- break;
- case OP_SLESS:
- bool_cmp(state, ins, OP_CMP, OP_JMP_SLESS, OP_SET_SLESS);
- break;
- case OP_ULESS:
- bool_cmp(state, ins, OP_CMP, OP_JMP_ULESS, OP_SET_ULESS);
- break;
- case OP_SMORE:
- bool_cmp(state, ins, OP_CMP, OP_JMP_SMORE, OP_SET_SMORE);
- break;
- case OP_UMORE:
- bool_cmp(state, ins, OP_CMP, OP_JMP_UMORE, OP_SET_UMORE);
- break;
- case OP_SLESSEQ:
- bool_cmp(state, ins, OP_CMP, OP_JMP_SLESSEQ, OP_SET_SLESSEQ);
- break;
- case OP_ULESSEQ:
- bool_cmp(state, ins, OP_CMP, OP_JMP_ULESSEQ, OP_SET_ULESSEQ);
- break;
- case OP_SMOREEQ:
- bool_cmp(state, ins, OP_CMP, OP_JMP_SMOREEQ, OP_SET_SMOREEQ);
- break;
- case OP_UMOREEQ:
- bool_cmp(state, ins, OP_CMP, OP_JMP_UMOREEQ, OP_SET_UMOREEQ);
- break;
- case OP_LTRUE:
- bool_cmp(state, ins, OP_TEST, OP_JMP_NOTEQ, OP_SET_NOTEQ);
- break;
- case OP_LFALSE:
- bool_cmp(state, ins, OP_TEST, OP_JMP_EQ, OP_SET_EQ);
+ break;
+ case OP_ADDRCONST:
+ ins->template_id = TEMPLATE_INTCONST32;
+ break;
+ case OP_NOOP:
+ case OP_SDECL:
+ case OP_BLOBCONST:
+ case OP_LABEL:
+ ins->template_id = TEMPLATE_NOP;
+ break;
+ case OP_COPY:
+ ins->template_id = TEMPLATE_COPY_REG;
+ if (is_imm8(RHS(ins, 0))) {
+ ins->template_id = TEMPLATE_COPY_IMM8;
+ }
+ else if (is_imm16(RHS(ins, 0))) {
+ ins->template_id = TEMPLATE_COPY_IMM16;
+ }
+ else if (is_imm32(RHS(ins, 0))) {
+ ins->template_id = TEMPLATE_COPY_IMM32;
+ }
+ else if (is_const(RHS(ins, 0))) {
+ internal_error(state, ins, "bad constant passed to copy");
+ }
+ break;
+ case OP_PHI:
+ ins->template_id = TEMPLATE_PHI;
+ break;
+ case OP_STORE:
+ switch(ins->type->type & TYPE_MASK) {
+ case TYPE_CHAR: case TYPE_UCHAR:
+ ins->template_id = TEMPLATE_STORE8;
break;
- case OP_BRANCH:
- if (TRIPLE_RHS(ins->sizes) > 0) {
- internal_error(state, ins, "bad branch test");
- }
- ins->op = OP_JMP;
+ case TYPE_SHORT: case TYPE_USHORT:
+ ins->template_id = TEMPLATE_STORE16;
break;
-
- case OP_INB:
- case OP_INW:
- case OP_INL:
- get_imm8(ins, &RHS(ins, 0));
- switch(ins->op) {
- case OP_INB: ins->id = MK_REG_ID(REG_AL, REGCM_GPR8); break;
- case OP_INW: ins->id = MK_REG_ID(REG_AX, REGCM_GPR16); break;
- case OP_INL: ins->id = MK_REG_ID(REG_EAX, REGCM_GPR32); break;
- }
- if (!is_const(RHS(ins, 0))) {
- in = pre_copy(state, ins, &RHS(ins, 0),
- REG_DX, REGCM_GPR16);
- }
- post_copy(state, ins);
+ case TYPE_INT: case TYPE_UINT:
+ case TYPE_LONG: case TYPE_ULONG:
+ case TYPE_POINTER:
+ ins->template_id = TEMPLATE_STORE32;
break;
- case OP_OUTB:
- case OP_OUTW:
- case OP_OUTL:
- {
- unsigned reg, mask;
- get_imm8(ins, &RHS(ins, 1));
- switch(ins->op) {
- case OP_OUTB: reg = REG_AL; mask = REGCM_GPR8; break;
- case OP_OUTW: reg = REG_AX; mask = REGCM_GPR16; break;
- case OP_OUTL: reg = REG_EAX; mask = REGCM_GPR32; break;
- default: reg = REG_UNSET; mask = 0; break;
- }
- in = pre_copy(state, ins, &RHS(ins, 0), reg, mask);
- if (!is_const(RHS(ins, 1))) {
- in2 = pre_copy(state, ins, &RHS(ins, 1),
- REG_DX, REGCM_GPR16);
- }
+ default:
+ internal_error(state, ins, "unknown type in store");
break;
}
- case OP_BSF:
- case OP_BSR:
- in = pre_copy(state, ins, &RHS(ins, 0),
- REG_UNSET, REGCM_GPR32);
- ins->id = MK_REG_ID(REG_UNSET, REGCM_GPR32 | REGCM_GPR32_8);
- break;
- case OP_RDMSR:
- in = pre_copy(state, ins, &RHS(ins, 0),
- REG_ECX, REGCM_GPR32);
- verify_lhs(state, ins);
- LHS(ins,0)->id = MK_REG_ID(REG_EAX, REGCM_GPR32);
- LHS(ins,1)->id = MK_REG_ID(REG_EDX, REGCM_GPR32);
- next = ins->next->next->next;
- break;
- case OP_WRMSR:
- pre_copy(state, ins, &RHS(ins, 0), REG_ECX, REGCM_GPR32);
- pre_copy(state, ins, &RHS(ins, 1), REG_EAX, REGCM_GPR32);
- pre_copy(state, ins, &RHS(ins, 2), REG_EDX, REGCM_GPR32);
- break;
- case OP_HLT:
+ break;
+ case OP_LOAD:
+ switch(ins->type->type & TYPE_MASK) {
+ case TYPE_CHAR: case TYPE_UCHAR:
+ ins->template_id = TEMPLATE_LOAD8;
break;
- /* Already transformed instructions */
- case OP_CMP:
- case OP_TEST:
- ins->id = MK_REG_ID(REG_EFLAGS, REGCM_FLAGS);
+ case TYPE_SHORT:
+ case TYPE_USHORT:
+ ins->template_id = TEMPLATE_LOAD16;
break;
- case OP_JMP_EQ: case OP_JMP_NOTEQ:
- case OP_JMP_SLESS: case OP_JMP_ULESS:
- case OP_JMP_SMORE: case OP_JMP_UMORE:
- case OP_JMP_SLESSEQ: case OP_JMP_ULESSEQ:
- case OP_JMP_SMOREEQ: case OP_JMP_UMOREEQ:
- case OP_SET_EQ: case OP_SET_NOTEQ:
- case OP_SET_SLESS: case OP_SET_ULESS:
- case OP_SET_SMORE: case OP_SET_UMORE:
- case OP_SET_SLESSEQ: case OP_SET_ULESSEQ:
- case OP_SET_SMOREEQ: case OP_SET_UMOREEQ:
+ case TYPE_INT:
+ case TYPE_UINT:
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ case TYPE_POINTER:
+ ins->template_id = TEMPLATE_LOAD32;
break;
- /* Unhandled instructions */
- case OP_PIECE:
default:
- internal_error(state, ins, "unhandled ins: %d %s\n",
- ins->op, tops(ins->op));
+ internal_error(state, ins, "unknown type in load");
break;
}
- ins = next;
- } while(ins != first);
+ break;
+ case OP_ADD:
+ case OP_SUB:
+ case OP_AND:
+ case OP_XOR:
+ case OP_OR:
+ case OP_SMUL:
+ ins->template_id = TEMPLATE_BINARY_REG;
+ if (get_imm32(ins, &RHS(ins, 1))) {
+ ins->template_id = TEMPLATE_BINARY_IMM;
+ }
+ break;
+ case OP_SL:
+ case OP_SSR:
+ case OP_USR:
+ ins->template_id = TEMPLATE_SL_CL;
+ if (get_imm8(ins, &RHS(ins, 1))) {
+ ins->template_id = TEMPLATE_SL_IMM;
+ }
+ break;
+ case OP_INVERT:
+ case OP_NEG:
+ ins->template_id = TEMPLATE_UNARY;
+ break;
+ case OP_EQ:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_EQ, OP_SET_EQ);
+ break;
+ case OP_NOTEQ:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_NOTEQ, OP_SET_NOTEQ);
+ break;
+ case OP_SLESS:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_SLESS, OP_SET_SLESS);
+ break;
+ case OP_ULESS:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_ULESS, OP_SET_ULESS);
+ break;
+ case OP_SMORE:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_SMORE, OP_SET_SMORE);
+ break;
+ case OP_UMORE:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_UMORE, OP_SET_UMORE);
+ break;
+ case OP_SLESSEQ:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_SLESSEQ, OP_SET_SLESSEQ);
+ break;
+ case OP_ULESSEQ:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_ULESSEQ, OP_SET_ULESSEQ);
+ break;
+ case OP_SMOREEQ:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_SMOREEQ, OP_SET_SMOREEQ);
+ break;
+ case OP_UMOREEQ:
+ bool_cmp(state, ins, OP_CMP, OP_JMP_UMOREEQ, OP_SET_UMOREEQ);
+ break;
+ case OP_LTRUE:
+ bool_cmp(state, ins, OP_TEST, OP_JMP_NOTEQ, OP_SET_NOTEQ);
+ break;
+ case OP_LFALSE:
+ bool_cmp(state, ins, OP_TEST, OP_JMP_EQ, OP_SET_EQ);
+ break;
+ case OP_BRANCH:
+ if (TRIPLE_RHS(ins->sizes) > 0) {
+ internal_error(state, ins, "bad branch test");
+ }
+ ins->op = OP_JMP;
+ ins->template_id = TEMPLATE_NOP;
+ break;
+ case OP_INB:
+ case OP_INW:
+ case OP_INL:
+ switch(ins->op) {
+ case OP_INB: ins->template_id = TEMPLATE_INB_DX; break;
+ case OP_INW: ins->template_id = TEMPLATE_INW_DX; break;
+ case OP_INL: ins->template_id = TEMPLATE_INL_DX; break;
+ }
+ if (get_imm8(ins, &RHS(ins, 0))) {
+ ins->template_id += 1;
+ }
+ break;
+ case OP_OUTB:
+ case OP_OUTW:
+ case OP_OUTL:
+ switch(ins->op) {
+ case OP_OUTB: ins->template_id = TEMPLATE_OUTB_DX; break;
+ case OP_OUTW: ins->template_id = TEMPLATE_OUTW_DX; break;
+ case OP_OUTL: ins->template_id = TEMPLATE_OUTL_DX; break;
+ }
+ if (get_imm8(ins, &RHS(ins, 1))) {
+ ins->template_id += 1;
+ }
+ break;
+ case OP_BSF:
+ case OP_BSR:
+ ins->template_id = TEMPLATE_BSF;
+ break;
+ case OP_RDMSR:
+ ins->template_id = TEMPLATE_RDMSR;
+ next = after_lhs(state, ins);
+ break;
+ case OP_WRMSR:
+ ins->template_id = TEMPLATE_WRMSR;
+ break;
+ case OP_HLT:
+ ins->template_id = TEMPLATE_NOP;
+ break;
+ case OP_ASM:
+ ins->template_id = TEMPLATE_NOP;
+ next = after_lhs(state, ins);
+ break;
+ /* Already transformed instructions */
+ case OP_TEST:
+ ins->template_id = TEMPLATE_TEST;
+ break;
+ case OP_CMP:
+ ins->template_id = TEMPLATE_CMP_REG;
+ if (get_imm32(ins, &RHS(ins, 1))) {
+ ins->template_id = TEMPLATE_CMP_IMM;
+ }
+ break;
+ case OP_JMP_EQ: case OP_JMP_NOTEQ:
+ case OP_JMP_SLESS: case OP_JMP_ULESS:
+ case OP_JMP_SMORE: case OP_JMP_UMORE:
+ case OP_JMP_SLESSEQ: case OP_JMP_ULESSEQ:
+ case OP_JMP_SMOREEQ: case OP_JMP_UMOREEQ:
+ ins->template_id = TEMPLATE_JMP;
+ 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:
+ case OP_SET_SLESSEQ: case OP_SET_ULESSEQ:
+ case OP_SET_SMOREEQ: case OP_SET_UMOREEQ:
+ ins->template_id = TEMPLATE_SET;
+ break;
+ /* Unhandled instructions */
+ case OP_PIECE:
+ default:
+ internal_error(state, ins, "unhandled ins: %d %s\n",
+ ins->op, tops(ins->op));
+ break;
+ }
+ return next;
}
static void generate_local_labels(struct compile_state *state)
@@ -12977,9 +15493,6 @@ static int check_reg(struct compile_state *state,
if (reg == REG_UNSET) {
internal_error(state, triple, "register not set");
}
- if (ID_REG_CLASSES(triple->id)) {
- internal_error(state, triple, "class specifier present");
- }
mask = arch_reg_regcm(state, reg);
if (!(classes & mask)) {
internal_error(state, triple, "reg %d in wrong class",
@@ -12992,6 +15505,7 @@ static const char *arch_reg_str(int reg)
{
static const char *regs[] = {
"%bad_register",
+ "%bad_register2",
"%eflags",
"%al", "%bl", "%cl", "%dl", "%ah", "%bh", "%ch", "%dh",
"%ax", "%bx", "%cx", "%dx", "%si", "%di", "%bp", "%sp",
@@ -13007,6 +15521,7 @@ static const char *arch_reg_str(int reg)
return regs[reg];
}
+
static const char *reg(struct compile_state *state, struct triple *triple,
int classes)
{
@@ -13030,6 +15545,25 @@ const char *type_suffix(struct compile_state *state, struct type *type)
return suffix;
}
+static void print_const_val(
+ struct compile_state *state, struct triple *ins, FILE *fp)
+{
+ switch(ins->op) {
+ case OP_INTCONST:
+ fprintf(fp, " $%ld ",
+ (long_t)(ins->u.cval));
+ break;
+ case OP_ADDRCONST:
+ fprintf(fp, " $L%lu+%lu ",
+ MISC(ins, 0)->u.cval,
+ ins->u.cval);
+ break;
+ default:
+ internal_error(state, ins, "unknown constant type");
+ break;
+ }
+}
+
static void print_binary_op(struct compile_state *state,
const char *op, struct triple *ins, FILE *fp)
{
@@ -13039,11 +15573,10 @@ static void print_binary_op(struct compile_state *state,
internal_error(state, ins, "invalid register assignment");
}
if (is_const(RHS(ins, 1))) {
- fprintf(fp, "\t%s $%lu, %s\n",
- op,
- RHS(ins, 1)->u.cval,
+ fprintf(fp, "\t%s ", op);
+ print_const_val(state, RHS(ins, 1), fp);
+ fprintf(fp, ", %s\n",
reg(state, RHS(ins, 0), mask));
-
}
else {
unsigned lmask, rmask;
@@ -13078,11 +15611,10 @@ static void print_op_shift(struct compile_state *state,
internal_error(state, ins, "invalid register assignment");
}
if (is_const(RHS(ins, 1))) {
- fprintf(fp, "\t%s $%lu, %s\n",
- op,
- RHS(ins, 1)->u.cval,
+ fprintf(fp, "\t%s ", op);
+ print_const_val(state, RHS(ins, 1), fp);
+ fprintf(fp, ", %s\n",
reg(state, RHS(ins, 0), mask));
-
}
else {
fprintf(fp, "\t%s %s, %s\n",
@@ -13112,8 +15644,9 @@ static void print_op_in(struct compile_state *state, struct triple *ins, FILE *f
internal_error(state, ins, "dst != %%eax");
}
if (is_const(RHS(ins, 0))) {
- fprintf(fp, "\t%s $%lu, %s\n",
- op, RHS(ins, 0)->u.cval,
+ fprintf(fp, "\t%s ", op);
+ print_const_val(state, RHS(ins, 0), fp);
+ fprintf(fp, ", %s\n",
reg(state, ins, mask));
}
else {
@@ -13149,9 +15682,10 @@ static void print_op_out(struct compile_state *state, struct triple *ins, FILE *
internal_error(state, ins, "src != %%eax");
}
if (is_const(RHS(ins, 1))) {
- fprintf(fp, "\t%s %s, $%lu\n",
- op, reg(state, RHS(ins, 0), mask),
- RHS(ins, 1)->u.cval);
+ fprintf(fp, "\t%s %s,",
+ op, reg(state, RHS(ins, 0), mask));
+ print_const_val(state, RHS(ins, 1), fp);
+ fprintf(fp, "\n");
}
else {
int addr_reg;
@@ -13171,6 +15705,8 @@ static void print_op_move(struct compile_state *state,
{
/* op_move is complex because there are many types
* of registers we can move between.
+ * Because OP_COPY will be introduced in arbitrary locations
+ * OP_COPY must not affect flags.
*/
int omit_copy = 1; /* Is it o.k. to omit a noop copy? */
struct triple *dst, *src;
@@ -13235,8 +15771,8 @@ static void print_op_move(struct compile_state *state,
}
}
/* Move 8/16bit to 16/32bit */
- else if ((src_regcm & (REGCM_GPR8 | REGCM_GPR16)) &&
- (dst_regcm & (REGC_GPR16 | REGCM_GPR32))) {
+ else if ((src_regcm & (REGCM_GPR8 | REGCM_GPR16)) &&
+ (dst_regcm & (REGCM_GPR16 | REGCM_GPR32))) {
const char *op;
op = is_signed(src->type)? "movsx": "movzx";
fprintf(fp, "\t%s %s, %s\n",
@@ -13247,7 +15783,7 @@ static void print_op_move(struct compile_state *state,
/* Move between sse registers */
else if ((src_regcm & dst_regcm & REGCM_XMM)) {
if ((src_reg != dst_reg) || !omit_copy) {
- fprintf(fp, "\tmovdqa %s %s\n",
+ fprintf(fp, "\tmovdqa %s, %s\n",
reg(state, src, src_regcm),
reg(state, dst, dst_regcm));
}
@@ -13256,7 +15792,7 @@ static void print_op_move(struct compile_state *state,
else if ((src_regcm & (REGCM_MMX | REGCM_XMM)) &&
(dst_regcm & (REGCM_MMX | REGCM_XMM))) {
if ((src_reg != dst_reg) || !omit_copy) {
- fprintf(fp, "\tmovq %s %s\n",
+ fprintf(fp, "\tmovq %s, %s\n",
reg(state, src, src_regcm),
reg(state, dst, dst_regcm));
}
@@ -13268,28 +15804,70 @@ static void print_op_move(struct compile_state *state,
reg(state, src, src_regcm),
reg(state, dst, dst_regcm));
}
+#if X86_4_8BIT_GPRS
+ /* Move from 8bit gprs to mmx/sse registers */
+ else if ((src_regcm & REGCM_GPR8) && (src_reg <= REG_DL) &&
+ (dst_regcm & (REGCM_MMX | REGCM_XMM))) {
+ const char *op;
+ int mid_reg;
+ op = is_signed(src->type)? "movsx":"movzx";
+ mid_reg = (src_reg - REGC_GPR8_FIRST) + REGC_GPR32_FIRST;
+ fprintf(fp, "\t%s %s, %s\n\tmovd %s, %s\n",
+ op,
+ reg(state, src, src_regcm),
+ arch_reg_str(mid_reg),
+ arch_reg_str(mid_reg),
+ reg(state, dst, dst_regcm));
+ }
+ /* Move from mmx/sse registers and 8bit gprs */
+ else if ((src_regcm & (REGCM_MMX | REGCM_XMM)) &&
+ (dst_regcm & REGCM_GPR8) && (dst_reg <= REG_DL)) {
+ int mid_reg;
+ mid_reg = (dst_reg - REGC_GPR8_FIRST) + REGC_GPR32_FIRST;
+ fprintf(fp, "\tmovd %s, %s\n",
+ reg(state, src, src_regcm),
+ arch_reg_str(mid_reg));
+ }
+ /* Move from 32bit gprs to 16bit gprs */
+ else if ((src_regcm & REGCM_GPR32) &&
+ (dst_regcm & REGCM_GPR16)) {
+ dst_reg = (dst_reg - REGC_GPR16_FIRST) + REGC_GPR32_FIRST;
+ if ((src_reg != dst_reg) || !omit_copy) {
+ fprintf(fp, "\tmov %s, %s\n",
+ arch_reg_str(src_reg),
+ arch_reg_str(dst_reg));
+ }
+ }
+ /* Move from 32bit gprs to 8bit gprs */
+ else if ((src_regcm & REGCM_GPR32) &&
+ (dst_regcm & REGCM_GPR8)) {
+ dst_reg = (dst_reg - REGC_GPR8_FIRST) + REGC_GPR32_FIRST;
+ if ((src_reg != dst_reg) || !omit_copy) {
+ fprintf(fp, "\tmov %s, %s\n",
+ arch_reg_str(src_reg),
+ arch_reg_str(dst_reg));
+ }
+ }
+ /* Move from 16bit gprs to 8bit gprs */
+ else if ((src_regcm & REGCM_GPR16) &&
+ (dst_regcm & REGCM_GPR8)) {
+ dst_reg = (dst_reg - REGC_GPR8_FIRST) + REGC_GPR16_FIRST;
+ if ((src_reg != dst_reg) || !omit_copy) {
+ fprintf(fp, "\tmov %s, %s\n",
+ arch_reg_str(src_reg),
+ arch_reg_str(dst_reg));
+ }
+ }
+#endif /* X86_4_8BIT_GPRS */
else {
internal_error(state, ins, "unknown copy type");
}
}
- else switch(src->op) {
- case OP_INTCONST:
- {
- long_t value;
- value = (long_t)(src->u.cval);
- fprintf(fp, "\tmov $%ld, %s\n",
- value,
+ else {
+ fprintf(fp, "\tmov ");
+ print_const_val(state, src, fp);
+ fprintf(fp, ", %s\n",
reg(state, dst, REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8));
- break;
- }
- case OP_ADDRCONST:
- fprintf(fp, "\tmov $L%lu+%lu, %s\n",
- RHS(src, 0)->u.cval,
- src->u.cval,
- reg(state, dst, REGCM_GPR32));
- break;
- default:
- internal_error(state, ins, "uknown copy operation");
}
}
@@ -13350,9 +15928,9 @@ static void print_op_smul(struct compile_state *state,
reg(state, RHS(ins, 0), REGCM_GPR32));
}
else {
- fprintf(fp, "\timul $%ld, %s\n",
- RHS(ins, 1)->u.cval,
- reg(state, RHS(ins, 0), REGCM_GPR32));
+ fprintf(fp, "\timul ");
+ print_const_val(state, RHS(ins, 1), fp);
+ fprintf(fp, ", %s\n", reg(state, RHS(ins, 0), REGCM_GPR32));
}
}
@@ -13367,9 +15945,9 @@ static void print_op_cmp(struct compile_state *state,
internal_error(state, ins, "bad dest register for cmp");
}
if (is_const(RHS(ins, 1))) {
- fprintf(fp, "\tcmp $%lu, %s\n",
- RHS(ins, 1)->u.cval,
- reg(state, RHS(ins, 0), mask));
+ fprintf(fp, "\tcmp ");
+ print_const_val(state, RHS(ins, 1), fp);
+ fprintf(fp, ", %s\n", reg(state, RHS(ins, 0), mask));
}
else {
unsigned lmask, rmask;
@@ -13406,6 +15984,7 @@ static void print_op_branch(struct compile_state *state,
bop = "jmp";
}
else {
+ struct triple *ptr;
if (TRIPLE_RHS(branch->sizes) != 1) {
internal_error(state, branch, "jmpcc without condition?");
}
@@ -13415,8 +15994,11 @@ static void print_op_branch(struct compile_state *state,
internal_error(state, branch, "bad branch test");
}
#warning "FIXME I have observed instructions between the test and branch instructions"
- if (RHS(branch, 0)->next != branch) {
- internal_error(state, branch, "branch does not follow test");
+ ptr = RHS(branch, 0);
+ for(ptr = RHS(branch, 0)->next; ptr != branch; ptr = ptr->next) {
+ if (ptr->op != OP_COPY) {
+ internal_error(state, branch, "branch does not follow test");
+ }
}
switch(branch->op) {
case OP_JMP_EQ: bop = "jz"; break;
@@ -13532,27 +16114,23 @@ static void print_const(struct compile_state *state,
}
break;
}
-#if 0
- case OP_ADDRCONST:
- fprintf(fp, ".int $L%lu+%lu",
- ins->left->u.cval,
- ins->u.cval);
- break;
-#endif
default:
internal_error(state, ins, "Unknown constant type");
break;
}
}
+#define TEXT_SECTION ".rom.text"
+#define DATA_SECTION ".rom.data"
+
static void print_sdecl(struct compile_state *state,
struct triple *ins, FILE *fp)
{
- fprintf(fp, ".section \".rom.data\"\n");
+ fprintf(fp, ".section \"" DATA_SECTION "\"\n");
fprintf(fp, ".balign %d\n", align_of(state, ins->type));
fprintf(fp, "L%lu:\n", ins->u.cval);
print_const(state, MISC(ins, 0), fp);
- fprintf(fp, ".section \".rom.text\"\n");
+ fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
}
@@ -13563,6 +16141,9 @@ static void print_instruction(struct compile_state *state,
* everything is in a valid register.
*/
switch(ins->op) {
+ case OP_ASM:
+ print_op_asm(state, ins, fp);
+ break;
case OP_ADD: print_binary_op(state, "add", ins, fp); break;
case OP_SUB: print_binary_op(state, "sub", ins, fp); break;
case OP_AND: print_binary_op(state, "and", ins, fp); break;
@@ -13576,6 +16157,7 @@ static void print_instruction(struct compile_state *state,
case OP_INVERT: print_unary_op(state, "not", ins, fp); break;
case OP_INTCONST:
case OP_ADDRCONST:
+ case OP_BLOBCONST:
/* Don't generate anything here for constants */
case OP_PHI:
/* Don't generate anything for variable declarations. */
@@ -13624,7 +16206,7 @@ static void print_instruction(struct compile_state *state,
print_op_bit_scan(state, ins, fp);
break;
case OP_RDMSR:
- verify_lhs(state, ins);
+ after_lhs(state, ins);
fprintf(fp, "\trdmsr\n");
break;
case OP_WRMSR:
@@ -13669,8 +16251,8 @@ static void print_instructions(struct compile_state *state)
last_line = -1;
last_col = -1;
last_filename = 0;
- fp = stdout;
- fprintf(fp, ".section \".rom.text\"\n");
+ fp = state->output;
+ fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
first = RHS(state->main_function, 0);
ins = first;
do {
@@ -13716,7 +16298,8 @@ static void print_tokens(struct compile_state *state)
} while(tk->tok != TOK_EOF);
}
-static void compile(char *filename, int debug, int opt)
+static void compile(const char *filename, const char *ofilename,
+ int cpu, int debug, int opt)
{
int i;
struct compile_state state;
@@ -13727,8 +16310,16 @@ static void compile(char *filename, int debug, int opt)
state.token[i].tok = -1;
}
/* Remember the debug settings */
- state.debug = debug;
+ state.cpu = cpu;
+ state.debug = debug;
state.optimize = opt;
+ /* Remember the output filename */
+ state.ofilename = ofilename;
+ state.output = fopen(state.ofilename, "w");
+ if (!state.output) {
+ error(&state, 0, "Cannot open output file %s\n",
+ ofilename);
+ }
/* Prep the preprocessor */
state.if_depth = 0;
state.if_value = 0;
@@ -13754,6 +16345,7 @@ static void compile(char *filename, int debug, int opt)
* optimize the intermediate code
*/
optimize(&state);
+
generate_code(&state);
if (state.debug) {
fprintf(stderr, "done\n");
@@ -13786,10 +16378,14 @@ static void arg_error(char *fmt, ...)
int main(int argc, char **argv)
{
- char *filename;
+ const char *filename;
+ const char *ofilename;
+ int cpu;
int last_argc;
int debug;
int optimize;
+ cpu = CPU_DEFAULT;
+ ofilename = "auto.inc";
optimize = 0;
debug = 0;
last_argc = -1;
@@ -13811,12 +16407,26 @@ int main(int argc, char **argv)
argv++;
argc--;
}
+ else if ((strcmp(argv[1], "-o") == 0) && (argc > 2)) {
+ ofilename = argv[2];
+ argv += 2;
+ argc -= 2;
+ }
+ else if (strncmp(argv[1], "-mcpu=", 6) == 0) {
+ cpu = arch_encode_cpu(argv[1] + 6);
+ if (cpu == BAD_CPU) {
+ arg_error("Invalid cpu specified: %s\n",
+ argv[1] + 6);
+ }
+ argv++;
+ argc--;
+ }
}
if (argc != 2) {
arg_error("Wrong argument count %d\n", argc);
}
filename = argv[1];
- compile(filename, debug, optimize);
+ compile(filename, ofilename, cpu, debug, optimize);
return 0;
}
diff --git a/util/romcc/tests/hello_world2.c b/util/romcc/tests/hello_world2.c
new file mode 100644
index 0000000000..7990dcb518
--- /dev/null
+++ b/util/romcc/tests/hello_world2.c
@@ -0,0 +1,127 @@
+void outb(unsigned char value, unsigned short port)
+{
+ __builtin_outb(value, port);
+}
+
+unsigned char inb(unsigned short port)
+{
+ return __builtin_inb(port);
+}
+
+/* Base Address */
+#ifndef TTYS0_BASE
+#define TTYS0_BASE 0x3f8
+#endif
+
+#ifndef TTYS0_BAUD
+#define TTYS0_BAUD 115200
+#endif
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+#if TTYS0_BAUD == 115200
+#define TTYS0_DIV (1)
+#else
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+#endif
+
+/* Line Control Settings */
+#ifndef TTYS0_LCS
+/* Set 8bit, 1 stop bit, no parity */
+#define TTYS0_LCS 0x3
+#endif
+
+#define UART_LCS TTYS0_LCS
+
+/* Data */
+#define UART_RBR 0x00
+#define UART_TBR 0x00
+
+/* Control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* Status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+int uart_can_tx_byte(void)
+{
+ return inb(TTYS0_BASE + UART_LSR) & 0x20;
+}
+
+void uart_wait_to_tx_byte(void)
+{
+ while(!uart_can_tx_byte())
+ ;
+}
+
+void uart_wait_until_sent(void)
+{
+ while(!(inb(TTYS0_BASE + UART_LSR) & 0x40))
+ ;
+}
+
+static void uart_tx_byte(unsigned char data)
+{
+ uart_wait_to_tx_byte();
+ outb(data, TTYS0_BASE + UART_TBR);
+ /* Make certain the data clears the fifos */
+ uart_wait_until_sent();
+}
+
+
+void uart_init(void)
+{
+ /* disable interrupts */
+ outb(0x0, TTYS0_BASE + UART_IER);
+ /* enable fifo's */
+ outb(0x01, TTYS0_BASE + UART_FCR);
+ /* Set Baud Rate Divisor to 12 ==> 115200 Baud */
+ outb(0x80 | UART_LCS, TTYS0_BASE + UART_LCR);
+ outb(TTYS0_DIV & 0xFF, TTYS0_BASE + UART_DLL);
+ outb((TTYS0_DIV >> 8) & 0xFF, TTYS0_BASE + UART_DLM);
+ outb(UART_LCS, TTYS0_BASE + UART_LCR);
+}
+
+
+void __console_tx_char(unsigned char byte)
+{
+ uart_tx_byte(byte);
+
+}
+
+void __console_tx_string(char *str)
+{
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ __console_tx_char(ch);
+ }
+}
+
+
+void print_debug_char(unsigned char byte) { __console_tx_char(byte); }
+void print_debug(char *str) { __console_tx_string(str); }
+
+void main(void)
+{
+ static const char msg[] = "hello world\r\n";
+ uart_init();
+#if 0
+ print_debug(msg);
+#endif
+#if 1
+ print_debug("hello world\r\n");
+#endif
+ while(1) {
+ ;
+ }
+}
diff --git a/util/romcc/tests/ldscript.ld b/util/romcc/tests/ldscript.ld
new file mode 100644
index 0000000000..97b307fc66
--- /dev/null
+++ b/util/romcc/tests/ldscript.ld
@@ -0,0 +1,20 @@
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x1000;
+ .text . : {
+ . = ALIGN(16);
+ _start = . ;
+ *(.rom.text);
+ *(.text)
+ . = ALIGN(16);
+ }
+ .data . : {
+ . = ALIGN(16);
+ *(.rom.data);
+ *(.data)
+ . = ALIGN(16);
+ }
+} \ No newline at end of file
diff --git a/util/romcc/tests/raminit_test.c b/util/romcc/tests/raminit_test.c
index 8dd9c977e5..9b6cf5d31c 100644
--- a/util/romcc/tests/raminit_test.c
+++ b/util/romcc/tests/raminit_test.c
@@ -1,7 +1,8 @@
#define HAVE_STRING_SUPPORT 0
-#define HAVE_CAST_SUPPORT 0
-#define HAVE_STATIC_ARRAY_SUPPORT 0
-#define HAVE_POINTER_SUPPORT 0
+#define HAVE_CAST_SUPPORT 1
+#define HAVE_STATIC_ARRAY_SUPPORT 1
+#define HAVE_POINTER_SUPPORT 1
+#define HAVE_MACRO_ARG_SUPPORT 0
void outb(unsigned char value, unsigned short port)
{
@@ -196,7 +197,7 @@ void __console_tx_string(char *str)
{
unsigned char ch;
while((ch = *str++) != '\0') {
- __console_tx_byte(ch);
+ __console_tx_char(ch);
}
}
#else
@@ -1112,7 +1113,11 @@ static void dimms_read(unsigned long offset)
print_debug("\n");
#endif
#if HAVE_POINTER_SUPPORT
+#if HAVE_MACRO_ARG_SUPPORT
dummy = RAM(unsigned long, addr);
+#else
+ dummy = *((volatile unsigned long *)(addr));
+#endif
#endif
#if HAVE_STRING_SUPPORT
print_debug("Reading ");
@@ -1120,7 +1125,11 @@ static void dimms_read(unsigned long offset)
print_debug("\n");
#endif
#if HAVE_POINTER_SUPPORT
+#if HAVE_MACRO_ARG_SUPPORT
dummy = RAM(unsigned long, addr ^ 0xdff8);
+#else
+ dummy = *((volatile unsigned long *)(addr ^ 0xdff8));
+#endif
#endif
#if HAVE_STRING_SUPPORT
print_debug("Read ");
diff --git a/util/romcc/tests/raminit_test2.c b/util/romcc/tests/raminit_test2.c
index 8dd9c977e5..68747a7a91 100644
--- a/util/romcc/tests/raminit_test2.c
+++ b/util/romcc/tests/raminit_test2.c
@@ -1,7 +1,8 @@
-#define HAVE_STRING_SUPPORT 0
-#define HAVE_CAST_SUPPORT 0
-#define HAVE_STATIC_ARRAY_SUPPORT 0
-#define HAVE_POINTER_SUPPORT 0
+#define HAVE_STRING_SUPPORT 1
+#define HAVE_CAST_SUPPORT 1
+#define HAVE_STATIC_ARRAY_SUPPORT 1
+#define HAVE_POINTER_SUPPORT 1
+#define HAVE_MACRO_ARG_SUPPORT 0
void outb(unsigned char value, unsigned short port)
{
@@ -196,7 +197,7 @@ void __console_tx_string(char *str)
{
unsigned char ch;
while((ch = *str++) != '\0') {
- __console_tx_byte(ch);
+ __console_tx_char(ch);
}
}
#else
@@ -1112,7 +1113,11 @@ static void dimms_read(unsigned long offset)
print_debug("\n");
#endif
#if HAVE_POINTER_SUPPORT
+#if HAVE_MACRO_ARG_SUPPORT
dummy = RAM(unsigned long, addr);
+#else
+ dummy = *((volatile unsigned long *)(addr));
+#endif
#endif
#if HAVE_STRING_SUPPORT
print_debug("Reading ");
@@ -1120,7 +1125,11 @@ static void dimms_read(unsigned long offset)
print_debug("\n");
#endif
#if HAVE_POINTER_SUPPORT
+#if HAVE_MACRO_ARG_SUPPORT
dummy = RAM(unsigned long, addr ^ 0xdff8);
+#else
+ dummy = *((volatile unsigned long *)(addr ^ 0xdff8));
+#endif
#endif
#if HAVE_STRING_SUPPORT
print_debug("Read ");
diff --git a/util/romcc/tests/raminit_test3.c b/util/romcc/tests/raminit_test3.c
new file mode 100644
index 0000000000..dc3b4760c2
--- /dev/null
+++ b/util/romcc/tests/raminit_test3.c
@@ -0,0 +1,1076 @@
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+# 1 "<built-in>"
+# 1 "<command line>"
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/arch/i386/include/stdint.h" 1
+# 11 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/arch/i386/include/stdint.h"
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+
+
+
+
+
+
+
+typedef unsigned char uint_least8_t;
+typedef signed char int_least8_t;
+
+typedef unsigned short uint_least16_t;
+typedef signed short int_least16_t;
+
+typedef unsigned int uint_least32_t;
+typedef signed int int_least32_t;
+
+
+
+
+
+
+
+typedef unsigned char uint_fast8_t;
+typedef signed char int_fast8_t;
+
+typedef unsigned int uint_fast16_t;
+typedef signed int int_fast16_t;
+
+typedef unsigned int uint_fast32_t;
+typedef signed int int_fast32_t;
+
+
+
+
+
+
+
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+
+
+
+
+
+typedef long int intmax_t;
+typedef unsigned long int uintmax_t;
+# 3 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c" 2
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/include/device/pci_def.h" 1
+# 4 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c" 2
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/arch/i386/include/arch/romcc_io.h" 1
+static void outb(unsigned char value, unsigned short port)
+{
+ __builtin_outb(value, port);
+}
+
+static void outw(unsigned short value, unsigned short port)
+{
+ __builtin_outw(value, port);
+}
+
+static void outl(unsigned int value, unsigned short port)
+{
+ __builtin_outl(value, port);
+}
+
+
+static unsigned char inb(unsigned short port)
+{
+ return __builtin_inb(port);
+}
+
+
+static unsigned char inw(unsigned short port)
+{
+ return __builtin_inw(port);
+}
+
+static unsigned char inl(unsigned short port)
+{
+ return __builtin_inl(port);
+}
+
+static void hlt(void)
+{
+ __builtin_hlt();
+}
+
+typedef __builtin_msr_t msr_t;
+
+static msr_t rdmsr(unsigned long index)
+{
+ return __builtin_rdmsr(index);
+}
+
+static void wrmsr(unsigned long index, msr_t msr)
+{
+ __builtin_wrmsr(index, msr.lo, msr.hi);
+}
+
+
+
+
+
+
+
+static unsigned char pci_read_config8(unsigned addr)
+{
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inb(0xCFC + (addr & 3));
+}
+
+static unsigned short pci_read_config16(unsigned addr)
+{
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inw(0xCFC + (addr & 2));
+}
+
+static unsigned int pci_read_config32(unsigned addr)
+{
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inl(0xCFC);
+}
+
+static void pci_write_config8(unsigned addr, unsigned char value)
+{
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outb(value, 0xCFC + (addr & 3));
+}
+
+static void pci_write_config16(unsigned addr, unsigned short value)
+{
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outw(value, 0xCFC + (addr & 2));
+}
+
+static void pci_write_config32(unsigned addr, unsigned int value)
+{
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outl(value, 0xCFC);
+}
+# 5 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c" 2
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/pc80/serial.c" 1
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/include/part/fallback_boot.h" 1
+# 2 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/pc80/serial.c" 2
+# 44 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/pc80/serial.c"
+static int uart_can_tx_byte(void)
+{
+ return inb(0x3f8 + 0x05) & 0x20;
+}
+
+static void uart_wait_to_tx_byte(void)
+{
+ while(!uart_can_tx_byte())
+ ;
+}
+
+static void uart_wait_until_sent(void)
+{
+ while(!(inb(0x3f8 + 0x05) & 0x40))
+ ;
+}
+
+static void uart_tx_byte(unsigned char data)
+{
+ uart_wait_to_tx_byte();
+ outb(data, 0x3f8 + 0x00);
+
+ uart_wait_until_sent();
+}
+
+static void uart_init(void)
+{
+
+ outb(0x0, 0x3f8 + 0x01);
+
+ outb(0x01, 0x3f8 + 0x02);
+
+ outb(0x80 | 0x3, 0x3f8 + 0x03);
+# 89 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/pc80/serial.c"
+ outb((115200/9600) & 0xFF, 0x3f8 + 0x00);
+ outb(((115200/9600) >> 8) & 0xFF, 0x3f8 + 0x01);
+
+ outb(0x3, 0x3f8 + 0x03);
+}
+# 6 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c" 2
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/arch/i386/lib/console.c" 1
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/include/console/loglevel.h" 1
+# 2 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/arch/i386/lib/console.c" 2
+
+static void __console_tx_byte(unsigned char byte)
+{
+ uart_tx_byte(byte);
+}
+
+static void __console_tx_nibble(unsigned nibble)
+{
+ unsigned char digit;
+ digit = nibble + '0';
+ if (digit > '9') {
+ digit += 39;
+ }
+ __console_tx_byte(digit);
+}
+
+static void __console_tx_char(int loglevel, unsigned char byte)
+{
+ if (8 > loglevel) {
+ uart_tx_byte(byte);
+ }
+}
+
+static void __console_tx_hex8(int loglevel, unsigned char value)
+{
+ if (8 > loglevel) {
+ __console_tx_nibble((value >> 4U) & 0x0fU);
+ __console_tx_nibble(value & 0x0fU);
+ }
+}
+
+static void __console_tx_hex16(int loglevel, unsigned short value)
+{
+ if (8 > loglevel) {
+ __console_tx_nibble((value >> 12U) & 0x0fU);
+ __console_tx_nibble((value >> 8U) & 0x0fU);
+ __console_tx_nibble((value >> 4U) & 0x0fU);
+ __console_tx_nibble(value & 0x0fU);
+ }
+}
+
+static void __console_tx_hex32(int loglevel, unsigned int value)
+{
+ if (8 > loglevel) {
+ __console_tx_nibble((value >> 28U) & 0x0fU);
+ __console_tx_nibble((value >> 24U) & 0x0fU);
+ __console_tx_nibble((value >> 20U) & 0x0fU);
+ __console_tx_nibble((value >> 16U) & 0x0fU);
+ __console_tx_nibble((value >> 12U) & 0x0fU);
+ __console_tx_nibble((value >> 8U) & 0x0fU);
+ __console_tx_nibble((value >> 4U) & 0x0fU);
+ __console_tx_nibble(value & 0x0fU);
+ }
+}
+
+static void __console_tx_string(int loglevel, const char *str)
+{
+ if (8 > loglevel) {
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ __console_tx_byte(ch);
+ }
+ }
+}
+
+static void print_emerg_char(unsigned char byte) { __console_tx_char(0, byte); }
+static void print_emerg_hex8(unsigned char value){ __console_tx_hex8(0, value); }
+static void print_emerg_hex16(unsigned short value){ __console_tx_hex16(0, value); }
+static void print_emerg_hex32(unsigned int value) { __console_tx_hex32(0, value); }
+static void print_emerg(const char *str) { __console_tx_string(0, str); }
+
+static void print_alert_char(unsigned char byte) { __console_tx_char(1, byte); }
+static void print_alert_hex8(unsigned char value) { __console_tx_hex8(1, value); }
+static void print_alert_hex16(unsigned short value){ __console_tx_hex16(1, value); }
+static void print_alert_hex32(unsigned int value) { __console_tx_hex32(1, value); }
+static void print_alert(const char *str) { __console_tx_string(1, str); }
+
+static void print_crit_char(unsigned char byte) { __console_tx_char(2, byte); }
+static void print_crit_hex8(unsigned char value) { __console_tx_hex8(2, value); }
+static void print_crit_hex16(unsigned short value){ __console_tx_hex16(2, value); }
+static void print_crit_hex32(unsigned int value) { __console_tx_hex32(2, value); }
+static void print_crit(const char *str) { __console_tx_string(2, str); }
+
+static void print_err_char(unsigned char byte) { __console_tx_char(3, byte); }
+static void print_err_hex8(unsigned char value) { __console_tx_hex8(3, value); }
+static void print_err_hex16(unsigned short value){ __console_tx_hex16(3, value); }
+static void print_err_hex32(unsigned int value) { __console_tx_hex32(3, value); }
+static void print_err(const char *str) { __console_tx_string(3, str); }
+
+static void print_warning_char(unsigned char byte) { __console_tx_char(4, byte); }
+static void print_warning_hex8(unsigned char value) { __console_tx_hex8(4, value); }
+static void print_warning_hex16(unsigned short value){ __console_tx_hex16(4, value); }
+static void print_warning_hex32(unsigned int value) { __console_tx_hex32(4, value); }
+static void print_warning(const char *str) { __console_tx_string(4, str); }
+
+static void print_notice_char(unsigned char byte) { __console_tx_char(5, byte); }
+static void print_notice_hex8(unsigned char value) { __console_tx_hex8(5, value); }
+static void print_notice_hex16(unsigned short value){ __console_tx_hex16(5, value); }
+static void print_notice_hex32(unsigned int value) { __console_tx_hex32(5, value); }
+static void print_notice(const char *str) { __console_tx_string(5, str); }
+
+static void print_info_char(unsigned char byte) { __console_tx_char(6, byte); }
+static void print_info_hex8(unsigned char value) { __console_tx_hex8(6, value); }
+static void print_info_hex16(unsigned short value){ __console_tx_hex16(6, value); }
+static void print_info_hex32(unsigned int value) { __console_tx_hex32(6, value); }
+static void print_info(const char *str) { __console_tx_string(6, str); }
+
+static void print_debug_char(unsigned char byte) { __console_tx_char(7, byte); }
+static void print_debug_hex8(unsigned char value) { __console_tx_hex8(7, value); }
+static void print_debug_hex16(unsigned short value){ __console_tx_hex16(7, value); }
+static void print_debug_hex32(unsigned int value) { __console_tx_hex32(7, value); }
+static void print_debug(const char *str) { __console_tx_string(7, str); }
+
+static void print_spew_char(unsigned char byte) { __console_tx_char(8, byte); }
+static void print_spew_hex8(unsigned char value) { __console_tx_hex8(8, value); }
+static void print_spew_hex16(unsigned short value){ __console_tx_hex16(8, value); }
+static void print_spew_hex32(unsigned int value) { __console_tx_hex32(8, value); }
+static void print_spew(const char *str) { __console_tx_string(8, str); }
+# 128 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/arch/i386/lib/console.c"
+static void console_init(void)
+{
+ static const char console_test[] =
+ "\r\n\r\nLinuxBIOS-"
+ "1.1.0"
+ ".0Fallback"
+ " "
+ "Mon Jun 9 18:15:20 MDT 2003"
+ " starting...\r\n";
+ print_info(console_test);
+}
+# 7 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c" 2
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/ram/ramtest.c" 1
+static void write_phys(unsigned long addr, unsigned long value)
+{
+ volatile unsigned long *ptr;
+ ptr = (void *)addr;
+ *ptr = value;
+}
+
+static unsigned long read_phys(unsigned long addr)
+{
+ volatile unsigned long *ptr;
+ ptr = (void *)addr;
+ return *ptr;
+}
+
+void ram_fill(unsigned long start, unsigned long stop)
+{
+ unsigned long addr;
+
+
+
+ print_debug("DRAM fill: ");
+ print_debug_hex32(start);
+ print_debug("-");
+ print_debug_hex32(stop);
+ print_debug("\r\n");
+ for(addr = start; addr < stop ; addr += 4) {
+
+ if ((addr & 0xffff) == 0) {
+ print_debug_hex32(addr);
+ print_debug("\r");
+ }
+ write_phys(addr, addr);
+ };
+
+ print_debug_hex32(addr);
+ print_debug("\r\nDRAM filled\r\n");
+}
+
+void ram_verify(unsigned long start, unsigned long stop)
+{
+ unsigned long addr;
+
+
+
+ print_debug("DRAM verify: ");
+ print_debug_hex32(start);
+ print_debug_char('-');
+ print_debug_hex32(stop);
+ print_debug("\r\n");
+ for(addr = start; addr < stop ; addr += 4) {
+ unsigned long value;
+
+ if ((addr & 0xffff) == 0) {
+ print_debug_hex32(addr);
+ print_debug("\r");
+ }
+ value = read_phys(addr);
+ if (value != addr) {
+
+ print_err_hex32(addr);
+ print_err_char(':');
+ print_err_hex32(value);
+ print_err("\r\n");
+ }
+ }
+
+ print_debug_hex32(addr);
+ print_debug("\r\nDRAM verified\r\n");
+}
+
+
+void ramcheck(unsigned long start, unsigned long stop)
+{
+ int result;
+
+
+
+
+
+ print_debug("Testing DRAM : ");
+ print_debug_hex32(start);
+ print_debug("-");
+ print_debug_hex32(stop);
+ print_debug("\r\n");
+ ram_fill(start, stop);
+ ram_verify(start, stop);
+ print_debug("Done.\n");
+}
+# 8 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c" 2
+
+static void die(const char *str)
+{
+ print_emerg(str);
+ do {
+ hlt();
+ } while(1);
+}
+
+
+
+
+static void sdram_set_registers(void)
+{
+ static const unsigned int register_values[] = {
+# 51 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x44) & 0xFF)), 0x0000f8f8, 0x003f0000,
+
+
+
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x4C) & 0xFF)), 0x0000f8f8, 0x00000001,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x54) & 0xFF)), 0x0000f8f8, 0x00000002,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x5C) & 0xFF)), 0x0000f8f8, 0x00000003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x64) & 0xFF)), 0x0000f8f8, 0x00000004,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x6C) & 0xFF)), 0x0000f8f8, 0x00000005,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x74) & 0xFF)), 0x0000f8f8, 0x00000006,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x7C) & 0xFF)), 0x0000f8f8, 0x00000007,
+# 93 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x40) & 0xFF)), 0x0000f8fc, 0x00000003,
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x48) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x50) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x58) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x60) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x68) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x70) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x78) & 0xFF)), 0x0000f8fc, 0x00400000,
+# 145 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x84) & 0xFF)), 0x00000048, 0x00e1ff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x8C) & 0xFF)), 0x00000048, 0x00dfff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x94) & 0xFF)), 0x00000048, 0x00e3ff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x9C) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA4) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xAC) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB4) & 0xFF)), 0x00000048, 0x00000b00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xBC) & 0xFF)), 0x00000048, 0x00fe0b00,
+# 180 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x80) & 0xFF)), 0x000000f0, 0x00e00003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x88) & 0xFF)), 0x000000f0, 0x00d80003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x90) & 0xFF)), 0x000000f0, 0x00e20003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x98) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA0) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA8) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB0) & 0xFF)), 0x000000f0, 0x00000a03,
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB8) & 0xFF)), 0x000000f0, 0x00400003,
+# 219 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC4) & 0xFF)), 0xFE000FC8, 0x0000d000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xCC) & 0xFF)), 0xFE000FC8, 0x000ff000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD4) & 0xFF)), 0xFE000FC8, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xDC) & 0xFF)), 0xFE000FC8, 0x00000000,
+# 249 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC0) & 0xFF)), 0xFE000FCC, 0x0000d003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC8) & 0xFF)), 0xFE000FCC, 0x00001013,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD0) & 0xFF)), 0xFE000FCC, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD8) & 0xFF)), 0xFE000FCC, 0x00000000,
+# 290 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE0) & 0xFF)), 0x0000FC88, 0xff000003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE4) & 0xFF)), 0x0000FC88, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE8) & 0xFF)), 0x0000FC88, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xEC) & 0xFF)), 0x0000FC88, 0x00000000,
+# 316 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x40) & 0xFF)), 0x001f01fe, 0x00000001,
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x44) & 0xFF)), 0x001f01fe, 0x01000001,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x48) & 0xFF)), 0x001f01fe, 0x02000001,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x4C) & 0xFF)), 0x001f01fe, 0x03000001,
+
+
+
+
+
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x50) & 0xFF)), 0x001f01fe, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x54) & 0xFF)), 0x001f01fe, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x58) & 0xFF)), 0x001f01fe, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x5C) & 0xFF)), 0x001f01fe, 0x00000000,
+# 351 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x60) & 0xFF)), 0xC01f01ff, 0x00e0fe00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x64) & 0xFF)), 0xC01f01ff, 0x00e0fe00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x68) & 0xFF)), 0xC01f01ff, 0x00e0fe00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x6C) & 0xFF)), 0xC01f01ff, 0x00e0fe00,
+
+
+
+
+
+
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x70) & 0xFF)), 0xC01f01ff, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x74) & 0xFF)), 0xC01f01ff, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x78) & 0xFF)), 0xC01f01ff, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x7C) & 0xFF)), 0xC01f01ff, 0x00000000,
+# 387 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x80) & 0xFF)), 0xffff8888, 0x00000033,
+# 456 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x88) & 0xFF)), 0xe8088008, 0x03623125,
+# 487 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x8c) & 0xFF)), 0xff8fe08e, 0x00000930,
+# 563 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x90) & 0xFF)), 0xf0000000,
+ (4 << 25)|(0 << 24)|
+ (0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)|
+ (1 << 19)|(1 << 18)|(0 << 17)|(0 << 16)|
+ (2 << 14)|(0 << 13)|(0 << 12)|
+ (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)|
+ (0 << 3) |(0 << 1) |(0 << 0),
+# 635 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x94) & 0xFF)), 0xc180f0f0, 0x0e2b0a05,
+# 655 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x98) & 0xFF)), 0xfc00ffff, 0x00000000,
+# 689 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((3) & 0x07) << 8) | ((0x58) & 0xFF)), 0xffe0e0e0, 0x00000000,
+# 698 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((3) & 0x07) << 8) | ((0x5C) & 0xFF)), 0x0000003e, 0x00000000,
+
+
+
+
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((3) & 0x07) << 8) | ((0x60) & 0xFF)), 0xffffff00, 0x00000000,
+ };
+ int i;
+ int max;
+ print_debug("setting up CPU0 northbridge registers\r\n");
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ for(i = 0; i < max; i += 3) {
+ unsigned long reg;
+
+
+
+
+
+
+ reg = pci_read_config32(register_values[i]);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2];
+ pci_write_config32(register_values[i], reg);
+ }
+ print_debug("done.\r\n");
+}
+# 743 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+static void sdram_set_spd_registers(void)
+{
+ unsigned long dcl;
+ dcl = pci_read_config32(( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x90) & 0xFF)));
+
+ dcl &= ~(1<<17);
+ pci_write_config32(( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x90) & 0xFF)), dcl);
+}
+
+
+static void sdram_enable(void)
+{
+ unsigned long dcl;
+
+
+ dcl = pci_read_config32(( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x90) & 0xFF)));
+ print_debug("dcl: ");
+ print_debug_hex32(dcl);
+ print_debug("\r\n");
+ dcl |= (1<<3);
+ pci_write_config32(( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x90) & 0xFF)), dcl);
+ dcl &= ~(1<<3);
+ dcl &= ~(1<<0);
+ dcl &= ~(1<<1);
+ dcl &= ~(1<<2);
+ dcl |= (1<<8);
+ pci_write_config32(( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x90) & 0xFF)), dcl);
+
+ print_debug("Initializing memory: ");
+ int loops = 0;
+ do {
+ dcl = pci_read_config32(( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((2) & 0x07) << 8) | ((0x90) & 0xFF)));
+ loops += 1;
+ if ((loops & 1023) == 0) {
+ print_debug(".");
+ }
+ } while(((dcl & (1<<8)) != 0) && (loops < 300000));
+ if (loops >= 300000) {
+ print_debug(" failed\r\n");
+ } else {
+ print_debug(" done\r\n");
+ }
+# 803 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+}
+
+static void sdram_first_normal_reference(void) {}
+static void sdram_enable_refresh(void) {}
+static void sdram_special_finishup(void) {}
+
+# 1 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/sdram/generic_sdram.c" 1
+void sdram_no_memory(void)
+{
+ print_err("No memory!!\r\n");
+ while(1) {
+ hlt();
+ }
+}
+
+
+void sdram_initialize(void)
+{
+ print_debug("Ram1\r\n");
+
+ sdram_set_registers();
+
+ print_debug("Ram2\r\n");
+
+ sdram_set_spd_registers();
+
+ print_debug("Ram3\r\n");
+
+
+
+
+ sdram_enable();
+
+ print_debug("Ram4\r\n");
+ sdram_first_normal_reference();
+
+ print_debug("Ram5\r\n");
+ sdram_enable_refresh();
+ sdram_special_finishup();
+
+ print_debug("Ram6\r\n");
+}
+# 810 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c" 2
+
+static int boot_cpu(void)
+{
+ volatile unsigned long *local_apic;
+ unsigned long apic_id;
+ int bsp;
+ msr_t msr;
+ msr = rdmsr(0x1b);
+ bsp = !!(msr.lo & (1 << 8));
+ if (bsp) {
+ print_debug("Bootstrap cpu\r\n");
+ }
+
+ return bsp;
+}
+
+static int cpu_init_detected(void)
+{
+ unsigned long dcl;
+ int cpu_init;
+
+ unsigned long htic;
+
+ htic = pci_read_config32(( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x6c) & 0xFF)));
+# 849 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ cpu_init = (htic & (1<<6));
+ if (cpu_init) {
+ print_debug("CPU INIT Detected.\r\n");
+ }
+ return cpu_init;
+}
+
+static void setup_coherent_ht_domain(void)
+{
+ static const unsigned int register_values[] = {
+# 884 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x40) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x44) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x48) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x4c) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x50) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x54) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x58) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x5c) & 0xFF)), 0xfff0f0f0, 0x00010101,
+# 983 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x68) & 0xFF)), 0x00800000, 0x0f00840f,
+# 1005 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x6C) & 0xFF)), 0xffffff8c, 0x00000000 | (1 << 6) |(1 << 5)| (1 << 4),
+# 1082 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x84) & 0xFF)), 0x00009c05, 0x11110020,
+# 1127 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x88) & 0xFF)), 0xfffff0ff, 0x00000200,
+# 1148 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x94) & 0xFF)), 0xff000000, 0x00ff0000,
+# 1182 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x44) & 0xFF)), 0x0000f8f8, 0x003f0000,
+
+
+
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x4C) & 0xFF)), 0x0000f8f8, 0x00000001,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x54) & 0xFF)), 0x0000f8f8, 0x00000002,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x5C) & 0xFF)), 0x0000f8f8, 0x00000003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x64) & 0xFF)), 0x0000f8f8, 0x00000004,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x6C) & 0xFF)), 0x0000f8f8, 0x00000005,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x74) & 0xFF)), 0x0000f8f8, 0x00000006,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x7C) & 0xFF)), 0x0000f8f8, 0x00000007,
+# 1224 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x40) & 0xFF)), 0x0000f8fc, 0x00000003,
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x48) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x50) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x58) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x60) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x68) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x70) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x78) & 0xFF)), 0x0000f8fc, 0x00400000,
+# 1276 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x84) & 0xFF)), 0x00000048, 0x00e1ff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x8C) & 0xFF)), 0x00000048, 0x00dfff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x94) & 0xFF)), 0x00000048, 0x00e3ff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x9C) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA4) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xAC) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB4) & 0xFF)), 0x00000048, 0x00000b00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xBC) & 0xFF)), 0x00000048, 0x00fe0b00,
+# 1311 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x80) & 0xFF)), 0x000000f0, 0x00e00003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x88) & 0xFF)), 0x000000f0, 0x00d80003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x90) & 0xFF)), 0x000000f0, 0x00e20003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x98) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA0) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA8) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB0) & 0xFF)), 0x000000f0, 0x00000a03,
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB8) & 0xFF)), 0x000000f0, 0x00400003,
+# 1350 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC4) & 0xFF)), 0xFE000FC8, 0x0000d000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xCC) & 0xFF)), 0xFE000FC8, 0x000ff000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD4) & 0xFF)), 0xFE000FC8, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xDC) & 0xFF)), 0xFE000FC8, 0x00000000,
+# 1380 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC0) & 0xFF)), 0xFE000FCC, 0x0000d003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC8) & 0xFF)), 0xFE000FCC, 0x00001013,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD0) & 0xFF)), 0xFE000FCC, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD8) & 0xFF)), 0xFE000FCC, 0x00000000,
+# 1421 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE0) & 0xFF)), 0x0000FC88, 0xff000003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE4) & 0xFF)), 0x0000FC88, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE8) & 0xFF)), 0x0000FC88, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xEC) & 0xFF)), 0x0000FC88, 0x00000000,
+
+ };
+ int i;
+ int max;
+ print_debug("setting up coherent ht domain....\r\n");
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ for(i = 0; i < max; i += 3) {
+ unsigned long reg;
+
+
+
+
+
+
+ reg = pci_read_config32(register_values[i]);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2] & ~register_values[i+1];
+ pci_write_config32(register_values[i], reg);
+ }
+ print_debug("done.\r\n");
+}
+
+static void enumerate_ht_chain(void)
+{
+ unsigned next_unitid, last_unitid;;
+ next_unitid = 1;
+ do {
+ uint32_t id;
+ uint8_t hdr_type, pos;
+ last_unitid = next_unitid;
+
+ id = pci_read_config32(( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x00) & 0xFF)));
+
+ if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
+ break;
+ }
+ hdr_type = pci_read_config8(( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x0e) & 0xFF)));
+ pos = 0;
+ hdr_type &= 0x7f;
+
+ if ((hdr_type == 0) ||
+ (hdr_type == 1)) {
+ pos = pci_read_config8(( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x34) & 0xFF)));
+ }
+ while(pos != 0) {
+ uint8_t cap;
+ cap = pci_read_config8(( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((pos + 0) & 0xFF)));
+ if (cap == 0x08) {
+ uint16_t flags;
+ flags = pci_read_config16(( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((pos + 2) & 0xFF)));
+ if ((flags >> 13) == 0) {
+ unsigned count;
+ flags &= ~0x1f;
+ flags |= next_unitid & 0x1f;
+ count = (flags >> 5) & 0x1f;
+ pci_write_config16(( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((pos + 2) & 0xFF)), flags);
+ next_unitid += count;
+ break;
+ }
+ }
+ pos = pci_read_config8(( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((pos + 1) & 0xFF)));
+ }
+ } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
+}
+
+static void print_pci_devices(void)
+{
+ uint32_t addr;
+ for(addr = ( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0) & 0xFF));
+ addr <= ( (((0) & 0xFF) << 16) | (((0x1f) & 0x1f) << 11) | (((0x7) & 0x07) << 8) | ((0) & 0xFF));
+ addr += ( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0) & 0xFF))) {
+ uint32_t id;
+ id = pci_read_config32(addr + 0x00);
+ if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
+ continue;
+ }
+ print_debug("PCI: 00:");
+ print_debug_hex8(addr >> 11);
+ print_debug_char('.');
+ print_debug_hex8((addr >> 8) & 7);
+ print_debug("\r\n");
+ }
+}
+# 1525 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+static void enable_smbus(void)
+{
+ uint32_t addr;
+ for(addr = ( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0) & 0xFF));
+ addr <= ( (((0) & 0xFF) << 16) | (((0x1f) & 0x1f) << 11) | (((0x7) & 0x07) << 8) | ((0) & 0xFF));
+ addr += ( (((0) & 0xFF) << 16) | (((0) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0) & 0xFF))) {
+ uint32_t id;
+ id = pci_read_config32(addr);
+ if (id == ((0x746b << 16) | (0x1022))) {
+ break;
+ }
+ }
+ if (addr > ( (((0) & 0xFF) << 16) | (((0x1f) & 0x1f) << 11) | (((0x7) & 0x07) << 8) | ((0) & 0xFF))) {
+ die("SMBUS controller not found\r\n");
+ }
+ uint8_t enable;
+ print_debug("SMBus controller enabled\r\n");
+ pci_write_config32(addr + 0x58, 0x1000 | 1);
+ enable = pci_read_config8(addr + 0x41);
+ pci_write_config8(addr + 0x41, enable | (1 << 7));
+}
+
+
+static inline void smbus_delay(void)
+{
+ outb(0x80, 0x80);
+}
+
+static int smbus_wait_until_ready(void)
+{
+ unsigned long loops;
+ loops = (100*1000*10);
+ do {
+ unsigned short val;
+ smbus_delay();
+ val = inw(0x1000 + 0xe0);
+ if ((val & 0x800) == 0) {
+ break;
+ }
+ } while(--loops);
+ return loops?0:-1;
+}
+
+static int smbus_wait_until_done(void)
+{
+ unsigned long loops;
+ loops = (100*1000*10);
+ do {
+ unsigned short val;
+ smbus_delay();
+
+ val = inw(0x1000 + 0xe0);
+ if (((val & 0x8) == 0) || ((val & 0x437) != 0)) {
+ break;
+ }
+ } while(--loops);
+ return loops?0:-1;
+}
+
+static int smbus_read_byte(unsigned device, unsigned address)
+{
+ unsigned char global_control_register;
+ unsigned char global_status_register;
+ unsigned char byte;
+
+ if (smbus_wait_until_ready() < 0) {
+ return -1;
+ }
+
+
+
+ outw(inw(0x1000 + 0xe2) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), 0x1000 + 0xe2);
+
+ outw(((device & 0x7f) << 1) | 1, 0x1000 + 0xe4);
+
+ outb(address & 0xFF, 0x1000 + 0xe8);
+
+ outw((inw(0x1000 + 0xe2) & ~7) | (0x2), 0x1000 + 0xe2);
+
+
+
+ outw(inw(0x1000 + 0xe0), 0x1000 + 0xe0);
+
+
+ outw(0, 0x1000 + 0xe6);
+
+
+ outw((inw(0x1000 + 0xe2) | (1 << 3)), 0x1000 + 0xe2);
+
+
+
+ if (smbus_wait_until_done() < 0) {
+ return -1;
+ }
+
+ global_status_register = inw(0x1000 + 0xe0);
+
+
+ byte = inw(0x1000 + 0xe6) & 0xff;
+
+ if (global_status_register != (1 << 4)) {
+ return -1;
+ }
+ return byte;
+}
+
+static void dump_spd_registers(void)
+{
+ unsigned device;
+ device = (0xa << 3);
+ print_debug("\r\n");
+ while(device <= ((0xa << 3) +1)) {
+ int i;
+ print_debug("dimm: ");
+ print_debug_hex8(device);
+ for(i = 0; i < 256; i++) {
+ int status;
+ unsigned char byte;
+ if ((i & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(i);
+ print_debug(": ");
+ }
+ status = smbus_read_byte(device, i);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ continue;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug_char(' ');
+ }
+ device += 1;
+ print_debug("\r\n");
+ }
+}
+
+static void dump_spd_registers1(void)
+{
+ int i;
+ print_debug("dimm: ");
+ print_debug_hex8((0xa << 3));
+ for(i = 0; i < 256; i++) {
+ int status;
+ unsigned char byte;
+ if ((i & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(i);
+ print_debug(": ");
+ }
+ status = smbus_read_byte((0xa << 3), i);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ break;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug_char(' ');
+ }
+ print_debug("\r\n");
+}
+
+
+
+static void dump_spd_registers2(void)
+{
+ unsigned dev;
+ print_debug("\r\n");
+ for(dev = (0xa << 3); dev <= ((0xa << 3) +1); dev += 1) {
+ print_debug("dimm: ");
+ print_debug_hex8(dev);
+ int status;
+ unsigned char byte;
+ status = smbus_read_byte(dev, 0);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ continue;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug("\r\n");
+ }
+}
+
+static void main(void)
+{
+ uart_init();
+ console_init();
+ if (boot_cpu() && !cpu_init_detected()) {
+ setup_coherent_ht_domain();
+ enumerate_ht_chain();
+ print_pci_devices();
+ enable_smbus();
+ sdram_initialize();
+
+
+
+ dump_spd_registers1();
+ dump_spd_registers2();
+
+
+
+
+
+ ram_fill( 0x00000000, 0x00001000);
+ ram_verify(0x00000000, 0x00001000);
+
+
+
+
+
+ }
+}
diff --git a/util/romcc/tests/simple_test21.c b/util/romcc/tests/simple_test21.c
new file mode 100644
index 0000000000..7f7b87122b
--- /dev/null
+++ b/util/romcc/tests/simple_test21.c
@@ -0,0 +1,6 @@
+
+
+static void main(void)
+{
+ asm("hlt");
+}
diff --git a/util/romcc/tests/simple_test22.c b/util/romcc/tests/simple_test22.c
new file mode 100644
index 0000000000..247369b80b
--- /dev/null
+++ b/util/romcc/tests/simple_test22.c
@@ -0,0 +1,306 @@
+struct syscall_result {
+ long val;
+ int errno;
+};
+
+static struct syscall_result syscall_return(long result)
+{
+ struct syscall_result res;
+ if (((unsigned long)result) >= ((unsigned long)-125)) {
+ res.errno = - result;
+ res.val = -1;
+ } else {
+ res.errno = 0;
+ res.val = result;
+ }
+ return res;
+}
+
+static struct syscall_result syscall0(unsigned long nr)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr));
+ return syscall_return(res);
+}
+
+static struct syscall_result syscall1(unsigned long nr, unsigned long arg1)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1));
+ return syscall_return(res);
+
+}
+
+static struct syscall_result syscall2(unsigned long nr, unsigned long arg1, unsigned long arg2)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1), "c" (arg2));
+ return syscall_return(res);
+
+}
+
+
+static struct syscall_result syscall3(unsigned long nr, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3));
+ return syscall_return(res);
+
+}
+
+static struct syscall_result syscall4(unsigned long nr, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3), "S" (arg4));
+ return syscall_return(res);
+
+}
+
+static struct syscall_result syscall5(unsigned long nr, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4, unsigned long arg5)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3),
+ "S" (arg4), "D" (arg5));
+ return syscall_return(res);
+
+}
+
+#define NR_exit 1
+#define NR_fork 2
+#define NR_read 3
+#define NR_write 4
+#define NR_open 5
+#define NR_close 6
+#define NR_waitpid 7
+#define NR_creat 8
+#define NR_link 9
+#define NR_unlink 10
+#define NR_execve 11
+#define NR_chdir 12
+#define NR_time 13
+#define NR_mknod 14
+#define NR_chmod 15
+#define NR_lchown 16
+#define NR_break 17
+#define NR_oldstat 18
+#define NR_lseek 19
+#define NR_getpid 20
+#define NR_mount 21
+#define NR_umount 22
+#define NR_setuid 23
+#define NR_getuid 24
+#define NR_stime 25
+#define NR_ptrace 26
+#define NR_alarm 27
+#define NR_oldfstat 28
+#define NR_pause 29
+#define NR_utime 30
+#define NR_stty 31
+#define NR_gtty 32
+#define NR_access 33
+#define NR_nice 34
+#define NR_ftime 35
+#define NR_sync 36
+#define NR_kill 37
+#define NR_rename 38
+#define NR_mkdir 39
+#define NR_rmdir 40
+#define NR_dup 41
+#define NR_pipe 42
+#define NR_times 43
+#define NR_prof 44
+#define NR_brk 45
+#define NR_setgid 46
+#define NR_getgid 47
+#define NR_signal 48
+#define NR_geteuid 49
+#define NR_getegid 50
+#define NR_acct 51
+#define NR_umount2 52
+#define NR_lock 53
+#define NR_ioctl 54
+#define NR_fcntl 55
+#define NR_mpx 56
+#define NR_setpgid 57
+#define NR_ulimit 58
+#define NR_oldolduname 59
+#define NR_umask 60
+#define NR_chroot 61
+#define NR_ustat 62
+#define NR_dup2 63
+#define NR_getppid 64
+#define NR_getpgrp 65
+#define NR_setsid 66
+#define NR_sigaction 67
+#define NR_sgetmask 68
+#define NR_ssetmask 69
+#define NR_setreuid 70
+#define NR_setregid 71
+#define NR_sigsuspend 72
+#define NR_sigpending 73
+#define NR_sethostname 74
+#define NR_setrlimit 75
+#define NR_getrlimit 76
+#define NR_getrusage 77
+#define NR_gettimeofday 78
+#define NR_settimeofday 79
+#define NR_getgroups 80
+#define NR_setgroups 81
+#define NR_select 82
+#define NR_symlink 83
+#define NR_oldlstat 84
+#define NR_readlink 85
+#define NR_uselib 86
+#define NR_swapon 87
+#define NR_reboot 88
+#define NR_readdir 89
+#define NR_mmap 90
+#define NR_munmap 91
+#define NR_truncate 92
+#define NR_ftruncate 93
+#define NR_fchmod 94
+#define NR_fchown 95
+#define NR_getpriority 96
+#define NR_setpriority 97
+#define NR_profil 98
+#define NR_statfs 99
+#define NR_fstatfs 100
+#define NR_ioperm 101
+#define NR_socketcall 102
+#define NR_syslog 103
+#define NR_setitimer 104
+#define NR_getitimer 105
+#define NR_stat 106
+#define NR_lstat 107
+#define NR_fstat 108
+#define NR_olduname 109
+#define NR_iopl 110
+#define NR_vhangup 111
+#define NR_idle 112
+#define NR_vm86old 113
+#define NR_wait4 114
+#define NR_swapoff 115
+#define NR_sysinfo 116
+#define NR_ipc 117
+#define NR_fsync 118
+#define NR_sigreturn 119
+#define NR_clone 120
+#define NR_setdomainname 121
+#define NR_uname 122
+#define NR_modify_ldt 123
+#define NR_adjtimex 124
+#define NR_mprotect 125
+#define NR_sigprocmask 126
+#define NR_create_module 127
+#define NR_init_module 128
+#define NR_delete_module 129
+#define NR_get_kernel_syms 130
+#define NR_quotactl 131
+#define NR_getpgid 132
+#define NR_fchdir 133
+#define NR_bdflush 134
+#define NR_sysfs 135
+#define NR_personality 136
+#define NR_afs_syscall 137 /* Syscall for Andrew File System */
+#define NR_setfsuid 138
+#define NR_setfsgid 139
+#define NR__llseek 140
+#define NR_getdents 141
+#define NR__newselect 142
+#define NR_flock 143
+#define NR_msync 144
+#define NR_readv 145
+#define NR_writev 146
+#define NR_getsid 147
+#define NR_fdatasync 148
+#define NR__sysctl 149
+#define NR_mlock 150
+#define NR_munlock 151
+#define NR_mlockall 152
+#define NR_munlockall 153
+#define NR_sched_setparam 154
+#define NR_sched_getparam 155
+#define NR_sched_setscheduler 156
+#define NR_sched_getscheduler 157
+#define NR_sched_yield 158
+#define NR_sched_get_priority_max 159
+#define NR_sched_get_priority_min 160
+#define NR_sched_rr_get_interval 161
+#define NR_nanosleep 162
+#define NR_mremap 163
+#define NR_setresuid 164
+#define NR_getresuid 165
+#define NR_vm86 166
+#define NR_query_module 167
+#define NR_poll 168
+#define NR_nfsservctl 169
+#define NR_setresgid 170
+#define NR_getresgid 171
+#define NR_prctl 172
+#define NR_rt_sigreturn 173
+#define NR_rt_sigaction 174
+#define NR_rt_sigprocmask 175
+#define NR_rt_sigpending 176
+#define NR_rt_sigtimedwait 177
+#define NR_rt_sigqueueinfo 178
+#define NR_rt_sigsuspend 179
+#define NR_pread 180
+#define NR_pwrite 181
+#define NR_chown 182
+#define NR_getcwd 183
+#define NR_capget 184
+#define NR_capset 185
+#define NR_sigaltstack 186
+#define NR_sendfile 187
+#define NR_getpmsg 188 /* some people actually want streams */
+#define NR_putpmsg 189 /* some people actually want streams */
+#define NR_vfork 190
+
+typedef long ssize_t;
+typedef unsigned long size_t;
+
+/* Standard file descriptors */
+#define STDIN_FILENO 0 /* Standard input */
+#define STDOUT_FILENO 1 /* Standard output */
+#define STDERR_FILENO 2 /* Standard error output */
+
+static ssize_t write(int fd, const void *buf, size_t count)
+{
+ struct syscall_result res;
+ res = syscall3(NR_write, fd, (unsigned long)buf, count);
+ return res.val;
+}
+
+static void _exit(int status)
+{
+ struct syscall_result res;
+ res = syscall1(NR_exit, status);
+}
+
+static void main(void)
+{
+ static const char msg[] = "hello world\r\n";
+ write(STDOUT_FILENO, msg, sizeof(msg));
+ _exit(0);
+}
diff --git a/util/romcc/tests/simple_test23.c b/util/romcc/tests/simple_test23.c
new file mode 100644
index 0000000000..33acd047a2
--- /dev/null
+++ b/util/romcc/tests/simple_test23.c
@@ -0,0 +1,18 @@
+static void print(char *str)
+{
+ while(1) {
+ unsigned char ch;
+ ch = *str;
+ if (ch == '\0') {
+ break;
+ }
+ __builtin_outb(ch, 0x1234);
+ str += 1;
+ }
+}
+
+static void main(void)
+{
+ print("hello world\r\n");
+ print("how are you today\r\n");
+}
diff --git a/util/romcc/tests/simple_test24.c b/util/romcc/tests/simple_test24.c
new file mode 100644
index 0000000000..01413c2dad
--- /dev/null
+++ b/util/romcc/tests/simple_test24.c
@@ -0,0 +1,16 @@
+void smbus_read_byte(void)
+{
+ unsigned char host_status_register;
+ unsigned char byte;
+ int result;
+
+ host_status_register = __builtin_inb(0x1234);
+
+ /* read results of transaction */
+ byte = __builtin_inb(0x4567);
+
+ result = byte;
+ if (host_status_register != 0x02) {
+ result = -1;
+ }
+}
diff --git a/util/romcc/tests/simple_test25.c b/util/romcc/tests/simple_test25.c
new file mode 100644
index 0000000000..80ddfa6740
--- /dev/null
+++ b/util/romcc/tests/simple_test25.c
@@ -0,0 +1,109 @@
+#define COUNT 26
+static void main(void)
+{
+ unsigned char a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
+ a = 1;
+ b = 2;
+ c = 3;
+ d = 4;
+ e = 5;
+ f = 6;
+ g = 7;
+ h = 8;
+ i = 9;
+ j = 10;
+ k = 11;
+ l = 12;
+ m = 13;
+ n = 14;
+ o = 15;
+ p = 16;
+ q = 17;
+ r = 18;
+ s = 19;
+ t = 20;
+ u = 21;
+ v = 22;
+ w = 23;
+ x = 24;
+ y = 25;
+ z = 26;
+#if COUNT >= 26
+ __builtin_outb(z, 0xab);
+#endif
+#if COUNT >= 25
+ __builtin_outb(y, 0xab);
+#endif
+#if COUNT >= 24
+ __builtin_outb(x, 0xab);
+#endif
+#if COUNT >= 23
+ __builtin_outb(w, 0xab);
+#endif
+#if COUNT >= 22
+ __builtin_outb(v, 0xab);
+#endif
+#if COUNT >= 21
+ __builtin_outb(u, 0xab);
+#endif
+#if COUNT >= 20
+ __builtin_outb(t, 0xab);
+#endif
+#if COUNT >= 19
+ __builtin_outb(s, 0xab);
+#endif
+#if COUNT >= 18
+ __builtin_outb(r, 0xab);
+#endif
+#if COUNT >= 17
+ __builtin_outb(q, 0xab);
+#endif
+#if COUNT >= 16
+ __builtin_outb(p, 0xab);
+#endif
+#if COUNT >= 15
+ __builtin_outb(o, 0xab);
+#endif
+#if COUNT >= 14
+ __builtin_outb(n, 0xab);
+#endif
+#if COUNT >= 13
+ __builtin_outb(m, 0xab);
+#endif
+#if COUNT >= 12
+ __builtin_outb(l, 0xab);
+#endif
+#if COUNT >= 11
+ __builtin_outb(k, 0xab);
+#endif
+#if COUNT >= 10
+ __builtin_outb(j, 0xab);
+#endif
+#if COUNT >= 9
+ __builtin_outb(i, 0xab);
+#endif
+#if COUNT >= 8
+ __builtin_outb(h, 0xab);
+#endif
+#if COUNT >= 7
+ __builtin_outb(g, 0xab);
+#endif
+#if COUNT >= 6
+ __builtin_outb(f, 0xab);
+#endif
+#if COUNT >= 5
+ __builtin_outb(e, 0xab);
+#endif
+#if COUNT >= 4
+ __builtin_outb(d, 0xab);
+#endif
+#if COUNT >= 3
+ __builtin_outb(c, 0xab);
+#endif
+#if COUNT >= 2
+ __builtin_outb(b, 0xab);
+#endif
+#if COUNT >= 1
+ __builtin_outb(a, 0xab);
+#endif
+}
diff --git a/util/romcc/tests/simple_test26.c b/util/romcc/tests/simple_test26.c
new file mode 100644
index 0000000000..b26bbb2ed7
--- /dev/null
+++ b/util/romcc/tests/simple_test26.c
@@ -0,0 +1,109 @@
+#define COUNT 23
+static void main(void)
+{
+ unsigned int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
+ a = __builtin_inb(0xab);
+ b = __builtin_inb(0xab);
+ c = __builtin_inb(0xab);
+ d = __builtin_inb(0xab);
+ e = __builtin_inb(0xab);
+ f = __builtin_inb(0xab);
+ g = __builtin_inb(0xab);
+ h = __builtin_inb(0xab);
+ i = __builtin_inb(0xab);
+ j = __builtin_inb(0xab);
+ k = __builtin_inb(0xab);
+ l = __builtin_inb(0xab);
+ m = __builtin_inb(0xab);
+ n = __builtin_inb(0xab);
+ o = __builtin_inb(0xab);
+ p = __builtin_inb(0xab);
+ q = __builtin_inb(0xab);
+ r = __builtin_inb(0xab);
+ s = __builtin_inb(0xab);
+ t = __builtin_inb(0xab);
+ u = __builtin_inb(0xab);
+ v = __builtin_inb(0xab);
+ w = __builtin_inb(0xab);
+ x = __builtin_inb(0xab);
+ y = __builtin_inb(0xab);
+ z = __builtin_inb(0xab);
+#if COUNT >= 26
+ __builtin_outb(z, 0xab);
+#endif
+#if COUNT >= 25
+ __builtin_outb(y, 0xab);
+#endif
+#if COUNT >= 24
+ __builtin_outb(x, 0xab);
+#endif
+#if COUNT >= 23
+ __builtin_outb(w, 0xab);
+#endif
+#if COUNT >= 22
+ __builtin_outb(v, 0xab);
+#endif
+#if COUNT >= 21
+ __builtin_outb(u, 0xab);
+#endif
+#if COUNT >= 20
+ __builtin_outb(t, 0xab);
+#endif
+#if COUNT >= 19
+ __builtin_outb(s, 0xab);
+#endif
+#if COUNT >= 18
+ __builtin_outb(r, 0xab);
+#endif
+#if COUNT >= 17
+ __builtin_outb(q, 0xab);
+#endif
+#if COUNT >= 16
+ __builtin_outb(p, 0xab);
+#endif
+#if COUNT >= 15
+ __builtin_outb(o, 0xab);
+#endif
+#if COUNT >= 14
+ __builtin_outb(n, 0xab);
+#endif
+#if COUNT >= 13
+ __builtin_outb(m, 0xab);
+#endif
+#if COUNT >= 12
+ __builtin_outb(l, 0xab);
+#endif
+#if COUNT >= 11
+ __builtin_outb(k, 0xab);
+#endif
+#if COUNT >= 10
+ __builtin_outb(j, 0xab);
+#endif
+#if COUNT >= 9
+ __builtin_outb(i, 0xab);
+#endif
+#if COUNT >= 8
+ __builtin_outb(h, 0xab);
+#endif
+#if COUNT >= 7
+ __builtin_outb(g, 0xab);
+#endif
+#if COUNT >= 6
+ __builtin_outb(f, 0xab);
+#endif
+#if COUNT >= 5
+ __builtin_outb(e, 0xab);
+#endif
+#if COUNT >= 4
+ __builtin_outb(d, 0xab);
+#endif
+#if COUNT >= 3
+ __builtin_outb(c, 0xab);
+#endif
+#if COUNT >= 2
+ __builtin_outb(b, 0xab);
+#endif
+#if COUNT >= 1
+ __builtin_outb(a, 0xab);
+#endif
+}
diff --git a/util/romcc/tests/simple_test27.c b/util/romcc/tests/simple_test27.c
new file mode 100644
index 0000000000..d40e43f1c4
--- /dev/null
+++ b/util/romcc/tests/simple_test27.c
@@ -0,0 +1,133 @@
+void outb(unsigned char value, unsigned short port)
+{
+ __builtin_outb(value, port);
+}
+
+unsigned char inb(unsigned short port)
+{
+ return __builtin_inb(port);
+}
+
+/* Base Address */
+#ifndef TTYS0_BASE
+#define TTYS0_BASE 0x3f8
+#endif
+
+#ifndef TTYS0_BAUD
+#define TTYS0_BAUD 115200
+#endif
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+#if TTYS0_BAUD == 115200
+#define TTYS0_DIV (1)
+#else
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+#endif
+
+/* Line Control Settings */
+#ifndef TTYS0_LCS
+/* Set 8bit, 1 stop bit, no parity */
+#define TTYS0_LCS 0x3
+#endif
+
+#define UART_LCS TTYS0_LCS
+
+/* Data */
+#define UART_RBR 0x00
+#define UART_TBR 0x00
+
+/* Control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* Status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+int uart_can_tx_byte(void)
+{
+ return inb(TTYS0_BASE + UART_LSR) & 0x20;
+}
+
+void uart_wait_to_tx_byte(void)
+{
+ while(!uart_can_tx_byte())
+ ;
+}
+
+void uart_wait_until_sent(void)
+{
+ while(!(inb(TTYS0_BASE + UART_LSR) & 0x40))
+ ;
+}
+
+static void uart_tx_byte(unsigned char data)
+{
+ uart_wait_to_tx_byte();
+ outb(data, TTYS0_BASE + UART_TBR);
+ /* Make certain the data clears the fifos */
+ uart_wait_until_sent();
+}
+
+
+void uart_init(void)
+{
+ /* disable interrupts */
+ outb(0x0, TTYS0_BASE + UART_IER);
+ /* enable fifo's */
+ outb(0x01, TTYS0_BASE + UART_FCR);
+ /* Set Baud Rate Divisor to 12 ==> 115200 Baud */
+ outb(0x80 | UART_LCS, TTYS0_BASE + UART_LCR);
+ outb(TTYS0_DIV & 0xFF, TTYS0_BASE + UART_DLL);
+ outb((TTYS0_DIV >> 8) & 0xFF, TTYS0_BASE + UART_DLM);
+ outb(UART_LCS, TTYS0_BASE + UART_LCR);
+}
+
+
+void __console_tx_char(unsigned char byte)
+{
+ uart_tx_byte(byte);
+
+}
+
+void __console_tx_string(char *str)
+{
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ __console_tx_char(ch);
+ }
+}
+
+
+void print_debug_char(unsigned char byte) { __console_tx_char(byte); }
+void print_debug(char *str) { __console_tx_string(str); }
+
+void main(void)
+{
+ static const char msg[] = "hello world\r\n";
+ uart_init();
+#if 0
+ print_debug(msg);
+#endif
+#if 1
+ print_debug("hello world\r\n");
+ print_debug("how are you today\r\n");
+#endif
+ while(1) {
+ ;
+ }
+}
+
+void main2(void)
+{
+ main();
+}
diff --git a/util/romcc/tests/simple_test28.c b/util/romcc/tests/simple_test28.c
new file mode 100644
index 0000000000..8d83383124
--- /dev/null
+++ b/util/romcc/tests/simple_test28.c
@@ -0,0 +1,24 @@
+static void outl(unsigned int value, unsigned short port)
+{
+ __builtin_outl(value, port);
+}
+
+static unsigned char inl(unsigned short port)
+{
+ return __builtin_inl(port);
+}
+
+
+static void setup_coherent_ht_domain(void)
+{
+ static const unsigned int register_values[] = {
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x40) & 0xFF)), 0xfff0f0f0, 0x00010101,
+
+ };
+ unsigned long reg;
+ reg = inl(0xFC);
+ reg &= register_values[1];
+ reg |= register_values[2] & ~register_values[1];
+ outl(register_values[0], 0xF8);
+ outl(reg, 0xFC);
+}
diff --git a/util/romcc/tests/simple_test29.c b/util/romcc/tests/simple_test29.c
new file mode 100644
index 0000000000..7eb8f4fa75
--- /dev/null
+++ b/util/romcc/tests/simple_test29.c
@@ -0,0 +1,37 @@
+static void outb(unsigned char value, unsigned short port)
+{
+ __builtin_outb(value, port);
+}
+
+static unsigned char inb(unsigned short port)
+{
+ return __builtin_inb(port);
+}
+
+static void __console_tx_byte(unsigned char byte)
+{
+ while(inb(0x3f8 + 0x05))
+ ;
+ outb(byte, 0x3f8 + 0x00);
+}
+
+static void __console_tx_string(int loglevel, const char *str)
+{
+ if (8 > loglevel) {
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ __console_tx_byte(ch);
+ }
+ }
+}
+static void console_init(void)
+{
+ static const char console_test[] =
+ "\r\n\r\nLinuxBIOS-"
+ "1.1.0"
+ ".0Fallback"
+ " "
+ "Mon Jun 9 18:15:20 MDT 2003"
+ " starting...\r\n";
+ __console_tx_string(6, console_test);
+}
diff --git a/util/romcc/tests/simple_test30.c b/util/romcc/tests/simple_test30.c
new file mode 100644
index 0000000000..fc21fc6833
--- /dev/null
+++ b/util/romcc/tests/simple_test30.c
@@ -0,0 +1,1087 @@
+struct syscall_result {
+ long val;
+ int errno;
+};
+
+static struct syscall_result syscall_return(long result)
+{
+ struct syscall_result res;
+ if (((unsigned long)result) >= ((unsigned long)-125)) {
+ res.errno = - result;
+ res.val = -1;
+ } else {
+ res.errno = 0;
+ res.val = result;
+ }
+ return res;
+}
+
+static struct syscall_result syscall0(unsigned long nr)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr));
+ return syscall_return(res);
+}
+
+static struct syscall_result syscall1(unsigned long nr, unsigned long arg1)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1));
+ return syscall_return(res);
+
+}
+
+static struct syscall_result syscall2(unsigned long nr, unsigned long arg1, unsigned long arg2)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1), "c" (arg2));
+ return syscall_return(res);
+
+}
+
+
+static struct syscall_result syscall3(unsigned long nr, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3));
+ return syscall_return(res);
+
+}
+
+static struct syscall_result syscall4(unsigned long nr, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3), "S" (arg4));
+ return syscall_return(res);
+
+}
+
+static struct syscall_result syscall5(unsigned long nr, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4, unsigned long arg5)
+{
+ long res;
+ asm volatile(
+ "int $0x80"
+ : "a" (res)
+ : "a" (nr), "b" (arg1), "c" (arg2), "d" (arg3),
+ "S" (arg4), "D" (arg5));
+ return syscall_return(res);
+
+}
+
+#define NR_exit 1
+#define NR_fork 2
+#define NR_read 3
+#define NR_write 4
+#define NR_open 5
+#define NR_close 6
+#define NR_waitpid 7
+#define NR_creat 8
+#define NR_link 9
+#define NR_unlink 10
+#define NR_execve 11
+#define NR_chdir 12
+#define NR_time 13
+#define NR_mknod 14
+#define NR_chmod 15
+#define NR_lchown 16
+#define NR_break 17
+#define NR_oldstat 18
+#define NR_lseek 19
+#define NR_getpid 20
+#define NR_mount 21
+#define NR_umount 22
+#define NR_setuid 23
+#define NR_getuid 24
+#define NR_stime 25
+#define NR_ptrace 26
+#define NR_alarm 27
+#define NR_oldfstat 28
+#define NR_pause 29
+#define NR_utime 30
+#define NR_stty 31
+#define NR_gtty 32
+#define NR_access 33
+#define NR_nice 34
+#define NR_ftime 35
+#define NR_sync 36
+#define NR_kill 37
+#define NR_rename 38
+#define NR_mkdir 39
+#define NR_rmdir 40
+#define NR_dup 41
+#define NR_pipe 42
+#define NR_times 43
+#define NR_prof 44
+#define NR_brk 45
+#define NR_setgid 46
+#define NR_getgid 47
+#define NR_signal 48
+#define NR_geteuid 49
+#define NR_getegid 50
+#define NR_acct 51
+#define NR_umount2 52
+#define NR_lock 53
+#define NR_ioctl 54
+#define NR_fcntl 55
+#define NR_mpx 56
+#define NR_setpgid 57
+#define NR_ulimit 58
+#define NR_oldolduname 59
+#define NR_umask 60
+#define NR_chroot 61
+#define NR_ustat 62
+#define NR_dup2 63
+#define NR_getppid 64
+#define NR_getpgrp 65
+#define NR_setsid 66
+#define NR_sigaction 67
+#define NR_sgetmask 68
+#define NR_ssetmask 69
+#define NR_setreuid 70
+#define NR_setregid 71
+#define NR_sigsuspend 72
+#define NR_sigpending 73
+#define NR_sethostname 74
+#define NR_setrlimit 75
+#define NR_getrlimit 76
+#define NR_getrusage 77
+#define NR_gettimeofday 78
+#define NR_settimeofday 79
+#define NR_getgroups 80
+#define NR_setgroups 81
+#define NR_select 82
+#define NR_symlink 83
+#define NR_oldlstat 84
+#define NR_readlink 85
+#define NR_uselib 86
+#define NR_swapon 87
+#define NR_reboot 88
+#define NR_readdir 89
+#define NR_mmap 90
+#define NR_munmap 91
+#define NR_truncate 92
+#define NR_ftruncate 93
+#define NR_fchmod 94
+#define NR_fchown 95
+#define NR_getpriority 96
+#define NR_setpriority 97
+#define NR_profil 98
+#define NR_statfs 99
+#define NR_fstatfs 100
+#define NR_ioperm 101
+#define NR_socketcall 102
+#define NR_syslog 103
+#define NR_setitimer 104
+#define NR_getitimer 105
+#define NR_stat 106
+#define NR_lstat 107
+#define NR_fstat 108
+#define NR_olduname 109
+#define NR_iopl 110
+#define NR_vhangup 111
+#define NR_idle 112
+#define NR_vm86old 113
+#define NR_wait4 114
+#define NR_swapoff 115
+#define NR_sysinfo 116
+#define NR_ipc 117
+#define NR_fsync 118
+#define NR_sigreturn 119
+#define NR_clone 120
+#define NR_setdomainname 121
+#define NR_uname 122
+#define NR_modify_ldt 123
+#define NR_adjtimex 124
+#define NR_mprotect 125
+#define NR_sigprocmask 126
+#define NR_create_module 127
+#define NR_init_module 128
+#define NR_delete_module 129
+#define NR_get_kernel_syms 130
+#define NR_quotactl 131
+#define NR_getpgid 132
+#define NR_fchdir 133
+#define NR_bdflush 134
+#define NR_sysfs 135
+#define NR_personality 136
+#define NR_afs_syscall 137 /* Syscall for Andrew File System */
+#define NR_setfsuid 138
+#define NR_setfsgid 139
+#define NR__llseek 140
+#define NR_getdents 141
+#define NR__newselect 142
+#define NR_flock 143
+#define NR_msync 144
+#define NR_readv 145
+#define NR_writev 146
+#define NR_getsid 147
+#define NR_fdatasync 148
+#define NR__sysctl 149
+#define NR_mlock 150
+#define NR_munlock 151
+#define NR_mlockall 152
+#define NR_munlockall 153
+#define NR_sched_setparam 154
+#define NR_sched_getparam 155
+#define NR_sched_setscheduler 156
+#define NR_sched_getscheduler 157
+#define NR_sched_yield 158
+#define NR_sched_get_priority_max 159
+#define NR_sched_get_priority_min 160
+#define NR_sched_rr_get_interval 161
+#define NR_nanosleep 162
+#define NR_mremap 163
+#define NR_setresuid 164
+#define NR_getresuid 165
+#define NR_vm86 166
+#define NR_query_module 167
+#define NR_poll 168
+#define NR_nfsservctl 169
+#define NR_setresgid 170
+#define NR_getresgid 171
+#define NR_prctl 172
+#define NR_rt_sigreturn 173
+#define NR_rt_sigaction 174
+#define NR_rt_sigprocmask 175
+#define NR_rt_sigpending 176
+#define NR_rt_sigtimedwait 177
+#define NR_rt_sigqueueinfo 178
+#define NR_rt_sigsuspend 179
+#define NR_pread 180
+#define NR_pwrite 181
+#define NR_chown 182
+#define NR_getcwd 183
+#define NR_capget 184
+#define NR_capset 185
+#define NR_sigaltstack 186
+#define NR_sendfile 187
+#define NR_getpmsg 188 /* some people actually want streams */
+#define NR_putpmsg 189 /* some people actually want streams */
+#define NR_vfork 190
+
+typedef long ssize_t;
+typedef unsigned long size_t;
+
+/* Standard file descriptors */
+#define STDIN_FILENO 0 /* Standard input */
+#define STDOUT_FILENO 1 /* Standard output */
+#define STDERR_FILENO 2 /* Standard error output */
+
+static ssize_t write(int fd, const void *buf, size_t count)
+{
+ struct syscall_result res;
+ res = syscall3(NR_write, fd, (unsigned long)buf, count);
+ return res.val;
+}
+
+static void _exit(int status)
+{
+ struct syscall_result res;
+ res = syscall1(NR_exit, status);
+}
+
+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)
+{
+ write(STDOUT_FILENO, addr_of_char(ch), 1);
+}
+
+static void console_tx_nibble(unsigned nibble)
+{
+ unsigned char digit;
+ digit = nibble + '0';
+ if (digit > '9') {
+ digit += 39;
+ }
+ console_tx_byte(digit);
+}
+
+static void console_tx_char(unsigned char byte)
+{
+ console_tx_byte(byte);
+}
+
+static void console_tx_hex8(unsigned char value)
+{
+ console_tx_nibble((value >> 4U) & 0x0fU);
+ console_tx_nibble(value & 0x0fU);
+}
+
+static void console_tx_hex16(unsigned short value)
+{
+ console_tx_nibble((value >> 12U) & 0x0FU);
+ console_tx_nibble((value >> 8U) & 0x0FU);
+ console_tx_nibble((value >> 4U) & 0x0FU);
+ console_tx_nibble(value & 0x0FU);
+}
+
+static void console_tx_hex32(unsigned short value)
+{
+ console_tx_nibble((value >> 28U) & 0x0FU);
+ console_tx_nibble((value >> 24U) & 0x0FU);
+ console_tx_nibble((value >> 20U) & 0x0FU);
+ console_tx_nibble((value >> 16U) & 0x0FU);
+ console_tx_nibble((value >> 12U) & 0x0FU);
+ console_tx_nibble((value >> 8U) & 0x0FU);
+ console_tx_nibble((value >> 4U) & 0x0FU);
+ console_tx_nibble(value & 0x0FU);
+}
+
+static void console_tx_string(const char *str)
+{
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ console_tx_byte(ch);
+ }
+}
+
+static void print_debug_char(unsigned char byte) { console_tx_char(byte); }
+static void print_debug_hex8(unsigned char value) { console_tx_hex8(value); }
+static void print_debug_hex16(unsigned short value){ console_tx_hex16(value); }
+static void print_debug_hex32(unsigned int value) { console_tx_hex32(value); }
+static void print_debug(const char *str) { console_tx_string(str); }
+
+
+static void setup_coherent_ht_domain(void)
+{
+ static const unsigned int register_values[] = {
+#if 1
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x40) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x44) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x48) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x4c) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x50) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x54) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x58) & 0xFF)), 0xfff0f0f0, 0x00010101,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x5c) & 0xFF)), 0xfff0f0f0, 0x00010101,
+# 983 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x68) & 0xFF)), 0x00800000, 0x0f00840f,
+# 1005 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x6C) & 0xFF)), 0xffffff8c, 0x00000000 | (1 << 6) |(1 << 5)| (1 << 4),
+# 1082 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x84) & 0xFF)), 0x00009c05, 0x11110020,
+# 1127 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x88) & 0xFF)), 0xfffff0ff, 0x00000200,
+# 1148 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((0) & 0x07) << 8) | ((0x94) & 0xFF)), 0xff000000, 0x00ff0000,
+# 1182 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x44) & 0xFF)), 0x0000f8f8, 0x003f0000,
+
+
+
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x4C) & 0xFF)), 0x0000f8f8, 0x00000001,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x54) & 0xFF)), 0x0000f8f8, 0x00000002,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x5C) & 0xFF)), 0x0000f8f8, 0x00000003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x64) & 0xFF)), 0x0000f8f8, 0x00000004,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x6C) & 0xFF)), 0x0000f8f8, 0x00000005,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x74) & 0xFF)), 0x0000f8f8, 0x00000006,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x7C) & 0xFF)), 0x0000f8f8, 0x00000007,
+# 1224 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x40) & 0xFF)), 0x0000f8fc, 0x00000003,
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x48) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x50) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x58) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x60) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x68) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x70) & 0xFF)), 0x0000f8fc, 0x00400000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x78) & 0xFF)), 0x0000f8fc, 0x00400000,
+# 1276 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x84) & 0xFF)), 0x00000048, 0x00e1ff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x8C) & 0xFF)), 0x00000048, 0x00dfff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x94) & 0xFF)), 0x00000048, 0x00e3ff00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x9C) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA4) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xAC) & 0xFF)), 0x00000048, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB4) & 0xFF)), 0x00000048, 0x00000b00,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xBC) & 0xFF)), 0x00000048, 0x00fe0b00,
+# 1311 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x80) & 0xFF)), 0x000000f0, 0x00e00003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x88) & 0xFF)), 0x000000f0, 0x00d80003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x90) & 0xFF)), 0x000000f0, 0x00e20003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0x98) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA0) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xA8) & 0xFF)), 0x000000f0, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB0) & 0xFF)), 0x000000f0, 0x00000a03,
+
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xB8) & 0xFF)), 0x000000f0, 0x00400003,
+# 1350 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC4) & 0xFF)), 0xFE000FC8, 0x0000d000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xCC) & 0xFF)), 0xFE000FC8, 0x000ff000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD4) & 0xFF)), 0xFE000FC8, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xDC) & 0xFF)), 0xFE000FC8, 0x00000000,
+# 1380 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC0) & 0xFF)), 0xFE000FCC, 0x0000d003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xC8) & 0xFF)), 0xFE000FCC, 0x00001013,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD0) & 0xFF)), 0xFE000FCC, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xD8) & 0xFF)), 0xFE000FCC, 0x00000000,
+# 1421 "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/mainboard/amd/solo/auto.c"
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE0) & 0xFF)), 0x0000FC88, 0xff000003,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE4) & 0xFF)), 0x0000FC88, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xE8) & 0xFF)), 0x0000FC88, 0x00000000,
+ ( (((0) & 0xFF) << 16) | (((0x18) & 0x1f) << 11) | (((1) & 0x07) << 8) | ((0xEC) & 0xFF)), 0x0000FC88, 0x00000000,
+#else
+#define PCI_ADDR(BUS, DEV, FN, WHERE) ( \
+ (((BUS) & 0xFF) << 16) | \
+ (((DEV) & 0x1f) << 11) | \
+ (((FN) & 0x07) << 8) | \
+ ((WHERE) & 0xFF))
+
+ /* Routing Table Node i
+ * F0:0x40 i = 0,
+ * F0:0x44 i = 1,
+ * F0:0x48 i = 2,
+ * F0:0x4c i = 3,
+ * F0:0x50 i = 4,
+ * F0:0x54 i = 5,
+ * F0:0x58 i = 6,
+ * F0:0x5c i = 7
+ * [ 0: 3] Request Route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ * [11: 8] Response Route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ * [19:16] Broadcast route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ */
+ PCI_ADDR(0, 0x18, 0, 0x40), 0xfff0f0f0, 0x00010101,
+ PCI_ADDR(0, 0x18, 0, 0x44), 0xfff0f0f0, 0x00010101,
+ PCI_ADDR(0, 0x18, 0, 0x48), 0xfff0f0f0, 0x00010101,
+ PCI_ADDR(0, 0x18, 0, 0x4c), 0xfff0f0f0, 0x00010101,
+ PCI_ADDR(0, 0x18, 0, 0x50), 0xfff0f0f0, 0x00010101,
+ PCI_ADDR(0, 0x18, 0, 0x54), 0xfff0f0f0, 0x00010101,
+ PCI_ADDR(0, 0x18, 0, 0x58), 0xfff0f0f0, 0x00010101,
+ PCI_ADDR(0, 0x18, 0, 0x5c), 0xfff0f0f0, 0x00010101,
+
+ /* Hypetransport Transaction Control Register
+ * F0:0x68
+ * [ 0: 0] Disable read byte probe
+ * 0 = Probes issues
+ * 1 = Probes not issued
+ * [ 1: 1] Disable Read Doubleword probe
+ * 0 = Probes issued
+ * 1 = Probes not issued
+ * [ 2: 2] Disable write byte probes
+ * 0 = Probes issued
+ * 1 = Probes not issued
+ * [ 3: 3] Disable Write Doubleword Probes
+ * 0 = Probes issued
+ * 1 = Probes not issued.
+ * [ 4: 4] Disable Memroy Controller Target Start
+ * 0 = TgtStart packets are generated
+ * 1 = TgtStart packets are not generated.
+ * [ 5: 5] CPU1 Enable
+ * 0 = Second CPU disabled or not present
+ * 1 = Second CPU enabled.
+ * [ 6: 6] CPU Request PassPW
+ * 0 = CPU requests do not pass posted writes
+ * 1 = CPU requests pass posted writes.
+ * [ 7: 7] CPU read Respons PassPW
+ * 0 = CPU Responses do not pass posted writes
+ * 1 = CPU responses pass posted writes.
+ * [ 8: 8] Disable Probe Memory Cancel
+ * 0 = Probes may generate MemCancels
+ * 1 = Probes may not generate MemCancels
+ * [ 9: 9] Disable Remote Probe Memory Cancel.
+ * 0 = Probes hitting dirty blocks generate memory cancel packets
+ * 1 = Only probed caches on the same node as the memory controller
+ * generate cancel packets.
+ * [10:10] Disable Fill Probe
+ * 0 = Probes issued for cache fills
+ * 1 = Probes not issued for cache fills.
+ * [11:11] Response PassPw
+ * 0 = Downstream response PassPW based on original request
+ * 1 = Downstream response PassPW set to 1
+ * [12:12] Change ISOC to Ordered
+ * 0 = Bit 1 of coherent HT RdSz/WrSz command used for iosynchronous prioritization
+ * 1 = Bit 1 of coherent HT RdSz/WrSz command used for ordering.
+ * [14:13] Buffer Release Priority select
+ * 00 = 64
+ * 01 = 16
+ * 10 = 8
+ * 11 = 2
+ * [15:15] Limit Coherent HT Configuration Space Range
+ * 0 = No coherent HT configuration space restrictions
+ * 1 = Limit coherent HT configuration space based on node count
+ * [16:16] Local Interrupt Conversion Enable.
+ * 0 = ExtInt/NMI interrups unaffected.
+ * 1 = ExtInt/NMI broadcat interrupts converted to LINT0/1
+ * [17:17] APIC Extended Broadcast Enable.
+ * 0 = APIC broadcast is 0F
+ * 1 = APIC broadcast is FF
+ * [18:18] APIC Extended ID Enable
+ * 0 = APIC ID is 4 bits.
+ * 1 = APIC ID is 8 bits.
+ * [19:19] APIC Extended Spurious Vector Enable
+ * 0 = Lower 4 bits of spurious vector are read-only 1111
+ * 1 = Lower 4 bits of spurious vecotr are writeable.
+ * [20:20] Sequence ID Source Node Enable
+ * 0 = Normal operation
+ * 1 = Keep SeqID on routed packets for debugging.
+ * [22:21] Downstream non-posted request limit
+ * 00 = No limit
+ * 01 = Limited to 1
+ * 10 = Limited to 4
+ * 11 = Limited to 8
+ * [23:23] RESERVED
+ * [25:24] Medium-Priority Bypass Count
+ * - Maximum # of times a medium priority access can pass a low
+ * priority access before Medium-Priority mode is disabled for one access.
+ * [27:26] High-Priority Bypass Count
+ * - Maximum # of times a high prioirty access can pass a medium or low
+ * priority access before High-prioirty mode is disabled for one access.
+ * [28:28] Enable High Priority CPU Reads
+ * 0 = Cpu reads are medium prioirty
+ * 1 = Cpu reads are high prioirty
+ * [29:29] Disable Low Priority Writes
+ * 0 = Non-isochronous writes are low priority
+ * 1 = Non-isochronous writes are medium prioirty
+ * [30:30] Disable High Priority Isochronous writes
+ * 0 = Isochronous writes are high priority
+ * 1 = Isochronous writes are medium priority
+ * [31:31] Disable Medium Priority Isochronous writes
+ * 0 = Isochronous writes are medium are high
+ * 1 = With bit 30 set makes Isochrouns writes low priority.
+ */
+ PCI_ADDR(0, 0x18, 0, 0x68), 0x00800000, 0x0f00840f,
+ /* HT Initialization Control Register
+ * F0:0x6C
+ * [ 0: 0] Routing Table Disable
+ * 0 = Packets are routed according to routing tables
+ * 1 = Packets are routed according to the default link field
+ * [ 1: 1] Request Disable (BSP should clear this)
+ * 0 = Request packets may be generated
+ * 1 = Request packets may not be generated.
+ * [ 3: 2] Default Link (Read-only)
+ * 00 = LDT0
+ * 01 = LDT1
+ * 10 = LDT2
+ * 11 = CPU on same node
+ * [ 4: 4] Cold Reset
+ * - Scratch bit cleared by a cold reset
+ * [ 5: 5] BIOS Reset Detect
+ * - Scratch bit cleared by a cold reset
+ * [ 6: 6] INIT Detect
+ * - Scratch bit cleared by a warm or cold reset not by an INIT
+ *
+ */
+ PCI_ADDR(0, 0x18, 0, 0x6C), 0xffffff8c, 0x00000000 | (1 << 6) |(1 << 5)| (1 << 4),
+ /* LDTi Capabilities Registers
+ * F0:0x80 i = 0,
+ * F0:0xA0 i = 1,
+ * F0:0xC0 i = 2,
+ */
+ /* LDTi Link Control Registrs
+ * F0:0x84 i = 0,
+ * F0:0xA4 i = 1,
+ * F0:0xC4 i = 2,
+ * [ 1: 1] CRC Flood Enable
+ * 0 = Do not generate sync packets on CRC error
+ * 1 = Generate sync packets on CRC error
+ * [ 2: 2] CRC Start Test (Read-Only)
+ * [ 3: 3] CRC Force Frame Error
+ * 0 = Do not generate bad CRC
+ * 1 = Generate bad CRC
+ * [ 4: 4] Link Failure
+ * 0 = No link failure detected
+ * 1 = Link failure detected
+ * [ 5: 5] Initialization Complete
+ * 0 = Initialization not complete
+ * 1 = Initialization complete
+ * [ 6: 6] Receiver off
+ * 0 = Recevier on
+ * 1 = Receiver off
+ * [ 7: 7] Transmitter Off
+ * 0 = Transmitter on
+ * 1 = Transmitter off
+ * [ 9: 8] CRC_Error
+ * 00 = No error
+ * [0] = 1 Error on byte lane 0
+ * [1] = 1 Error on byte lane 1
+ * [12:12] Isochrnous Enable (Read-Only)
+ * [13:13] HT Stop Tristate Enable
+ * 0 = Driven during an LDTSTOP_L
+ * 1 = Tristated during and LDTSTOP_L
+ * [14:14] Extended CTL Time
+ * 0 = CTL is asserted for 16 bit times during link initialization
+ * 1 = CTL is asserted for 50us during link initialization
+ * [18:16] Max Link Width In (Read-Only?)
+ * 000 = 8 bit link
+ * 001 = 16bit link
+ * [19:19] Doubleword Flow Control in (Read-Only)
+ * 0 = This link does not support doubleword flow control
+ * 1 = This link supports doubleword flow control
+ * [22:20] Max Link Width Out (Read-Only?)
+ * 000 = 8 bit link
+ * 001 = 16bit link
+ * [23:23] Doubleworld Flow Control out (Read-Only)
+ * 0 = This link does not support doubleword flow control
+ * 1 = This link supports doubleworkd flow control
+ * [26:24] Link Width In
+ * 000 = Use 8 bits
+ * 001 = Use 16 bits
+ * 010 = reserved
+ * 011 = Use 32 bits
+ * 100 = Use 2 bits
+ * 101 = Use 4 bits
+ * 110 = reserved
+ * 111 = Link physically not connected
+ * [27:27] Doubleword Flow Control In Enable
+ * 0 = Doubleword flow control disabled
+ * 1 = Doubleword flow control enabled (Not currently supported)
+ * [30:28] Link Width Out
+ * 000 = Use 8 bits
+ * 001 = Use 16 bits
+ * 010 = reserved
+ * 011 = Use 32 bits
+ * 100 = Use 2 bits
+ * 101 = Use 4 bits
+ * 110 = reserved
+ * 111 = Link physically not connected
+ * [31:31] Doubleworld Flow Control Out Enable
+ * 0 = Doubleworld flow control disabled
+ * 1 = Doubleword flow control enabled (Not currently supported)
+ */
+ PCI_ADDR(0, 0x18, 0, 0x84), 0x00009c05, 0x11110020,
+ /* LDTi Frequency/Revision Registers
+ * F0:0x88 i = 0,
+ * F0:0xA8 i = 1,
+ * F0:0xC8 i = 2,
+ * [ 4: 0] Minor Revision
+ * Contains the HT Minor revision
+ * [ 7: 5] Major Revision
+ * Contains the HT Major revision
+ * [11: 8] Link Frequency (Takes effect the next time the link is reconnected)
+ * 0000 = 200Mhz
+ * 0001 = reserved
+ * 0010 = 400Mhz
+ * 0011 = reserved
+ * 0100 = 600Mhz
+ * 0101 = 800Mhz
+ * 0110 = 1000Mhz
+ * 0111 = reserved
+ * 1000 = reserved
+ * 1001 = reserved
+ * 1010 = reserved
+ * 1011 = reserved
+ * 1100 = reserved
+ * 1101 = reserved
+ * 1110 = reserved
+ * 1111 = 100 Mhz
+ * [15:12] Error (Not currently Implemented)
+ * [31:16] Indicates the frequency capabilities of the link
+ * [16] = 1 encoding 0000 of freq supported
+ * [17] = 1 encoding 0001 of freq supported
+ * [18] = 1 encoding 0010 of freq supported
+ * [19] = 1 encoding 0011 of freq supported
+ * [20] = 1 encoding 0100 of freq supported
+ * [21] = 1 encoding 0101 of freq supported
+ * [22] = 1 encoding 0110 of freq supported
+ * [23] = 1 encoding 0111 of freq supported
+ * [24] = 1 encoding 1000 of freq supported
+ * [25] = 1 encoding 1001 of freq supported
+ * [26] = 1 encoding 1010 of freq supported
+ * [27] = 1 encoding 1011 of freq supported
+ * [28] = 1 encoding 1100 of freq supported
+ * [29] = 1 encoding 1101 of freq supported
+ * [30] = 1 encoding 1110 of freq supported
+ * [31] = 1 encoding 1111 of freq supported
+ */
+ PCI_ADDR(0, 0x18, 0, 0x88), 0xfffff0ff, 0x00000200,
+ /* LDTi Feature Capability
+ * F0:0x8C i = 0,
+ * F0:0xAC i = 1,
+ * F0:0xCC i = 2,
+ */
+ /* LDTi Buffer Count Registers
+ * F0:0x90 i = 0,
+ * F0:0xB0 i = 1,
+ * F0:0xD0 i = 2,
+ */
+ /* LDTi Bus Number Registers
+ * F0:0x94 i = 0,
+ * F0:0xB4 i = 1,
+ * F0:0xD4 i = 2,
+ * For NonCoherent HT specifies the bus number downstream (behind the host bridge)
+ * [ 0: 7] Primary Bus Number
+ * [15: 8] Secondary Bus Number
+ * [23:15] Subordiante Bus Number
+ * [31:24] reserved
+ */
+ PCI_ADDR(0, 0x18, 0, 0x94), 0xff000000, 0x00ff0000,
+ /* LDTi Type Registers
+ * F0:0x98 i = 0,
+ * F0:0xB8 i = 1,
+ * F0:0xD8 i = 2,
+ */
+ /* Careful set limit registers before base registers which contain the enables */
+ /* DRAM Limit i Registers
+ * F1:0x44 i = 0
+ * F1:0x4C i = 1
+ * F1:0x54 i = 2
+ * F1:0x5C i = 3
+ * F1:0x64 i = 4
+ * F1:0x6C i = 5
+ * F1:0x74 i = 6
+ * F1:0x7C i = 7
+ * [ 2: 0] Destination Node ID
+ * 000 = Node 0
+ * 001 = Node 1
+ * 010 = Node 2
+ * 011 = Node 3
+ * 100 = Node 4
+ * 101 = Node 5
+ * 110 = Node 6
+ * 111 = Node 7
+ * [ 7: 3] Reserved
+ * [10: 8] Interleave select
+ * specifies the values of A[14:12] to use with interleave enable.
+ * [15:11] Reserved
+ * [31:16] DRAM Limit Address i Bits 39-24
+ * This field defines the upper address bits of a 40 bit address
+ * that define the end of the DRAM region.
+ */
+#if MEMORY_1024MB
+ PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x003f0000,
+#endif
+#if MEMORY_512MB
+ PCI_ADDR(0, 0x18, 1, 0x44), 0x0000f8f8, 0x001f0000,
+#endif
+ PCI_ADDR(0, 0x18, 1, 0x4C), 0x0000f8f8, 0x00000001,
+ PCI_ADDR(0, 0x18, 1, 0x54), 0x0000f8f8, 0x00000002,
+ PCI_ADDR(0, 0x18, 1, 0x5C), 0x0000f8f8, 0x00000003,
+ PCI_ADDR(0, 0x18, 1, 0x64), 0x0000f8f8, 0x00000004,
+ PCI_ADDR(0, 0x18, 1, 0x6C), 0x0000f8f8, 0x00000005,
+ PCI_ADDR(0, 0x18, 1, 0x74), 0x0000f8f8, 0x00000006,
+ PCI_ADDR(0, 0x18, 1, 0x7C), 0x0000f8f8, 0x00000007,
+ /* DRAM Base i Registers
+ * F1:0x40 i = 0
+ * F1:0x48 i = 1
+ * F1:0x50 i = 2
+ * F1:0x58 i = 3
+ * F1:0x60 i = 4
+ * F1:0x68 i = 5
+ * F1:0x70 i = 6
+ * F1:0x78 i = 7
+ * [ 0: 0] Read Enable
+ * 0 = Reads Disabled
+ * 1 = Reads Enabled
+ * [ 1: 1] Write Enable
+ * 0 = Writes Disabled
+ * 1 = Writes Enabled
+ * [ 7: 2] Reserved
+ * [10: 8] Interleave Enable
+ * 000 = No interleave
+ * 001 = Interleave on A[12] (2 nodes)
+ * 010 = reserved
+ * 011 = Interleave on A[12] and A[14] (4 nodes)
+ * 100 = reserved
+ * 101 = reserved
+ * 110 = reserved
+ * 111 = Interleve on A[12] and A[13] and A[14] (8 nodes)
+ * [15:11] Reserved
+ * [13:16] DRAM Base Address i Bits 39-24
+ * This field defines the upper address bits of a 40-bit address
+ * that define the start of the DRAM region.
+ */
+ PCI_ADDR(0, 0x18, 1, 0x40), 0x0000f8fc, 0x00000003,
+#if MEMORY_1024MB
+ PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00400000,
+ PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00400000,
+ PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00400000,
+ PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00400000,
+ PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00400000,
+ PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00400000,
+ PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00400000,
+#endif
+#if MEMORY_512MB
+ PCI_ADDR(0, 0x18, 1, 0x48), 0x0000f8fc, 0x00200000,
+ PCI_ADDR(0, 0x18, 1, 0x50), 0x0000f8fc, 0x00200000,
+ PCI_ADDR(0, 0x18, 1, 0x58), 0x0000f8fc, 0x00200000,
+ PCI_ADDR(0, 0x18, 1, 0x60), 0x0000f8fc, 0x00200000,
+ PCI_ADDR(0, 0x18, 1, 0x68), 0x0000f8fc, 0x00200000,
+ PCI_ADDR(0, 0x18, 1, 0x70), 0x0000f8fc, 0x00200000,
+ PCI_ADDR(0, 0x18, 1, 0x78), 0x0000f8fc, 0x00200000,
+#endif
+
+ /* Memory-Mapped I/O Limit i Registers
+ * F1:0x84 i = 0
+ * F1:0x8C i = 1
+ * F1:0x94 i = 2
+ * F1:0x9C i = 3
+ * F1:0xA4 i = 4
+ * F1:0xAC i = 5
+ * F1:0xB4 i = 6
+ * F1:0xBC i = 7
+ * [ 2: 0] Destination Node ID
+ * 000 = Node 0
+ * 001 = Node 1
+ * 010 = Node 2
+ * 011 = Node 3
+ * 100 = Node 4
+ * 101 = Node 5
+ * 110 = Node 6
+ * 111 = Node 7
+ * [ 3: 3] Reserved
+ * [ 5: 4] Destination Link ID
+ * 00 = Link 0
+ * 01 = Link 1
+ * 10 = Link 2
+ * 11 = Reserved
+ * [ 6: 6] Reserved
+ * [ 7: 7] Non-Posted
+ * 0 = CPU writes may be posted
+ * 1 = CPU writes must be non-posted
+ * [31: 8] Memory-Mapped I/O Limit Address i (39-16)
+ * This field defines the upp adddress bits of a 40-bit address that
+ * defines the end of a memory-mapped I/O region n
+ */
+ PCI_ADDR(0, 0x18, 1, 0x84), 0x00000048, 0x00e1ff00,
+ PCI_ADDR(0, 0x18, 1, 0x8C), 0x00000048, 0x00dfff00,
+ PCI_ADDR(0, 0x18, 1, 0x94), 0x00000048, 0x00e3ff00,
+ PCI_ADDR(0, 0x18, 1, 0x9C), 0x00000048, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xA4), 0x00000048, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xAC), 0x00000048, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xB4), 0x00000048, 0x00000b00,
+ PCI_ADDR(0, 0x18, 1, 0xBC), 0x00000048, 0x00fe0b00,
+
+ /* Memory-Mapped I/O Base i Registers
+ * F1:0x80 i = 0
+ * F1:0x88 i = 1
+ * F1:0x90 i = 2
+ * F1:0x98 i = 3
+ * F1:0xA0 i = 4
+ * F1:0xA8 i = 5
+ * F1:0xB0 i = 6
+ * F1:0xB8 i = 7
+ * [ 0: 0] Read Enable
+ * 0 = Reads disabled
+ * 1 = Reads Enabled
+ * [ 1: 1] Write Enable
+ * 0 = Writes disabled
+ * 1 = Writes Enabled
+ * [ 2: 2] Cpu Disable
+ * 0 = Cpu can use this I/O range
+ * 1 = Cpu requests do not use this I/O range
+ * [ 3: 3] Lock
+ * 0 = base/limit registers i are read/write
+ * 1 = base/limit registers i are read-only
+ * [ 7: 4] Reserved
+ * [31: 8] Memory-Mapped I/O Base Address i (39-16)
+ * This field defines the upper address bits of a 40bit address
+ * that defines the start of memory-mapped I/O region i
+ */
+ PCI_ADDR(0, 0x18, 1, 0x80), 0x000000f0, 0x00e00003,
+ PCI_ADDR(0, 0x18, 1, 0x88), 0x000000f0, 0x00d80003,
+ PCI_ADDR(0, 0x18, 1, 0x90), 0x000000f0, 0x00e20003,
+ PCI_ADDR(0, 0x18, 1, 0x98), 0x000000f0, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xA0), 0x000000f0, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xA8), 0x000000f0, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xB0), 0x000000f0, 0x00000a03,
+#if MEMORY_1024MB
+ PCI_ADDR(0, 0x18, 1, 0xB8), 0x000000f0, 0x00400003,
+#endif
+#if MEMORY_512MB
+ PCI_ADDR(0, 0x18, 1, 0xB8), 0x000000f0, 0x00200003,
+#endif
+
+ /* PCI I/O Limit i Registers
+ * F1:0xC4 i = 0
+ * F1:0xCC i = 1
+ * F1:0xD4 i = 2
+ * F1:0xDC i = 3
+ * [ 2: 0] Destination Node ID
+ * 000 = Node 0
+ * 001 = Node 1
+ * 010 = Node 2
+ * 011 = Node 3
+ * 100 = Node 4
+ * 101 = Node 5
+ * 110 = Node 6
+ * 111 = Node 7
+ * [ 3: 3] Reserved
+ * [ 5: 4] Destination Link ID
+ * 00 = Link 0
+ * 01 = Link 1
+ * 10 = Link 2
+ * 11 = reserved
+ * [11: 6] Reserved
+ * [24:12] PCI I/O Limit Address i
+ * This field defines the end of PCI I/O region n
+ * [31:25] Reserved
+ */
+ PCI_ADDR(0, 0x18, 1, 0xC4), 0xFE000FC8, 0x0000d000,
+ PCI_ADDR(0, 0x18, 1, 0xCC), 0xFE000FC8, 0x000ff000,
+ PCI_ADDR(0, 0x18, 1, 0xD4), 0xFE000FC8, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xDC), 0xFE000FC8, 0x00000000,
+
+ /* PCI I/O Base i Registers
+ * F1:0xC0 i = 0
+ * F1:0xC8 i = 1
+ * F1:0xD0 i = 2
+ * F1:0xD8 i = 3
+ * [ 0: 0] Read Enable
+ * 0 = Reads Disabled
+ * 1 = Reads Enabled
+ * [ 1: 1] Write Enable
+ * 0 = Writes Disabled
+ * 1 = Writes Enabled
+ * [ 3: 2] Reserved
+ * [ 4: 4] VGA Enable
+ * 0 = VGA matches Disabled
+ * 1 = matches all address < 64K and where A[9:0] is in the
+ * range 3B0-3BB or 3C0-3DF independen of the base & limit registers
+ * [ 5: 5] ISA Enable
+ * 0 = ISA matches Disabled
+ * 1 = Blocks address < 64K and in the last 768 bytes of eack 1K block
+ * from matching agains this base/limit pair
+ * [11: 6] Reserved
+ * [24:12] PCI I/O Base i
+ * This field defines the start of PCI I/O region n
+ * [31:25] Reserved
+ */
+ PCI_ADDR(0, 0x18, 1, 0xC0), 0xFE000FCC, 0x0000d003,
+ PCI_ADDR(0, 0x18, 1, 0xC8), 0xFE000FCC, 0x00001013,
+ PCI_ADDR(0, 0x18, 1, 0xD0), 0xFE000FCC, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xD8), 0xFE000FCC, 0x00000000,
+
+ /* Config Base and Limit i Registers
+ * F1:0xE0 i = 0
+ * F1:0xE4 i = 1
+ * F1:0xE8 i = 2
+ * F1:0xEC i = 3
+ * [ 0: 0] Read Enable
+ * 0 = Reads Disabled
+ * 1 = Reads Enabled
+ * [ 1: 1] Write Enable
+ * 0 = Writes Disabled
+ * 1 = Writes Enabled
+ * [ 2: 2] Device Number Compare Enable
+ * 0 = The ranges are based on bus number
+ * 1 = The ranges are ranges of devices on bus 0
+ * [ 3: 3] Reserved
+ * [ 6: 4] Destination Node
+ * 000 = Node 0
+ * 001 = Node 1
+ * 010 = Node 2
+ * 011 = Node 3
+ * 100 = Node 4
+ * 101 = Node 5
+ * 110 = Node 6
+ * 111 = Node 7
+ * [ 7: 7] Reserved
+ * [ 9: 8] Destination Link
+ * 00 = Link 0
+ * 01 = Link 1
+ * 10 = Link 2
+ * 11 - Reserved
+ * [15:10] Reserved
+ * [23:16] Bus Number Base i
+ * This field defines the lowest bus number in configuration region i
+ * [31:24] Bus Number Limit i
+ * This field defines the highest bus number in configuration regin i
+ */
+ PCI_ADDR(0, 0x18, 1, 0xE0), 0x0000FC88, 0xff000003,
+ PCI_ADDR(0, 0x18, 1, 0xE4), 0x0000FC88, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xE8), 0x0000FC88, 0x00000000,
+ PCI_ADDR(0, 0x18, 1, 0xEC), 0x0000FC88, 0x00000000,
+#endif
+ };
+ int i;
+ int max;
+ print_debug("setting up coherent ht domain....\r\n");
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ for(i = 0; i < max; i += 3) {
+ unsigned long reg;
+#if 1
+ print_debug_hex32(register_values[i]);
+ print_debug(" <-");
+ print_debug_hex32(register_values[i+2]);
+ print_debug("\r\n");
+#endif
+#if 0
+ reg = pci_read_config32(register_values[i]);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2] & ~register_values[i+1];
+ pci_write_config32(register_values[i], reg);
+#endif
+ }
+ print_debug("done.\r\n");
+}
+
+static void main(void)
+{
+ static const char msg[] = "hello world\r\n";
+#if 0
+ write(STDOUT_FILENO, msg, sizeof(msg));
+#endif
+#if 1
+ setup_coherent_ht_domain();
+#endif
+ _exit(0);
+}
diff --git a/util/romcc/tests/simple_test6.c b/util/romcc/tests/simple_test6.c
index 3dac72d0fb..aba7f1f549 100644
--- a/util/romcc/tests/simple_test6.c
+++ b/util/romcc/tests/simple_test6.c
@@ -260,7 +260,7 @@ static void test(void)
#if 1
outb(m, 0xab);
#endif
-#if 0
+#if 1
outb(n, 0xab);
#endif
#if 0