- A new test case for romcc
- Minor romcc fixes
- In smbus_wail_until_done a romcc glitch with || in romcc where it likes
  to run out of registers.  Use | to be explicit that I don't need the short
  circuiting behavior.
- Remove unused #defines from coherent_ht.c
- Update the test in auto.c to 512M
- Add definition of log2 to romcc_io.h
- Implement SPD memory sizing in raminit.c
- Reduce the number of memory devices back 2 to for the SOLO board.


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@883 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
diff --git a/src/arch/i386/include/arch/romcc_io.h b/src/arch/i386/include/arch/romcc_io.h
index 7d3d50e..d67b3b6 100644
--- a/src/arch/i386/include/arch/romcc_io.h
+++ b/src/arch/i386/include/arch/romcc_io.h
@@ -35,6 +35,18 @@
 	__builtin_hlt();
 }
 
+int log2(int value)
+{
+	/* __builtin_bsr is a exactly equivalent to the x86 machine
+	 * instruction with the exception that it returns -1  
+	 * when the value presented to it is zero.
+	 * Otherwise __builtin_bsr returns the zero based index of
+	 * the highest bit set.
+	 */
+	return __builtin_bsr(value);
+}
+
+
 typedef __builtin_msr_t msr_t;
 
 static msr_t rdmsr(unsigned long index)
diff --git a/src/mainboard/amd/solo/auto.c b/src/mainboard/amd/solo/auto.c
index e8e3976..f61b794 100644
--- a/src/mainboard/amd/solo/auto.c
+++ b/src/mainboard/amd/solo/auto.c
@@ -11,6 +11,13 @@
 #include "northbridge/amd/amdk8/coherent_ht.c"
 #include "sdram/generic_sdram.c"
 
+#define NODE_ID		0x60
+#define	HT_INIT_CONTROL 0x6c
+
+#define HTIC_ColdR_Detect  (1<<4)
+#define HTIC_BIOSR_Detect  (1<<5)
+#define HTIC_INIT_Detect   (1<<6)
+
 static int boot_cpu(void)
 {
 	volatile unsigned long *local_apic;
@@ -59,6 +66,16 @@
 }
 
 
+static void print_debug_pci_dev(unsigned dev)
+{
+	print_debug("PCI: ");
+	print_debug_hex8((dev >> 16) & 0xff);
+	print_debug_char(':');
+	print_debug_hex8((dev >> 11) & 0x1f);
+	print_debug_char('.');
+	print_debug_hex8((dev >> 8) & 7);
+}
+
 static void print_pci_devices(void)
 {
 	device_t dev;
@@ -72,15 +89,33 @@
 			(((id >> 16) & 0xffff) == 0x0000)) {
 			continue;
 		}
-		print_debug("PCI: 00:");
-		print_debug_hex8(dev >> 11);
-		print_debug_char('.');
-		print_debug_hex8((dev >> 8) & 7);
+		print_debug_pci_dev(dev);
 		print_debug("\r\n");
 	}
 }
 
 
+static void dump_pci_device(unsigned dev)
+{
+	int i;
+	print_debug_pci_dev(dev);
+	print_debug("\r\n");
+	
+	for(i = 0; i <= 255; i++) {
+		unsigned char val;
+		if ((i & 0x0f) == 0) {
+			print_debug_hex8(i);
+			print_debug_char(':');
+		}
+		val = pci_read_config8(dev, i);
+		print_debug_char(' ');
+		print_debug_hex8(val);
+		if ((i & 0x0f) == 0x0f) {
+			print_debug("\r\n");
+		}
+	}
+}
+
 static void dump_spd_registers(void)
 {
 	unsigned device;
@@ -112,6 +147,7 @@
 	}
 }
 
+
 static void main(void)
 {
 	uart_init();
@@ -132,7 +168,16 @@
 		sdram_initialize();
 
 		dump_spd_registers();
-		/* Check the first 8M */
-		ram_check(0x00100000, 0x00800000);
+		dump_pci_device(PCI_DEV(0, 0x18, 2));
+		
+		/* Check the first 512M */
+		msr_t msr;
+		msr = rdmsr(TOP_MEM);
+		print_debug("TOP_MEM: ");
+		print_debug_hex32(msr.hi);
+		print_debug_hex32(msr.lo);
+		print_debug("\r\n");
+#warning "FIXME if I pass msr.lo somehow I get the value 0x00000030 as stop in ram_check"
+		ram_check(0x00000000, 0x20000000);
 	}
 }
diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c
index 68d8b39..fe2f372 100644
--- a/src/northbridge/amd/amdk8/coherent_ht.c
+++ b/src/northbridge/amd/amdk8/coherent_ht.c
@@ -1,11 +1,3 @@
-#define COHERENT_AMD_SOLO    1 /* AMD Solo motherboard */
-#define COHERENT_ARIMA_HDAMA 2 /* Arima HDAMA motherboard */
-
-#ifndef COHERENT_CONFIG
-#define COHERENT_CONFIG COHERENT_AMD_SOLO
-#endif
-
-
 static void setup_coherent_ht_domain(void)
 {
 	static const unsigned int register_values[] = {
diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c
index 6c757c9..54ca82e 100644
--- a/src/northbridge/amd/amdk8/raminit.c
+++ b/src/northbridge/amd/amdk8/raminit.c
@@ -1,3 +1,4 @@
+#include <cpu/k8/mtrr.h>
 #define MEMORY_SUSE_SOLO  1 /* SuSE Solo configuration */
 #define MEMORY_LNXI_SOLO  2 /* LNXI Solo configuration */
 #define MEMORY_LNXI_HDAMA 3 /* LNXI HDAMA configuration */
@@ -1112,6 +1113,192 @@
 	print_debug("done.\r\n");
 }
 
+
+struct dimm_size {
+	unsigned long side1;
+	unsigned long side2;
+};
+static struct dimm_size spd_get_dimm_size(unsigned device)
+{
+	/* Calculate the log base 2 size of a DIMM in bits */
+	struct dimm_size sz;
+	int value, low;
+	sz.side1 = 0;
+	sz.side2 = 0;
+
+	/* Note it might be easier to use byte 31 here, it has the DIMM size as
+	 * a multiple of 4MB.  The way we do it now we can size both
+	 * sides of an assymetric dimm.
+	 */
+	value = smbus_read_byte(device, 3);	/* rows */
+	if (value < 0) return sz;
+	sz.side1 += value & 0xf;
+
+	value = smbus_read_byte(device, 4);	/* columns */
+	if (value < 0) return sz;
+	sz.side1 += value & 0xf;
+
+	value = smbus_read_byte(device, 17);	/* banks */
+	if (value < 0) return sz;
+	sz.side1 += log2(value & 0xff);
+
+	/* Get the module data widht and convert it to a power of two */
+	value = smbus_read_byte(device, 7);	/* (high byte) */
+	if (value < 0) return sz;
+	value &= 0xff;
+	value <<= 8;
+	
+	low = smbus_read_byte(device, 6);	/* (low byte) */
+	if (low < 0) return sz;
+	value = value | (low & 0xff);
+	sz.side1 += log2(value);
+
+	/* side 2 */
+	value = smbus_read_byte(device, 5);	/* number of physical banks */
+	if (value <= 1) return sz;
+
+	/* Start with the symmetrical case */
+	sz.side2 = sz.side1;
+
+	value = smbus_read_byte(device, 3);	/* rows */
+	if (value < 0) return sz;
+	if ((value & 0xf0) == 0) return sz;	/* If symmetrical we are done */
+	sz.side2 -= (value & 0x0f); 		/* Subtract out rows on side 1 */
+	sz.side2 += ((value >> 4) & 0x0f);	/* Add in rows on side 2 */
+
+	value = smbus_read_byte(device, 4);	/* columns */
+	if (value < 0) return sz;
+	sz.side2 -= (value & 0x0f);		/* Subtract out columns on side 1 */
+	sz.side2 += ((value >> 4) & 0x0f);	/* Add in columsn on side 2 */
+	return sz;
+}
+
+static unsigned spd_to_dimm_side0(unsigned device)
+{
+	return (device - SMBUS_MEM_DEVICE_START) << 1;
+}
+
+static unsigned spd_to_dimm_side1(unsigned device)
+{
+	return ((device - SMBUS_MEM_DEVICE_START) << 1) + 1;
+}
+
+static void set_dimm_size(unsigned long size, unsigned index)
+{
+	unsigned value = 0;
+	/* Make certain the dimm is at least 32MB */
+	if (size >= (25 + 3)) {
+		/* Place the dimm size in 32 MB quantities in the bits 31 - 21.
+		 * The initialize dimm size is in bits.
+		 * Set the base enable bit0.
+		 */
+		value = (1 << ((size - (25 + 3)) + 21)) | 1;
+	}
+	/* Set the appropriate DIMM base address register */
+	pci_write_config32(PCI_DEV(0, 0x18, 2), 0x40 + (index << 2), value);
+}
+
+static void spd_set_ram_size(void)
+{
+	unsigned device;
+	for(device = SMBUS_MEM_DEVICE_START; 
+		device <= SMBUS_MEM_DEVICE_END;
+		device += SMBUS_MEM_DEVICE_INC) 
+	{
+		struct dimm_size sz;
+		sz = spd_get_dimm_size(device);
+		set_dimm_size(sz.side1, spd_to_dimm_side0(device));
+		set_dimm_size(sz.side2, spd_to_dimm_side1(device));
+	}
+}
+
+static void set_top_mem(unsigned tom_k)
+{
+	/* Error if I don't have memory */
+	if (!tom_k) {
+		die("No memory");
+	}
+	/* Now set top of memory */
+	msr_t msr;
+	msr.lo = (tom_k & 0x003fffff) << 10;
+	msr.hi = (tom_k & 0xffc00000) >> 22;
+	wrmsr(TOP_MEM, msr);
+
+#if 1
+	/* And report the amount of memory.  (I run out of registers if i don't) */
+	print_debug("RAM: 0x");
+	print_debug_hex32(tom_k);
+	print_debug(" KB\r\n");
+#endif
+}
+
+static void order_dimms(void)
+{
+	unsigned long tom;
+	unsigned mask;
+	unsigned index;
+
+	/* Remember which registers we have used in the high 8 bits of tom */
+	tom = 0;
+	for(;;) {
+		/* Find the largest remaining canidate */
+		unsigned canidate;
+		uint32_t csbase, csmask;
+		unsigned size;
+		csbase = 0;
+		canidate = 0;
+		for(index = 0; index < 8; index++) {
+			uint32_t value;
+			value = pci_read_config32(PCI_DEV(0, 0x18, 2), 0x40 + (index << 2));
+
+			/* Is it enabled? */
+			if (!(value & 1)) {
+				continue;
+			}
+			
+			/* Is it greater? */
+			if (value <= csbase) {
+				continue;
+			}
+			
+			/* Has it already been selected */
+			if (tom & (1 << (index + 24))) {
+				continue;
+			}
+			/* I have a new canidate */
+			csbase = value;
+			canidate = index;
+		}
+		/* See if I have found a new canidate */
+		if (csbase == 0) {
+			break;
+		}
+
+		/* Remember I have used this register */
+		tom |= (1 << (canidate + 24));
+
+		/* Remember the dimm size */
+		size = csbase >> 21;
+
+		/* Recompute the cs base register value */
+		csbase = (tom << 21) | 1;
+
+		/* Increment the top of memory */
+		tom += size;
+
+		/* Compute the memory mask */
+		csmask = ((size -1) << 21);
+		csmask |= 0xfe00; 		/* For now don't optimize */
+
+		/* Write the new base register */
+		pci_write_config32(PCI_DEV(0, 0x18, 2), 0x40 + (canidate << 2), csbase);
+		pci_write_config32(PCI_DEV(0, 0x18, 2), 0x60 + (canidate << 2), csmask);
+		
+	}
+	set_top_mem((tom & ~0xff000000) << 15);
+}
+
+
 #define DRAM_CONFIG_LOW 0x90
 #define  DCL_DLL_Disable   (1<<0)
 #define  DCL_D_DRV         (1<<1)
@@ -1122,20 +1309,21 @@
 #define  DCL_MemClrStatus  (1<<11)
 #define  DCL_DimmEcEn      (1<<17)
 
-#define NODE_ID		0x60
-#define	HT_INIT_CONTROL 0x6c
 
-#define HTIC_ColdR_Detect  (1<<4)
-#define HTIC_BIOSR_Detect  (1<<5)
-#define HTIC_INIT_Detect   (1<<6)
-
-static void sdram_set_spd_registers(void) 
+static void spd_set_ecc_mode(void)
 {
 	unsigned long dcl;
 	dcl = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW);
 	/* Until I know what is going on disable ECC support */
 	dcl &= ~DCL_DimmEcEn;
 	pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW, dcl);
