- Update romcc to version 0.27 and add more tests.
authorEric Biederman <ebiederm@xmission.com>
Tue, 10 Jun 2003 21:22:07 +0000 (21:22 +0000)
committerEric Biederman <ebiederm@xmission.com>
Tue, 10 Jun 2003 21:22:07 +0000 (21:22 +0000)
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@865 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

18 files changed:
util/romcc/Makefile
util/romcc/romcc.c
util/romcc/tests/hello_world2.c [new file with mode: 0644]
util/romcc/tests/ldscript.ld [new file with mode: 0644]
util/romcc/tests/raminit_test.c
util/romcc/tests/raminit_test2.c
util/romcc/tests/raminit_test3.c [new file with mode: 0644]
util/romcc/tests/simple_test21.c [new file with mode: 0644]
util/romcc/tests/simple_test22.c [new file with mode: 0644]
util/romcc/tests/simple_test23.c [new file with mode: 0644]
util/romcc/tests/simple_test24.c [new file with mode: 0644]
util/romcc/tests/simple_test25.c [new file with mode: 0644]
util/romcc/tests/simple_test26.c [new file with mode: 0644]
util/romcc/tests/simple_test27.c [new file with mode: 0644]
util/romcc/tests/simple_test28.c [new file with mode: 0644]
util/romcc/tests/simple_test29.c [new file with mode: 0644]
util/romcc/tests/simple_test30.c [new file with mode: 0644]
util/romcc/tests/simple_test6.c

index eb84ceec297f0b270bf20c148c03759b95cf8a66..ad209a52471e4c5c5f1480dd0afb92d2ed1db154 100644 (file)
@@ -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
 
index 386aa06b8198c9830d0a76b94e63d111d3037b96..255b6d499504276a8f95b8d4bcb22b769ecde65a 100644 (file)
 #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,27 +10207,314 @@ 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);
        }
        
 }
 
-static void insert_copies_to_phi(struct compile_state *state)
-{
-       /* To get out of ssa form we insert moves on the incoming
-        * edges to blocks containting phi functions.
-        */
+
+/* 
+ * 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
+        * edges to blocks containting phi functions.
+        */
        struct triple *first;
        struct triple *phi;
 
@@ -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.
         */
-       rstate->ranges = count_triples(state);
-       size = sizeof(rstate->lr[0]) * (rstate->ranges + 1);
-       rstate->lr = xcmalloc(size, "live_range");
+       count = count_triples(state);
+       /* Potentially I need one live range definitions for each
+        * instruction, plus an extra for the split routines.
+        */
+       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);
+               }
+
+               
+               /* Allocate and initialize the live ranges */
+               initialize_live_ranges(state, &rstate);
+               
+               do {
+                       /* Forget previous live range edge calculations */
+                       cleanup_live_edges(&rstate);
 
-               /* If it has a low degree or it already has a color
-                * place the node in low.
+                       /* 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,61 +15122,123 @@ 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);
+       set = post_triple(state, ins, set_op, ins->type, ins, 0);
+       use_triple(ins, set);
+       set->template_id = TEMPLATE_SET;
+
+       for(entry = ins->use; entry; entry = next) {
+               next = entry->next;
+               if (entry->member == set) {
+                       continue;
+               }
+               replace_rhs_use(state, ins, set, entry->member);
+       }
+       fixup_branches(state, ins, set, jmp_op);
+}
+
+static struct triple *after_lhs(struct compile_state *state, struct triple *ins)
+{
+       struct triple *next;
+       int lhs, i;
+       lhs = TRIPLE_LHS(ins->sizes);
+       for(next = ins->next, i = 0; i < lhs; i++, next = next->next) {
+               if (next != LHS(ins, i)) {
+                       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;
+}
 
-       if (block->last == ins) {
-               block->last = tmp2;
+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));
        }
-
-       set = tmp2;
-       for(entry = ins->use; entry; entry = next) {
-               next = entry->next;
-               if (entry->member == tmp1) {
-                       continue;
+       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);
                }
-               replace_rhs_use(state, ins, set, entry->member);
+               template = &templates[ins->template_id];
+               break;
        }
-       fixup_branches(state, ins, set, jmp_op);
+       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;
 }
 
-static void verify_lhs(struct compile_state *state, struct triple *ins)
+struct reg_info arch_reg_rhs(struct compile_state *state, struct triple *ins, int index)
 {
-       struct triple *next;
-       int lhs, i;
-       lhs = TRIPLE_LHS(ins->sizes);
-       for(next = ins->next, i = 0; i < lhs; i++, next = next->next) {
-               if (next != LHS(ins, i)) {
-                       internal_error(state, ins, "malformed lhs on %s",
-                               tops(ins->op));
+       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 void transform_to_arch_instructions(struct compile_state *state)
+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 (file)
index 0000000..7990dcb
--- /dev/null
@@ -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 (file)
index 0000000..97b307f
--- /dev/null
@@ -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
index 8dd9c977e5b148e5c7a2b45380e95864ba26c244..9b6cf5d31c4791bd3b3c744fe2ad9a6b11283ac6 100644 (file)
@@ -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 "); 
index 8dd9c977e5b148e5c7a2b45380e95864ba26c244..68747a7a910d1de9aa91c24d38965955b1da22e5 100644 (file)
@@ -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 (file)
index 0000000..dc3b476
--- /dev/null
@@ -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 (file)
index 0000000..7f7b871
--- /dev/null
@@ -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 (file)
index 0000000..247369b
--- /dev/null
@@ -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 (file)
index 0000000..33acd04
--- /dev/null
@@ -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 (file)
index 0000000..01413c2
--- /dev/null
@@ -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 (file)
index 0000000..80ddfa6
--- /dev/null
@@ -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 (file)
index 0000000..b26bbb2
--- /dev/null
@@ -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 (file)
index 0000000..d40e43f
--- /dev/null
@@ -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 (file)
index 0000000..8d83383
--- /dev/null
@@ -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 (file)
index 0000000..7eb8f4f
--- /dev/null
@@ -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 (file)
index 0000000..fc21fc6
--- /dev/null
@@ -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);
+}
index 3dac72d0fb4e494ee10288514c88682e474030b1..aba7f1f5493bcfc89546107470a889081b3f9da6 100644 (file)
@@ -260,7 +260,7 @@ static void test(void)
 #if 1
        outb(m, 0xab);
 #endif
-#if 0
+#if 1
        outb(n, 0xab);
 #endif
 #if 0