+
+}
+static void sdram_set_spd_registers(void) 
+{
+	spd_set_ram_size();
+	spd_set_ecc_mode();
+	order_dimms();
 }
 
 #define TIMEOUT_LOOPS 300000
diff --git a/src/southbridge/amd/amd8111/amd8111_early_smbus.c b/src/southbridge/amd/amd8111/amd8111_early_smbus.c
index 6b6d9ad..33f5588 100644
--- a/src/southbridge/amd/amd8111/amd8111_early_smbus.c
+++ b/src/southbridge/amd/amd8111/amd8111_early_smbus.c
@@ -53,7 +53,7 @@
 		smbus_delay();
 		
 		val = inw(SMBUS_IO_BASE + SMBGSTATUS);
-		if (((val & 0x8) == 0) || ((val & 0x437) != 0)) {
+		if (((val & 0x8) == 0) | ((val & 0x437) != 0)) {
 			break;
 		}
 	} while(--loops);
diff --git a/util/romcc/Makefile b/util/romcc/Makefile
index be2d031..9722ca3 100644
--- a/util/romcc/Makefile
+++ b/util/romcc/Makefile
@@ -51,6 +51,7 @@
 	simple_test30.c \
 	simple_test31.c \
 	simple_test32.c \
+	simple_test33.c \
 	raminit_test.c \
 	raminit_test2.c \
 	raminit_test3.c \
diff --git a/util/romcc/romcc.c b/util/romcc/romcc.c
index 7aea1b4..24fe206 100644
--- a/util/romcc/romcc.c
+++ b/util/romcc/romcc.c
@@ -1428,6 +1428,10 @@
 {
 	struct block *block;
 	struct triple *ret;
+	/* If I am an OP_PIECE jump to the real instruction */
+	if (base->op == OP_PIECE) {
+		base = MISC(base, 0);
+	}
 	block = block_of_triple(state, base);
 	ret = build_triple(state, op, type, left, right, 
 		base->filename, base->line, base->col);
@@ -1447,6 +1451,17 @@
 {
 	struct block *block;
 	struct triple *ret;
+	int zlhs;
+	/* If I am an OP_PIECE jump to the real instruction */
+	if (base->op == OP_PIECE) {
+		base = MISC(base, 0);
+	}
+	/* If I have a left hand side skip over it */
+	zlhs = TRIPLE_LHS(base->sizes);
+	if (zlhs && (base->op != OP_WRITE) && (base->op != OP_STORE)) {
+		base = LHS(base, zlhs - 1);
+	}
+
 	block = block_of_triple(state, base);
 	ret = build_triple(state, op, type, left, right, 
 		base->filename, base->line, base->col);
@@ -1491,7 +1506,7 @@
 			fprintf(fp, " %-10p", ins->param[i]);
 		}
 		for(; i < 2; i++) {
-			printf("           ");
+			fprintf(fp, "           ");
 		}
 		fprintf(fp, " @ %s:%d.%d\n", 
 			ins->filename, ins->line, ins->col);
@@ -12248,6 +12263,7 @@
 	struct triple *ins;
 	struct triple_reg_set *live;
 	size_t count;
+	int constraints;
 };
 static void least_conflict(struct compile_state *state,
 	struct reg_block *blocks, struct triple_reg_set *live,
@@ -12257,19 +12273,13 @@
 	struct live_range_edge *edge;
 	struct triple_reg_set *set;
 	size_t count;
-
-#if 0
-#define HI() fprintf(stderr, "%-10p(%-15s) %d\n", ins, tops(ins->op), __LINE__)
-#else
-#define HI()
-#endif
+	int constraints;
 
 #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)) {
-HI();
 		return;
 	}
 
@@ -12280,22 +12290,25 @@
 	for(set = live; set; set = set->next) {
 		struct live_range *lr;
 		lr = conflict->rstate->lrd[set->member->id].lr;
+		/* Ignore it if there cannot be an edge between these two nodes */
+		if (!arch_regcm_intersect(conflict->ref_range->classes, lr->classes)) {
+			continue;
+		}
 		for(edge = conflict->ref_range->edges; edge; edge = edge->next) {
 			if (edge->node == lr) {
 				break;
 			}
 		}
 		if (!edge && (lr != conflict->ref_range)) {
-HI();
 			return;
 		}
 		count++;
 	}
 	if (count <= 1) {
-HI();
 		return;
 	}
 
+#if 0
 	/* See if there is an uncolored member in this subset. 
 	 */
 	 for(set = live; set; set = set->next) {
@@ -12306,11 +12319,79 @@
 		}
 	}
 	if (!set && (conflict->ref_range != REG_UNSET)) {
-HI();
+		return;
+	}
+#endif
+
+	/* See if any of the live registers are constrained,
+	 * if not it won't be productive to pick this as
+	 * a conflict instruction.
+	 */
+	constraints = 0;
+	for(set = live; set; set = set->next) {
+		struct triple_set *uset;
+		struct reg_info info;
+		unsigned classes;
+		unsigned cur_size, size;
+		/* Skip this instruction */
+		if (set->member == ins) {
+			continue;
+		}
+		/* Find how many registers this value can potentially 
+		 * be assigned to.
+		 */
+		classes = arch_type_to_regcm(state, set->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, set->member, 0);
+		
+		/* If the value does not live in a register it
+		 * isn't constrained.
+		 */
+		if (info.reg == REG_UNNEEDED) {
+			continue;
+		}
+		
+		if ((info.reg == REG_UNSET) || (info.reg >= MAX_REGISTERS)) {
+			cur_size = regc_max_size(state, info.regcm);
+		} else {
+			cur_size = 1;
+		}
+
+		/* If there is no difference between potential and
+		 * actual register count there is not a constraint
+		 */
+		if (cur_size >= size) {
+			continue;
+		}
+		
+		/* If this live_range feeds into conflict->inds
+		 * it isn't a constraint we can relieve.
+		 */
+		for(uset = set->member->use; uset; uset = uset->next) {
+			if (uset->member == ins) {
+				break;
+			}
+		}
+		if (uset) {
+			continue;
+		}
+		constraints = 1;
+		break;
+	}
+	/* Don't drop canidates with constraints */
+	if (conflict->constraints && !constraints) {
 		return;
 	}
 
 
+#if 0
+	fprintf(stderr, "conflict ins? %p %s count: %d constraints: %d\n",
+		ins, tops(ins->op), count, constraints);
+#endif
 	/* 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.
@@ -12322,6 +12403,7 @@
 		/* Remember the canidate instruction */
 		conflict->ins = ins;
 		conflict->count = count;
+		conflict->constraints = constraints;
 		/* Free the old collection of live registers */
 		for(set = conflict->live; set; set = next) {
 			next = set->next;
@@ -12353,7 +12435,6 @@
 			;
 		}
 	}
-HI();
 	return;
 }
 
@@ -12362,12 +12443,6 @@
 	struct least_conflict *conflict)
 {
 
-#if 0
-	static void verify_blocks(struct compile_state *stae);
-	verify_blocks(state);
-	print_blocks(state, stderr);
-	print_dominators(state, stderr);
-#endif
 	/* 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.
@@ -12387,37 +12462,25 @@
 	 *    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;
+	conflict->rstate      = rstate;
+	conflict->ref_range   = ref_range;
+	conflict->ins         = 0;
+	conflict->live        = 0;
+	conflict->count       = 0;
+	conflict->constraints = 0;
 	walk_variable_lifetimes(state, rstate->blocks, least_conflict, conflict);
 
 	if (!conflict->ins) {
-		struct live_range_edge *edge;
-		struct live_range_def *lrd;
-		fprintf(stderr, "edges:\n");
-		for(edge = ref_range->edges; edge; edge = edge->next) {
-			lrd = edge->node->defs;
-			do {
-				fprintf(stderr, " %-10p(%s)", lrd->def, tops(lrd->def->op));
-				lrd = lrd->next;
-			} while(lrd != edge->node->defs);
-			fprintf(stderr, "|\n");
-		}
-		fprintf(stderr, "range:\n");
-		lrd = ref_range->defs;
-		do {
-			fprintf(stderr, " %-10p(%s)", lrd->def, tops(lrd->def->op));
-			lrd = lrd->next;
-		} while(lrd != ref_range->defs);
-		fprintf(stderr,"\n");
 		internal_error(state, ref_range->defs->def, "No conflict ins?");
 	}
 	if (!conflict->live) {
 		internal_error(state, ref_range->defs->def, "No conflict live?");
 	}
+#if 0
+	fprintf(stderr, "conflict ins: %p %s count: %d constraints: %d\n", 
+		conflict->ins, tops(conflict->ins->op),
+		conflict->count, conflict->constraints);
+#endif
 	return;
 }
 
@@ -12452,6 +12515,13 @@
 		 * be assigned to.
 		 */
 		info = arch_reg_lhs(state, cset->member, 0);
+
+		/* If the register doesn't need a register 
+		 * splitting it can't help.
+		 */
+		if (info.reg == REG_UNNEEDED) {
+			continue;
+		}
 #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);
@@ -12497,6 +12567,10 @@
 {
 	struct triple *new;
 
+#if 0
+	fprintf(stderr, "split_ranges %d %s %p\n", 
+		rstate->passes, tops(range->defs->def->op), range->defs->def);
+#endif
 	if ((range->color == REG_UNNEEDED) ||
 		(rstate->passes >= rstate->max_passes)) {
 		return 0;
@@ -12506,6 +12580,9 @@
 	if (arch_select_free_register(state, used, range->classes) == REG_UNSET) {
 		struct least_conflict conflict;
 
+#if 0
+	fprintf(stderr, "find_range_conflict\n");
+#endif
 		/* Find where in the set of registers the conflict
 		 * actually occurs.
 		 */
@@ -12528,6 +12605,11 @@
 		 *
 		 */
 #warning "WISHLIST implement live range splitting..."
+#if 0
+			print_blocks(state, stderr);
+			print_dominators(state, stderr);
+
+#endif
 			return 0;
 		}
 	}
@@ -12536,7 +12618,13 @@
 		new->id = rstate->defs;
 		rstate->defs++;
 #if 0
-		fprintf(stderr, "new: %p\n", new);
+		fprintf(stderr, "new: %p old: %s %p\n", 
+			new, tops(RHS(new, 0)->op), RHS(new, 0));
+#endif
+#if 0
+		print_blocks(state, stderr);
+		print_dominators(state, stderr);
+
 #endif
 		return 1;
 	}
@@ -12717,17 +12805,29 @@
 			arch_select_free_register(state, used, range->classes);
 	}
 	if (range->color == REG_UNSET) {
+		struct live_range_def *lrd;
 		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->defs->def, "reg %s", 
+			warning(state, edge->node->defs->def, "edge reg %s",
 				arch_reg_str(edge->node->color));
+			lrd = edge->node->defs;
+			do {
+				warning(state, lrd->def, " %s",
+					tops(lrd->def->op));
+				lrd = lrd->next;
+			} while(lrd != edge->node->defs);
 		}
+		warning(state, range->defs->def, "range: ");
+		lrd = range->defs;
+		do {
+			warning(state, lrd->def, " %s",
+				tops(lrd->def->op));
+			lrd = lrd->next;
+		} while(lrd != range->defs);
+			
 		warning(state, range->defs->def, "classes: %x",
 			range->classes);
 		for(i = 0; i < MAX_REGISTERS; i++) {
diff --git a/util/romcc/tests/simple_test33.c b/util/romcc/tests/simple_test33.c
new file mode 100644
index 0000000..4caaa3a
--- /dev/null
+++ b/util/romcc/tests/simple_test33.c
@@ -0,0 +1,41 @@
+static void main(void)
+{
+	unsigned long loops0, loops1, loops2;
+	unsigned long accum;
+
+	accum = 0;
+
+	loops0 = 10;
+	do {
+		unsigned short val;
+		val = __builtin_inw(0x10e0);
+		if (((val & 0x08) == 0)  || (val == 1)) {
+			break;
+		}
+	} while(--loops0);
+	if (loops0 < 0) return;
+	accum += loops0;
+
+
+	loops1 = 20;
+	do {
+		unsigned short val;
+		val = __builtin_inw(0x10e0);
+		if (((val & 0x08) == 0)  || (val == 1)) {
+			break;
+		}
+	} while(--loops1);
+
+	loops2 = 30;
+	do {
+		unsigned short val;
+		val = __builtin_inw(0x10e0);
+		if (((val & 0x08) == 0)  || (val == 1)) {
+			break;
+		}
+	} while(--loops2);
+
+	accum += loops1 + loops0;
+}
+
+