summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/romcc/Makefile41
-rw-r--r--util/romcc/do_tests.sh96
-rw-r--r--util/romcc/results/linux_test10.out1
-rw-r--r--util/romcc/results/linux_test11.out1
-rw-r--r--util/romcc/results/linux_test12.out11
-rw-r--r--util/romcc/results/linux_test13.out14
-rw-r--r--util/romcc/results/linux_test8.out1
-rw-r--r--util/romcc/results/linux_test9.out134
-rw-r--r--util/romcc/romcc.c9757
-rw-r--r--util/romcc/tests.sh67
-rw-r--r--util/romcc/tests/fail_test10.c19
-rw-r--r--util/romcc/tests/fail_test11.c21
-rw-r--r--util/romcc/tests/fail_test9.c9
-rw-r--r--util/romcc/tests/hello_world1.c128
-rw-r--r--util/romcc/tests/include/linux_console.h136
-rw-r--r--util/romcc/tests/include/linux_syscall.h7
-rw-r--r--util/romcc/tests/include/linuxi386_syscall.h299
-rw-r--r--util/romcc/tests/ldscript.ld1
-rw-r--r--util/romcc/tests/linux_test10.c57
-rw-r--r--util/romcc/tests/linux_test11.c11
-rw-r--r--util/romcc/tests/linux_test12.c70
-rw-r--r--util/romcc/tests/linux_test13.c47
-rw-r--r--util/romcc/tests/linux_test5.c2
-rw-r--r--util/romcc/tests/linux_test9.c13
-rw-r--r--util/romcc/tests/raminit_test1.c1292
-rw-r--r--util/romcc/tests/raminit_test7.c2805
-rw-r--r--util/romcc/tests/simple_test1.c252
-rw-r--r--util/romcc/tests/simple_test60.c2
-rw-r--r--util/romcc/tests/simple_test71.c6
-rw-r--r--util/romcc/tests/simple_test74.c88
-rw-r--r--util/romcc/tests/simple_test75.c21
-rw-r--r--util/romcc/tests/simple_test76.c69
-rw-r--r--util/romcc/tests/simple_test77.c5
-rw-r--r--util/romcc/tests/simple_test78.c7
-rw-r--r--util/romcc/tests/simple_test79.c5
-rw-r--r--util/romcc/tests/simple_test80.c13
-rw-r--r--util/romcc/tests/simple_test81.c8
-rw-r--r--util/romcc/tests/simple_test82.c17
-rw-r--r--util/romcc/tests/simple_test83.c16
-rw-r--r--util/romcc/tests/simple_test84.c28
-rw-r--r--util/romcc/tests/simple_test85.c51
-rw-r--r--util/romcc/tests/simple_test86.c5
42 files changed, 13439 insertions, 2194 deletions
diff --git a/util/romcc/Makefile b/util/romcc/Makefile
index 75fb56c01f..c06777d7df 100644
--- a/util/romcc/Makefile
+++ b/util/romcc/Makefile
@@ -1,11 +1,8 @@
-VERSION:=0.38
-RELEASE_DATE:=18 December 2003
-PACKAGE:=romcc
# Move the configuration defines to makefile.conf
CC=gcc
-CPPFLAGS=-DVERSION='"$(VERSION)"' -DRELEASE_DATE='"$(RELEASE_DATE)"'
+CPPFLAGS=
CFLAGS= -g -Wall $(CPPFLAGS)
CPROF_FLAGS=-pg -fprofile-arcs
@@ -26,11 +23,16 @@ LINUX_TESTS=\
linux_test6.c \
linux_test7.c \
linux_test8.c \
+ linux_test9.c \
+ linux_test10.c \
+ linux_test11.c \
+ linux_test12.c \
+ linux_test13.c \
TESTS=\
- hello_world.c \
+ hello_world1.c \
hello_world2.c \
- simple_test.c \
+ simple_test1.c \
simple_test2.c \
simple_test3.c \
simple_test4.c \
@@ -91,10 +93,24 @@ TESTS=\
simple_test67.c \
simple_test68.c \
simple_test69.c \
+ simple_test70.c \
simple_test71.c \
simple_test72.c \
simple_test73.c \
- raminit_test.c \
+ simple_test74.c \
+ simple_test75.c \
+ simple_test76.c \
+ simple_test77.c \
+ simple_test78.c \
+ simple_test79.c \
+ simple_test80.c \
+ simple_test81.c \
+ simple_test82.c \
+ simple_test83.c \
+ simple_test84.c \
+ simple_test85.c \
+ simple_test86.c \
+ raminit_test1.c \
raminit_test2.c \
raminit_test3.c \
raminit_test4.c \
@@ -111,6 +127,9 @@ FAIL_TESTS = \
fail_test6.c \
fail_test7.c \
fail_test8.c \
+ fail_test9.c \
+ fail_test10.c \
+ fail_test11.c \
TEST_SRCS:=$(patsubst %, tests/%, $(TESTS))
TEST_ASM:=$(patsubst %.c, tests/%.S, $(TESTS))
@@ -128,7 +147,8 @@ TEST_ASM_O2_mmmx_msse:=$(patsubst %.c, tests/%.S-O2-mmmx-msse, $(TESTS))
TEST_ASM_O2_mmmx_call :=$(patsubst %.c, tests/%.S-O2-mmmx-call, $(TESTS))
TEST_ASM_O2_mmmx_msse_call:=$(patsubst %.c, tests/%.S-O2-mmmx-msse-call, $(TESTS))
TEST_ASM_ALL:= $(TEST_ASM) $(TEST_ASM_O) $(TEST_ASM_O2) $(TEST_ASM_mmmx) $(TEST_ASM_msse) $(TEST_ASM_mmmx_msse) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse) $(TEST_ASM_O2_mmmx_call) $(TEST_ASM_O2_mmmx_msse_call)
-TEST_ASM_MOST:= $(TEST_ASM_O) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse) $(TEST_ASM_O2_mmmx_call) $(TEST_ASM_O2_mmmx_msse_call)
+TEST_ASM_MOST:= $(TEST_ASM_O) $(TEST_ASM_O_mmmx) $(TEST_ASM_O_msse) $(TEST_ASM_O_mmmx_msse) $(TEST_ASM_O2) $(TEST_ASM_O2_mmmx) $(TEST_ASM_O2_msse) $(TEST_ASM_O2_mmmx_msse)
+# $(TEST_ASM_O2_mmmx_call) $(TEST_ASM_O2_mmmx_msse_call)
TEST_OBJ:=$(patsubst %.c, tests/%.o, $(TESTS))
TEST_ELF:=$(patsubst %.c, tests/%.elf, $(TESTS))
LINUX_ELF:=$(patsubst %.c, tests/%.elf, $(LINUX_TESTS))
@@ -138,7 +158,7 @@ FAIL_SRCS:=$(patsubst %, tests/%, $(FAIL_TESTS))
FAIL_OUT:=$(patsubst %.c, tests/%.out, $(FAIL_TESTS))
-ROMCC_OPTS=-fmax-allocation-passes=8 -fdebug-live-range-conflicts
+ROMCC_OPTS=-fmax-allocation-passes=8 -fdebug-live-range-conflicts -Itests/include
$(TEST_ASM): %.S: %.c romcc
export ALLOC_CHECK_=2; ./romcc $(ROMCC_OPTS) -o $@ $< > $*.debug
@@ -189,6 +209,8 @@ $(TEST_ASM_O2_mmmx_msse_call): %.S-O2-mmmx-msse-call: %.c romcc
$(FAIL_OUT): %.out: %.c romcc
export ALLOC_CHECK_=2; if ./romcc $(ROMCC_OPTS) -O2 -o $*.S $< > $*.debug 2> $@ ; then exit 1 ; else exit 0 ; fi
+#$(TEST_OBJ): %.o: %.S-O2-mmmx-call
+
$(TEST_OBJ): %.o: %.S-O2-mmmx
as $< -o $@
@@ -205,6 +227,7 @@ run_linux: $(LINUX_OUT)
echo:
echo "TEST_SRCS=$(TEST_SRCS)"
echo "TEST_ASM=$(TEST_ASM)"
+ echo "TEST_ASM=$(TEST_ASM_MOST)"
echo "TEST_OBJ=$(TEST_OBJ)"
echo "TEST_ELF=$(TEST_ELF)"
echo ""
diff --git a/util/romcc/do_tests.sh b/util/romcc/do_tests.sh
new file mode 100644
index 0000000000..fdbe2a6189
--- /dev/null
+++ b/util/romcc/do_tests.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+type="simple"
+if [ -n "$1" ] ; then
+ type=$1
+fi
+if [ "$type" = "simple" ] ; then
+LIST="18 57 21 79 77 40 62 52 65 78 63 81 80 64 12 8 9 7 53 58 37 35 48 11 75 51 49 41 71 23 70 16 13 24 31 55 19 69 67 66 17 28 68 61 32 33 43 60 45 47 36 10 46 15 3 29 50 56 76 34 74 25 26 27 20 1 14 73 5 4"
+LIST="82 83 $LIST"
+BASE="simple_test"
+#REG_SKIP="34 73 5 33 45 47 25 27 26 20 "
+#SKIP="$REG_SKIP"
+EXPECTED_BAD="34 73 5 4"
+fi
+if [ "$type" = "linux" ] ; then
+LIST="1 2 3 4 5 6 7 8 9 10 11 12"
+BASE="linux_test"
+#SKIP="5"
+EXPECTED_BAD=""
+fi
+if [ "$type" = "raminit" ] ; then
+LIST="1 2 3 4 5 6"
+BASE="raminit_test"
+#SKIP="6"
+EXPECTED_BAD=""
+fi
+if [ "$type" = "hello" ] ; then
+LIST="1 2"
+BASE="hello_world"
+EXPECTED_BAD=""
+fi
+
+
+SKIPPED=""
+GOOD=""
+BAD=""
+OLD_BAD=""
+NEW_BAD=""
+NEW_GOOD=""
+for i in $LIST ; do
+ DO_SKIP=""
+ for j in $SKIP ; do
+ if [ "$j" = "$i" ] ; then
+ DO_SKIP="yes"
+ break;
+ fi
+ done
+ if [ ! -z "$DO_SKIP" ] ; then
+ SKIPPED="$SKIPPED$i "
+ continue;
+ fi
+ PROBLEM=""
+ for j in $EXPECTED_BAD ; do
+ if [ "$j" = "$i" ] ; then
+ PROBLEM=":("
+ break;
+ fi
+ done
+ echo -e -n "$i $PROBLEM\t"
+ if ./tests.sh $BASE $i > /dev/null 2> /dev/null ; then
+ echo OK
+ if [ ! -z "$PROBLEM" ] ; then
+ NEW_GOOD="$NEW_GOOD$i "
+ fi
+ GOOD="$GOOD$i "
+ else
+ echo -n "FAILED: "
+ tail -n 1 tests/$BASE$i.debug2 | tr -d '\r\n'
+ echo
+ if [ -z "$PROBLEM" ] ; then
+ NEW_BAD="$NEW_BAD$i "
+ else
+ OLD_BAD="$OLD_BAD$i "
+ fi
+ BAD="$BAD$i "
+ fi
+done
+echo -e "SKIPPED\t\t$SKIPPED"
+echo -e "FAILED\t\t$BAD"
+if [ ! -z "$NEW_BAD" ]; then
+ echo -e "NEW FAILED\t$NEW_BAD"
+fi
+echo -e "OK\t\t$GOOD"
+if [ ! -z "$NEW_GOOD" ]; then
+ echo -e "NEW OK\t\t$NEW_GOOD"
+fi
+
+for i in $NEW_BAD ; do
+ printf "%2d: " $i
+ tail -n 1 tests/$BASE$i.debug2 | tr -d '\n\r'
+ echo
+done
+echo "-----"
+for i in $OLD_BAD ; do
+ printf "%2d: " $i
+ tail -n 1 tests/$BASE$i.debug2
+done
diff --git a/util/romcc/results/linux_test10.out b/util/romcc/results/linux_test10.out
new file mode 100644
index 0000000000..0e830706d6
--- /dev/null
+++ b/util/romcc/results/linux_test10.out
@@ -0,0 +1 @@
+ a: 00000001 b: 00000002 c: ffffffff d: 00000007
diff --git a/util/romcc/results/linux_test11.out b/util/romcc/results/linux_test11.out
new file mode 100644
index 0000000000..536e35fcfb
--- /dev/null
+++ b/util/romcc/results/linux_test11.out
@@ -0,0 +1 @@
+ffffffff
diff --git a/util/romcc/results/linux_test12.out b/util/romcc/results/linux_test12.out
new file mode 100644
index 0000000000..b78dcd9c42
--- /dev/null
+++ b/util/romcc/results/linux_test12.out
@@ -0,0 +1,11 @@
+hah?
+Hi!! There
+This should be shown as a string... "enclosed in quotes"
+This is a quote" see
+135 There
+00000003
+x ## y
+romcc: 00.3b
+linux_test12.c:test:0000003c
+Compiled at: Apr 12 2004 12:06:09
+Compile time: 12:06:09
diff --git a/util/romcc/results/linux_test13.out b/util/romcc/results/linux_test13.out
new file mode 100644
index 0000000000..8faa643109
--- /dev/null
+++ b/util/romcc/results/linux_test13.out
@@ -0,0 +1,14 @@
+A
+1
+2
+3
+4
+2
+3
+4
+2
+4
+2
+4
+5
+B
diff --git a/util/romcc/results/linux_test8.out b/util/romcc/results/linux_test8.out
new file mode 100644
index 0000000000..ec2c310672
--- /dev/null
+++ b/util/romcc/results/linux_test8.out
@@ -0,0 +1 @@
+clocks: 00000003
diff --git a/util/romcc/results/linux_test9.out b/util/romcc/results/linux_test9.out
new file mode 100644
index 0000000000..3e86ef9b31
--- /dev/null
+++ b/util/romcc/results/linux_test9.out
@@ -0,0 +1,134 @@
+i: 0000007f
+i: 00000080
+i: 00000081
+i: 00000082
+i: 00000083
+i: 00000084
+i: 00000085
+i: 00000086
+i: 00000087
+i: 00000088
+i: 00000089
+i: 0000008a
+i: 0000008b
+i: 0000008c
+i: 0000008d
+i: 0000008e
+i: 0000008f
+i: 00000090
+i: 00000091
+i: 00000092
+i: 00000093
+i: 00000094
+i: 00000095
+i: 00000096
+i: 00000097
+i: 00000098
+i: 00000099
+i: 0000009a
+i: 0000009b
+i: 0000009c
+i: 0000009d
+i: 0000009e
+i: 0000009f
+i: 000000a0
+i: 000000a1
+i: 000000a2
+i: 000000a3
+i: 000000a4
+i: 000000a5
+i: 000000a6
+i: 000000a7
+i: 000000a8
+i: 000000a9
+i: 000000aa
+i: 000000ab
+i: 000000ac
+i: 000000ad
+i: 000000ae
+i: 000000af
+i: 000000b0
+i: 000000b1
+i: 000000b2
+i: 000000b3
+i: 000000b4
+i: 000000b5
+i: 000000b6
+i: 000000b7
+i: 000000b8
+i: 000000b9
+i: 000000ba
+i: 000000bb
+i: 000000bc
+i: 000000bd
+i: 000000be
+i: 000000bf
+i: 000000c0
+i: 000000c1
+i: 000000c2
+i: 000000c3
+i: 000000c4
+i: 000000c5
+i: 000000c6
+i: 000000c7
+i: 000000c8
+i: 000000c9
+i: 000000ca
+i: 000000cb
+i: 000000cc
+i: 000000cd
+i: 000000ce
+i: 000000cf
+i: 000000d0
+i: 000000d1
+i: 000000d2
+i: 000000d3
+i: 000000d4
+i: 000000d5
+i: 000000d6
+i: 000000d7
+i: 000000d8
+i: 000000d9
+i: 000000da
+i: 000000db
+i: 000000dc
+i: 000000dd
+i: 000000de
+i: 000000df
+i: 000000e0
+i: 000000e1
+i: 000000e2
+i: 000000e3
+i: 000000e4
+i: 000000e5
+i: 000000e6
+i: 000000e7
+i: 000000e8
+i: 000000e9
+i: 000000ea
+i: 000000eb
+i: 000000ec
+i: 000000ed
+i: 000000ee
+i: 000000ef
+i: 000000f0
+i: 000000f1
+i: 000000f2
+i: 000000f3
+i: 000000f4
+i: 000000f5
+i: 000000f6
+i: 000000f7
+i: 000000f8
+i: 000000f9
+i: 000000fa
+i: 000000fb
+i: 000000fc
+i: 000000fd
+i: 000000fe
+i: 000000ff
+i: 00000000
+i: 00000001
+i: 00000002
+i: 00000003
+i: 00000004
diff --git a/util/romcc/romcc.c b/util/romcc/romcc.c
index ff7aee669b..c487566d0a 100644
--- a/util/romcc/romcc.c
+++ b/util/romcc/romcc.c
@@ -1,3 +1,12 @@
+#undef VERSION_MAJOR
+#undef VERSION_MINOR
+#undef RELEASE_DATE
+#undef VERSION
+#define VERSION_MAJOR "0"
+#define VERSION_MINOR "63"
+#define RELEASE_DATE "28 May 2004"
+#define VERSION VERSION_MAJOR "." VERSION_MINOR
+
#include <stdarg.h>
#include <errno.h>
#include <stdint.h>
@@ -10,16 +19,36 @@
#include <stdio.h>
#include <string.h>
#include <limits.h>
+#include <locale.h>
+#include <time.h>
+#define MAX_CWD_SIZE 4096
#define MAX_ALLOCATION_PASSES 100
#define DEBUG_CONSISTENCY 1
#define DEBUG_SDP_BLOCKS 0
#define DEBUG_TRIPLE_COLOR 0
-#warning "FIXME boundary cases with small types in larger registers"
+#define DEBUG_DISPLAY_USES 1
+#define DEBUG_DISPLAY_TYPES 1
+#define DEBUG_REPLACE_CLOSURE_TYPE_HIRES 0
+#define DEBUG_DECOMPOSE_PRINT_TUPLES 0
+#define DEBUG_DECOMPOSE_HIRES 0
+#define DEBUG_INITIALIZER 0
+#define DEBUG_UPDATE_CLOSURE_TYPE 0
+#define DEBUG_LOCAL_TRIPLE 0
+#define DEBUG_BASIC_BLOCKS_VERBOSE 0
+#define DEBUG_CPS_RENAME_VARIABLES_HIRES 0
+#define DEBUG_SIMPLIFY_HIRES 0
+#define DEBUG_SHRINKING 0
+#define DEBUG_COALESCE_HITCHES 0
+#define DEBUG_CODE_ELIMINATION 0
+
+#define DEBUG_EXPLICIT_CLOSURES 0
+
#warning "FIXME give clear error messages about unused variables"
#warning "FIXME properly handle multi dimensional arrays"
+#warning "FIXME handle multiple register sizes"
/* Control flow graph of a loop without goto.
*
@@ -100,7 +129,6 @@ static void die(char *fmt, ...)
exit(1);
}
-#define MALLOC_STRONG_DEBUG
static void *xmalloc(size_t size, const char *name)
{
void *buf;
@@ -120,6 +148,17 @@ static void *xcmalloc(size_t size, const char *name)
return buf;
}
+static void *xrealloc(void *ptr, size_t size, const char *name)
+{
+ void *buf;
+ buf = realloc(ptr, size);
+ if (!buf) {
+ die("Cannot realloc %ld bytes to hold %s: %s\n",
+ size + 0UL, name, strerror(errno));
+ }
+ return buf;
+}
+
static void xfree(const void *ptr)
{
free((void *)ptr);
@@ -139,26 +178,37 @@ static char *xstrdup(const char *str)
static void xchdir(const char *path)
{
if (chdir(path) != 0) {
- die("chdir to %s failed: %s\n",
+ die("chdir to `%s' failed: %s\n",
path, strerror(errno));
}
}
static int exists(const char *dirname, const char *filename)
{
- int does_exist = 1;
- xchdir(dirname);
- if (access(filename, O_RDONLY) < 0) {
+ char cwd[MAX_CWD_SIZE];
+ int does_exist;
+
+ if (getcwd(cwd, sizeof(cwd)) == 0) {
+ die("cwd buffer to small");
+ }
+
+ does_exist = 1;
+ if (chdir(dirname) != 0) {
+ does_exist = 0;
+ }
+ if (does_exist && (access(filename, O_RDONLY) < 0)) {
if ((errno != EACCES) && (errno != EROFS)) {
does_exist = 0;
}
}
+ xchdir(cwd);
return does_exist;
}
static char *slurp_file(const char *dirname, const char *filename, off_t *r_size)
{
+ char cwd[MAX_CWD_SIZE];
int fd;
char *buf;
off_t size, progress;
@@ -169,8 +219,12 @@ static char *slurp_file(const char *dirname, const char *filename, off_t *r_size
*r_size = 0;
return 0;
}
+ if (getcwd(cwd, sizeof(cwd)) == 0) {
+ die("cwd buffer to small");
+ }
xchdir(dirname);
fd = open(filename, O_RDONLY);
+ xchdir(cwd);
if (fd < 0) {
die("Cannot open '%s' : %s\n",
filename, strerror(errno));
@@ -231,15 +285,54 @@ typedef uint32_t ulong_t;
#define LONG_T_MAX 2147483647
#define ULONG_T_MAX 4294967295U
+#define SIZEOF_I8 8
+#define SIZEOF_I16 16
+#define SIZEOF_I32 32
+#define SIZEOF_I64 64
+
+#define SIZEOF_CHAR 8
+#define SIZEOF_SHORT 16
+#define SIZEOF_INT 32
+#define SIZEOF_LONG (sizeof(long_t)*SIZEOF_CHAR)
+
+
+#define ALIGNOF_CHAR 8
+#define ALIGNOF_SHORT 16
+#define ALIGNOF_INT 32
+#define ALIGNOF_LONG (sizeof(long_t)*SIZEOF_CHAR)
+
+#define REG_SIZEOF_REG 32
+#define REG_SIZEOF_CHAR REG_SIZEOF_REG
+#define REG_SIZEOF_SHORT REG_SIZEOF_REG
+#define REG_SIZEOF_INT REG_SIZEOF_REG
+#define REG_SIZEOF_LONG REG_SIZEOF_REG
+
+#define REG_ALIGNOF_REG REG_SIZEOF_REG
+#define REG_ALIGNOF_CHAR REG_SIZEOF_REG
+#define REG_ALIGNOF_SHORT REG_SIZEOF_REG
+#define REG_ALIGNOF_INT REG_SIZEOF_REG
+#define REG_ALIGNOF_LONG REG_SIZEOF_REG
+
+/* Additional definitions for clarity.
+ * I currently assume a long is the largest native
+ * machine word and that a pointer fits into it.
+ */
+#define SIZEOF_WORD SIZEOF_LONG
+#define SIZEOF_POINTER SIZEOF_LONG
+#define ALIGNOF_WORD ALIGNOF_LONG
+#define ALIGNOF_POINTER ALIGNOF_LONG
+#define REG_SIZEOF_POINTER REG_SIZEOF_LONG
+#define REG_ALIGNOF_POINTER REG_ALIGNOF_LONG
+
struct file_state {
struct file_state *prev;
const char *basename;
char *dirname;
char *buf;
off_t size;
- char *pos;
+ const char *pos;
int line;
- char *line_start;
+ const char *line_start;
int report_line;
const char *report_name;
const char *report_dir;
@@ -252,6 +345,7 @@ struct token {
union {
ulong_t integer;
const char *str;
+ int notmacro;
} val;
};
@@ -325,10 +419,32 @@ struct token {
* RHS(1) holds the value to store.
*/
-#define OP_NOOP 34
+#define OP_UEXTRACT 34
+/* OP_UEXTRACT extracts an unsigned bitfield from a pseudo register
+ * RHS(0) holds the psuedo register to extract from
+ * ->type holds the size of the bitfield.
+ * ->u.bitfield.size holds the size of the bitfield.
+ * ->u.bitfield.offset holds the offset to extract from
+ */
+#define OP_SEXTRACT 35
+/* OP_SEXTRACT extracts a signed bitfield from a pseudo register
+ * RHS(0) holds the psuedo register to extract from
+ * ->type holds the size of the bitfield.
+ * ->u.bitfield.size holds the size of the bitfield.
+ * ->u.bitfield.offset holds the offset to extract from
+ */
+#define OP_DEPOSIT 36
+/* OP_DEPOSIT replaces a bitfield with a new value.
+ * RHS(0) holds the value to replace a bitifield in.
+ * RHS(1) holds the replacement value
+ * ->u.bitfield.size holds the size of the bitfield.
+ * ->u.bitfield.offset holds the deposit into
+ */
+
+#define OP_NOOP 37
#define OP_MIN_CONST 50
-#define OP_MAX_CONST 59
+#define OP_MAX_CONST 58
#define IS_CONST_OP(X) (((X) >= OP_MIN_CONST) && ((X) <= OP_MAX_CONST))
#define OP_INTCONST 50
/* For OP_INTCONST ->type holds the type.
@@ -344,11 +460,17 @@ struct token {
* MISC(0) holds the reference to the static variable.
* ->u.cval holds an offset from that value.
*/
+#define OP_UNKNOWNVAL 59
+/* For OP_UNKNOWNAL ->type holds the type.
+ * For some reason we don't know what value this type has.
+ * This allows for variables that have don't have values
+ * assigned yet, or variables whose value we simply do not know.
+ */
#define OP_WRITE 60
/* OP_WRITE moves one pseudo register to another.
- * RHS(0) holds the destination pseudo register, which must be an OP_DECL.
- * RHS(1) holds the psuedo to move.
+ * MISC(0) holds the destination pseudo register, which must be an OP_DECL.
+ * RHS(0) holds the psuedo to move.
*/
#define OP_READ 61
@@ -358,14 +480,18 @@ struct token {
* RHS(0) holds points to the triple to read from.
*/
#define OP_COPY 62
-/* OP_COPY makes a copy of the psedo register or constant in RHS(0).
+/* OP_COPY makes a copy of the pseudo register or constant in RHS(0).
+ */
+#define OP_CONVERT 63
+/* OP_CONVERT makes a copy of the pseudo register or constant in RHS(0).
+ * And then the type is converted appropriately.
*/
-#define OP_PIECE 63
+#define OP_PIECE 64
/* OP_PIECE returns one piece of a instruction that returns a structure.
* MISC(0) is the instruction
* u.cval is the LHS piece of the instruction to return.
*/
-#define OP_ASM 64
+#define OP_ASM 65
/* 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.
@@ -373,20 +499,27 @@ struct token {
* u.blob holds the string of assembly instructions.
*/
-#define OP_DEREF 65
+#define OP_DEREF 66
/* OP_DEREF generates an lvalue from a pointer.
* RHS(0) holds the pointer value.
* OP_DEREF serves as a place holder to indicate all necessary
* checks have been done to indicate a value is an lvalue.
*/
-#define OP_DOT 66
+#define OP_DOT 67
/* OP_DOT references a submember of a structure lvalue.
- * RHS(0) holds the lvalue.
+ * MISC(0) holds the lvalue.
* ->u.field holds the name of the field we want.
*
- * Not seen outside of expressions.
+ * Not seen after structures are flattened.
+ */
+#define OP_INDEX 68
+/* OP_INDEX references a submember of a tuple or array lvalue.
+ * MISC(0) holds the lvalue.
+ * ->u.cval holds the index into the lvalue.
+ *
+ * Not seen after structures are flattened.
*/
-#define OP_VAL 67
+#define OP_VAL 69
/* OP_VAL returns the value of a subexpression of the current expression.
* Useful for operators that have side effects.
* RHS(0) holds the expression.
@@ -395,47 +528,47 @@ struct token {
*
* Not seen outside of expressions.
*/
-#define OP_LAND 68
-/* OP_LAND performs a C logical and between RHS(0) and RHS(1).
- * Not seen outside of expressions.
- */
-#define OP_LOR 69
-/* OP_LOR performs a C logical or between RHS(0) and RHS(1).
- * Not seen outside of expressions.
- */
-#define OP_COND 70
-/* OP_CODE performas a C ? : operation.
- * RHS(0) holds the test.
- * RHS(1) holds the expression to evaluate if the test returns true.
- * RHS(2) holds the expression to evaluate if the test returns false.
- * Not seen outside of expressions.
+
+#define OP_TUPLE 70
+/* OP_TUPLE is an array of triples that are either variable
+ * or values for a structure or an array. It is used as
+ * a place holder when flattening compound types.
+ * The value represented by an OP_TUPLE is held in N registers.
+ * LHS(0..N-1) refer to those registers.
+ * ->use is a list of statements that use the value.
+ *
+ * Although OP_TUPLE always has register sized pieces they are not
+ * used until structures are flattened/decomposed into their register
+ * components.
+ * ???? registers ????
*/
-#define OP_COMMA 71
-/* OP_COMMA performacs a C comma operation.
- * That is RHS(0) is evaluated, then RHS(1)
- * and the value of RHS(1) is returned.
- * Not seen outside of expressions.
+
+#define OP_BITREF 71
+/* OP_BITREF describes a bitfield as an lvalue.
+ * RHS(0) holds the register value.
+ * ->type holds the type of the bitfield.
+ * ->u.bitfield.size holds the size of the bitfield.
+ * ->u.bitfield.offset holds the offset of the bitfield in the register
*/
-#define OP_FCALL 72
+
+#define OP_FCALL 72
/* OP_FCALL performs a procedure call.
* MISC(0) holds a pointer to the OP_LIST of a function
* RHS(x) holds argument x of a function
*
* Currently not seen outside of expressions.
*/
-#define OP_VAL_VEC 74
-/* OP_VAL_VEC is an array of triples that are either variable
- * or values for a structure or an array.
- * RHS(x) holds element x of the vector.
- * triple->type->elements holds the size of the vector.
+#define OP_PROG 73
+/* OP_PROG is an expression that holds a list of statements, or
+ * expressions. The final expression is the value of the expression.
+ * RHS(0) holds the start of the list.
*/
/* statements */
#define OP_LIST 80
/* OP_LIST Holds a list of statements that compose a function, and a result value.
* RHS(0) holds the list of statements.
- * MISC(0) holds the value of the statements.
* A list of all functions is maintained.
*/
@@ -475,7 +608,14 @@ struct token {
#define OP_ADECL 87
/* OP_ADECL is a triple that establishes an lvalue for assignments.
+ * A variable takes N registers to contain.
+ * LHS(0..N-1) refer to an OP_PIECE triple that represents
+ * the Xth register that the variable is stored in.
* ->use is a list of statements that use the variable.
+ *
+ * Although OP_ADECL always has register sized pieces they are not
+ * used until structures are flattened/decomposed into their register
+ * components.
*/
#define OP_SDECL 88
@@ -501,6 +641,46 @@ struct token {
* MISC(0) holds a pointer to the orginal OP_DECL node.
*/
+#if 0
+/* continuation helpers
+ */
+#define OP_CPS_BRANCH 90 /* an unconditional branch */
+/* OP_CPS_BRANCH calls a continuation
+ * RHS(x) holds argument x of the function
+ * TARG(0) holds OP_CPS_START target
+ */
+#define OP_CPS_CBRANCH 91 /* a conditional branch */
+/* OP_CPS_CBRANCH conditionally calls one of two continuations
+ * RHS(0) holds the branch condition
+ * RHS(x + 1) holds argument x of the function
+ * TARG(0) holds the OP_CPS_START to jump to when true
+ * ->next holds the OP_CPS_START to jump to when false
+ */
+#define OP_CPS_CALL 92 /* an uncontional branch that will return */
+/* For OP_CPS_CALL instructions
+ * RHS(x) holds argument x of the function
+ * MISC(0) holds the OP_CPS_RET that returns from the branch
+ * TARG(0) holds the branch target.
+ * ->next holds where the OP_CPS_RET will return to.
+ */
+#define OP_CPS_RET 93
+/* OP_CPS_RET conditionally calls one of two continuations
+ * RHS(0) holds the variable with the return function address
+ * RHS(x + 1) holds argument x of the function
+ * The branch target may be any OP_CPS_START
+ */
+#define OP_CPS_END 94
+/* OP_CPS_END is the triple at the end of the program.
+ * For most practical purposes it is a branch.
+ */
+#define OP_CPS_START 95
+/* OP_CPS_START is a triple at the start of a continuation
+ * The arguments variables takes N registers to contain.
+ * LHS(0..N-1) refer to an OP_PIECE triple that represents
+ * the Xth register that the arguments are stored in.
+ */
+#endif
+
/* Architecture specific instructions */
#define OP_CMP 100
#define OP_TEST 101
@@ -543,15 +723,21 @@ struct token {
struct op_info {
const char *name;
unsigned flags;
-#define PURE 1 /* Triple has no side effects */
-#define IMPURE 2 /* Triple has side effects */
+#define PURE 0x001 /* Triple has no side effects */
+#define IMPURE 0x002 /* Triple has side effects */
#define PURE_BITS(FLAGS) ((FLAGS) & 0x3)
-#define DEF 4 /* Triple is a variable definition */
-#define BLOCK 8 /* Triple stores the current block */
-#define STRUCTURAL 16 /* Triple does not generate a machine instruction */
-#define BRANCH 32 /* Triple is a branch instruction */
-#define CBRANCH 64 /* Triple is a conditional branch instruction */
- unsigned char lhs, rhs, misc, targ;
+#define DEF 0x004 /* Triple is a variable definition */
+#define BLOCK 0x008 /* Triple stores the current block */
+#define STRUCTURAL 0x010 /* Triple does not generate a machine instruction */
+#define BRANCH_BITS(FLAGS) ((FLAGS) & 0xe0 )
+#define UBRANCH 0x020 /* Triple is an unconditional branch instruction */
+#define CBRANCH 0x040 /* Triple is a conditional branch instruction */
+#define RETBRANCH 0x060 /* Triple is a return instruction */
+#define CALLBRANCH 0x080 /* Triple is a call instruction */
+#define ENDBRANCH 0x0a0 /* Triple is an end instruction */
+#define PART 0x100 /* Triple is really part of another triple */
+#define BITFIELD 0x200 /* Triple manipulates a bitfield */
+ signed char lhs, rhs, misc, targ;
};
#define OP(LHS, RHS, MISC, TARG, FLAGS, NAME) { \
@@ -596,44 +782,59 @@ static const struct op_info table_ops[] = {
[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( 0, 2, 0, 0, IMPURE | BLOCK , "store"),
+[OP_LOAD ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "load"),
+[OP_STORE ] = OP( 0, 2, 0, 0, PURE | BLOCK , "store"),
+
+[OP_UEXTRACT ] = OP( 0, 1, 0, 0, PURE | DEF | BITFIELD, "uextract"),
+[OP_SEXTRACT ] = OP( 0, 1, 0, 0, PURE | DEF | BITFIELD, "sextract"),
+[OP_DEPOSIT ] = OP( 0, 2, 0, 0, PURE | DEF | BITFIELD, "deposit"),
[OP_NOOP ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "noop"),
[OP_INTCONST ] = OP( 0, 0, 0, 0, PURE | DEF, "intconst"),
[OP_BLOBCONST ] = OP( 0, 0, 0, 0, PURE , "blobconst"),
[OP_ADDRCONST ] = OP( 0, 0, 1, 0, PURE | DEF, "addrconst"),
+[OP_UNKNOWNVAL ] = OP( 0, 0, 0, 0, PURE | DEF, "unknown"),
-[OP_WRITE ] = OP( 0, 2, 0, 0, PURE | BLOCK, "write"),
+#warning "FIXME is it correct for OP_WRITE to be a def? I currently use it as one..."
+[OP_WRITE ] = OP( 0, 1, 1, 0, PURE | DEF | 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 | STRUCTURAL, "piece"),
-[OP_ASM ] = OP(-1, -1, 0, 0, IMPURE, "asm"),
+[OP_CONVERT ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "convert"),
+[OP_PIECE ] = OP( 0, 0, 1, 0, PURE | DEF | STRUCTURAL | PART, "piece"),
+[OP_ASM ] = OP(-1, -1, 0, 0, PURE, "asm"),
[OP_DEREF ] = OP( 0, 1, 0, 0, 0 | DEF | BLOCK, "deref"),
-[OP_DOT ] = OP( 0, 1, 0, 0, 0 | DEF | BLOCK, "dot"),
+[OP_DOT ] = OP( 0, 0, 1, 0, PURE | DEF | PART, "dot"),
+[OP_INDEX ] = OP( 0, 0, 1, 0, PURE | DEF | PART, "index"),
[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"),
+[OP_TUPLE ] = OP(-1, 0, 0, 0, 0 | PURE | BLOCK | STRUCTURAL, "tuple"),
+[OP_BITREF ] = OP( 0, 1, 0, 0, 0 | DEF | PURE | STRUCTURAL | BITFIELD, "bitref"),
/* Call is special most it can stand in for anything so it depends on context */
-[OP_FCALL ] = OP(-1, -1, 1, 0, 0 | BLOCK, "fcall"),
-/* The sizes of OP_FCALL and OP_VAL_VEC depend upon context */
-[OP_VAL_VEC ] = OP( 0, -1, 0, 0, 0 | BLOCK | STRUCTURAL, "valvec"),
+[OP_FCALL ] = OP( 0, -1, 1, 0, 0 | BLOCK | CALLBRANCH, "fcall"),
+[OP_PROG ] = OP( 0, 1, 0, 0, 0 | IMPURE | BLOCK | STRUCTURAL, "prog"),
+/* The sizes of OP_FCALL depends upon context */
[OP_LIST ] = OP( 0, 1, 1, 0, 0 | DEF | STRUCTURAL, "list"),
-[OP_BRANCH ] = OP( 0, 0, 0, 1, PURE | BLOCK | BRANCH, "branch"),
-[OP_CBRANCH ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "cbranch"),
-[OP_CALL ] = OP( 0, 0, 1, 1, PURE | BLOCK | BRANCH, "call"),
-[OP_RET ] = OP( 0, 1, 0, 0, PURE | BLOCK | BRANCH, "ret"),
+[OP_BRANCH ] = OP( 0, 0, 0, 1, PURE | BLOCK | UBRANCH, "branch"),
+[OP_CBRANCH ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "cbranch"),
+[OP_CALL ] = OP( 0, 0, 1, 1, PURE | BLOCK | CALLBRANCH, "call"),
+[OP_RET ] = OP( 0, 1, 0, 0, PURE | BLOCK | RETBRANCH, "ret"),
[OP_LABEL ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "label"),
[OP_ADECL ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "adecl"),
[OP_SDECL ] = OP( 0, 0, 1, 0, PURE | BLOCK | STRUCTURAL, "sdecl"),
/* The number of RHS elements of OP_PHI depend upon context */
[OP_PHI ] = OP( 0, -1, 1, 0, PURE | DEF | BLOCK, "phi"),
+#if 0
+[OP_CPS_BRANCH ] = OP( 0, -1, 0, 1, PURE | BLOCK | UBRANCH, "cps_branch"),
+[OP_CPS_CBRANCH] = OP( 0, -1, 0, 1, PURE | BLOCK | CBRANCH, "cps_cbranch"),
+[OP_CPS_CALL ] = OP( 0, -1, 1, 1, PURE | BLOCK | CALLBRANCH, "cps_call"),
+[OP_CPS_RET ] = OP( 0, -1, 0, 0, PURE | BLOCK | RETBRANCH, "cps_ret"),
+[OP_CPS_END ] = OP( 0, -1, 0, 0, IMPURE | BLOCK | ENDBRANCH, "cps_end"),
+[OP_CPS_START ] = OP( -1, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "cps_start"),
+#endif
+
[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"),
@@ -646,17 +847,17 @@ static const struct op_info table_ops[] = {
[OP_SET_ULESSEQ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_ulesseq"),
[OP_SET_SMOREEQ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_smoreq"),
[OP_SET_UMOREEQ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "set_umoreq"),
-[OP_JMP ] = OP( 0, 0, 0, 1, PURE | BLOCK | BRANCH, "jmp"),
-[OP_JMP_EQ ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_eq"),
-[OP_JMP_NOTEQ ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_noteq"),
-[OP_JMP_SLESS ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_sless"),
-[OP_JMP_ULESS ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_uless"),
-[OP_JMP_SMORE ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_smore"),
-[OP_JMP_UMORE ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_umore"),
-[OP_JMP_SLESSEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_slesseq"),
-[OP_JMP_ULESSEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_ulesseq"),
-[OP_JMP_SMOREEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_smoreq"),
-[OP_JMP_UMOREEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | BRANCH | CBRANCH, "jmp_umoreq"),
+[OP_JMP ] = OP( 0, 0, 0, 1, PURE | BLOCK | UBRANCH, "jmp"),
+[OP_JMP_EQ ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_eq"),
+[OP_JMP_NOTEQ ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_noteq"),
+[OP_JMP_SLESS ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_sless"),
+[OP_JMP_ULESS ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_uless"),
+[OP_JMP_SMORE ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_smore"),
+[OP_JMP_UMORE ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_umore"),
+[OP_JMP_SLESSEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_slesseq"),
+[OP_JMP_ULESSEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_ulesseq"),
+[OP_JMP_SMOREEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_smoreq"),
+[OP_JMP_UMOREEQ] = OP( 0, 1, 0, 1, PURE | BLOCK | CBRANCH, "jmp_umoreq"),
[OP_INB ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "__inb"),
[OP_INW ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "__inw"),
@@ -693,10 +894,10 @@ struct triple_set {
struct triple *member;
};
-#define MAX_LHS 15
-#define MAX_RHS 250
+#define MAX_LHS 63
+#define MAX_RHS 127
#define MAX_MISC 3
-#define MAX_TARG 3
+#define MAX_TARG 1
struct occurance {
int count;
@@ -706,48 +907,49 @@ struct occurance {
int col;
struct occurance *parent;
};
+struct bitfield {
+ ulong_t size : 8;
+ ulong_t offset : 24;
+};
struct triple {
struct triple *next, *prev;
struct triple_set *use;
struct type *type;
- unsigned char op;
- unsigned char template_id;
- unsigned short sizes;
-#define TRIPLE_LHS(SIZES) (((SIZES) >> 0) & 0x0f)
-#define TRIPLE_RHS(SIZES) (((SIZES) >> 4) & 0xff)
-#define TRIPLE_MISC(SIZES) (((SIZES) >> 12) & 0x03)
-#define TRIPLE_TARG(SIZES) (((SIZES) >> 14) & 0x03)
-#define TRIPLE_SIZE(SIZES) \
- (TRIPLE_LHS(SIZES) + \
- TRIPLE_RHS(SIZES) + \
- TRIPLE_MISC(SIZES) + \
- TRIPLE_TARG(SIZES))
-#define TRIPLE_SIZES(LHS, RHS, MISC, TARG) \
- ((((LHS) & 0x0f) << 0) | \
- (((RHS) & 0xff) << 4) | \
- (((MISC) & 0x03) << 12) | \
- (((TARG) & 0x03) << 14))
-#define TRIPLE_LHS_OFF(SIZES) (0)
-#define TRIPLE_RHS_OFF(SIZES) (TRIPLE_LHS_OFF(SIZES) + TRIPLE_LHS(SIZES))
-#define TRIPLE_MISC_OFF(SIZES) (TRIPLE_RHS_OFF(SIZES) + TRIPLE_RHS(SIZES))
-#define TRIPLE_TARG_OFF(SIZES) (TRIPLE_MISC_OFF(SIZES) + TRIPLE_MISC(SIZES))
-#define LHS(PTR,INDEX) ((PTR)->param[TRIPLE_LHS_OFF((PTR)->sizes) + (INDEX)])
-#define RHS(PTR,INDEX) ((PTR)->param[TRIPLE_RHS_OFF((PTR)->sizes) + (INDEX)])
-#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 int op : 8;
+ unsigned int template_id : 7;
+ unsigned int lhs : 6;
+ unsigned int rhs : 7;
+ unsigned int misc : 2;
+ unsigned int targ : 1;
+#define TRIPLE_SIZE(TRIPLE) \
+ ((TRIPLE)->lhs + (TRIPLE)->rhs + (TRIPLE)->misc + (TRIPLE)->targ)
+#define TRIPLE_LHS_OFF(PTR) (0)
+#define TRIPLE_RHS_OFF(PTR) (TRIPLE_LHS_OFF(PTR) + (PTR)->lhs)
+#define TRIPLE_MISC_OFF(PTR) (TRIPLE_RHS_OFF(PTR) + (PTR)->rhs)
+#define TRIPLE_TARG_OFF(PTR) (TRIPLE_MISC_OFF(PTR) + (PTR)->misc)
+#define LHS(PTR,INDEX) ((PTR)->param[TRIPLE_LHS_OFF(PTR) + (INDEX)])
+#define RHS(PTR,INDEX) ((PTR)->param[TRIPLE_RHS_OFF(PTR) + (INDEX)])
+#define TARG(PTR,INDEX) ((PTR)->param[TRIPLE_TARG_OFF(PTR) + (INDEX)])
+#define MISC(PTR,INDEX) ((PTR)->param[TRIPLE_MISC_OFF(PTR) + (INDEX)])
unsigned id; /* A scratch value and finally the register */
#define TRIPLE_FLAG_FLATTENED (1 << 31)
#define TRIPLE_FLAG_PRE_SPLIT (1 << 30)
#define TRIPLE_FLAG_POST_SPLIT (1 << 29)
#define TRIPLE_FLAG_VOLATILE (1 << 28)
-#define TRIPLE_FLAG_LOCAL (1 << 27)
+#define TRIPLE_FLAG_INLINE (1 << 27) /* ???? */
+#define TRIPLE_FLAG_LOCAL (1 << 26)
+
+#define TRIPLE_FLAG_COPY TRIPLE_FLAG_VOLATILE
struct occurance *occurance;
union {
ulong_t cval;
+ struct bitfield bitfield;
struct block *block;
void *blob;
struct hash_entry *field;
struct asm_info *ainfo;
+ struct triple *func;
+ struct symbol *symbol;
} u;
struct triple *param[2];
};
@@ -794,10 +996,17 @@ struct symbol {
int scope_depth;
};
+struct macro_arg {
+ struct macro_arg *next;
+ struct hash_entry *ident;
+};
struct macro {
struct hash_entry *ident;
char *buf;
int buf_len;
+ int buf_off;
+ struct macro_arg *args;
+ int argc;
};
struct hash_entry {
@@ -819,14 +1028,32 @@ struct compiler_state {
unsigned long flags;
unsigned long debug;
unsigned long max_allocation_passes;
+
+ size_t include_path_count;
+ const char **include_paths;
+
+ size_t define_count;
+ const char **defines;
+
+ size_t undef_count;
+ const char **undefs;
};
struct arch_state {
unsigned long features;
};
+struct basic_blocks {
+ struct triple *func;
+ struct triple *first;
+ struct block *first_block, *last_block;
+ int last_vertex;
+};
+#define MAX_CPP_IF_DEPTH 63
struct compile_state {
struct compiler_state *compiler;
struct arch_state *arch;
FILE *output;
+ FILE *errout;
+ FILE *dbgout;
struct file_state *file;
struct occurance *last_occurance;
const char *function;
@@ -838,16 +1065,28 @@ struct compile_state {
struct hash_entry *i_break;
struct hash_entry *i_default;
struct hash_entry *i_return;
+ /* Additional hash entries for predefined macros */
+ struct hash_entry *i_defined;
+ struct hash_entry *i___VA_ARGS__;
+ struct hash_entry *i___FILE__;
+ struct hash_entry *i___LINE__;
+ /* Additional hash entries for predefined identifiers */
+ struct hash_entry *i___func__;
+ /* Additional hash entries for attributes */
+ struct hash_entry *i_noinline;
+ struct hash_entry *i_always_inline;
int scope_depth;
- int if_depth, if_value;
+ unsigned char if_bytes[(MAX_CPP_IF_DEPTH + CHAR_BIT -1)/CHAR_BIT];
+ int if_depth;
+ int eat_depth, eat_targ;
int macro_line;
struct file_state *macro_file;
struct triple *functions;
struct triple *main_function;
struct triple *first;
struct triple *global_pool;
- struct block *first_block, *last_block;
- int last_vertex;
+ struct basic_blocks bb;
+ int functions_joined;
};
/* visibility global/local */
@@ -879,8 +1118,8 @@ struct compile_state {
#define TYPE_SHIFT 8
#define TYPE_MASK 0x1f00
-#define TYPE_INTEGER(TYPE) ((((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_ULLONG)) || ((TYPE) == TYPE_ENUM))
-#define TYPE_ARITHMETIC(TYPE) ((((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_LDOUBLE)) || ((TYPE) == TYPE_ENUM))
+#define TYPE_INTEGER(TYPE) ((((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_ULLONG)) || ((TYPE) == TYPE_ENUM) || ((TYPE) == TYPE_BITFIELD))
+#define TYPE_ARITHMETIC(TYPE) ((((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_LDOUBLE)) || ((TYPE) == TYPE_ENUM) || ((TYPE) == TYPE_BITFIELD))
#define TYPE_UNSIGNED(TYPE) ((TYPE) & 0x0100)
#define TYPE_SIGNED(TYPE) (!TYPE_UNSIGNED(TYPE))
#define TYPE_MKUNSIGNED(TYPE) (((TYPE) & ~0xF000) | 0x0100)
@@ -911,7 +1150,17 @@ struct compile_state {
*/
#define TYPE_STRUCT 0x1000
+/* For TYPE_STRUCT
+ * type->left holds the link list of TYPE_PRODUCT entries that
+ * make up the structure.
+ * type->elements hold the length of the linked list
+ */
#define TYPE_UNION 0x1100
+/* For TYPE_UNION
+ * type->left holds the link list of TYPE_OVERLAP entries that
+ * make up the union.
+ * type->elements hold the length of the linked list
+ */
#define TYPE_POINTER 0x1200
/* For TYPE_POINTER:
* type->left holds the type pointed to.
@@ -919,7 +1168,8 @@ struct compile_state {
#define TYPE_FUNCTION 0x1300
/* For TYPE_FUNCTION:
* type->left holds the return type.
- * type->right holds the...
+ * type->right holds the type of the arguments
+ * type->elements holds the count of the arguments
*/
#define TYPE_PRODUCT 0x1400
/* TYPE_PRODUCT is a basic building block when defining structures
@@ -934,9 +1184,41 @@ struct compile_state {
#define TYPE_ARRAY 0x1800
/* TYPE_ARRAY is a basic building block when definitng arrays.
* type->left holds the type we are an array of.
- * type-> holds the number of elements.
+ * type->elements holds the number of elements.
+ */
+#define TYPE_TUPLE 0x1900
+/* TYPE_TUPLE is a basic building block when defining
+ * positionally reference type conglomerations. (i.e. closures)
+ * In essence it is a wrapper for TYPE_PRODUCT, like TYPE_STRUCT
+ * except it has no field names.
+ * type->left holds the liked list of TYPE_PRODUCT entries that
+ * make up the closure type.
+ * type->elements hold the number of elements in the closure.
+ */
+#define TYPE_JOIN 0x1a00
+/* TYPE_JOIN is a basic building block when defining
+ * positionally reference type conglomerations. (i.e. closures)
+ * In essence it is a wrapper for TYPE_OVERLAP, like TYPE_UNION
+ * except it has no field names.
+ * type->left holds the liked list of TYPE_OVERLAP entries that
+ * make up the closure type.
+ * type->elements hold the number of elements in the closure.
+ */
+#define TYPE_BITFIELD 0x1b00
+/* TYPE_BITFIED is the type of a bitfield.
+ * type->left holds the type basic type TYPE_BITFIELD is derived from.
+ * type->elements holds the number of bits in the bitfield.
+ */
+#define TYPE_UNKNOWN 0x1c00
+/* TYPE_UNKNOWN is the type of an unknown value.
+ * Used on unknown consts and other places where I don't know the type.
*/
+#define ATTRIB_SHIFT 16
+#define ATTRIB_MASK 0xffff0000
+#define ATTRIB_NOINLINE 0x00010000
+#define ATTRIB_ALWAYS_INLINE 0x00020000
+
#define ELEMENT_COUNT_UNSPECIFIED ULONG_T_MAX
struct type {
@@ -954,8 +1236,9 @@ struct type {
#define MAX_REGISTERS 75
#define REGISTER_BITS 7
#define MAX_VIRT_REGISTERS (1<<REGISTER_BITS)
-#define REG_UNSET 0
-#define REG_UNNEEDED 1
+#define REG_ERROR 0
+#define REG_UNSET 1
+#define REG_UNNEEDED 2
#define REG_VIRT0 (MAX_REGISTERS + 0)
#define REG_VIRT1 (MAX_REGISTERS + 1)
#define REG_VIRT2 (MAX_REGISTERS + 2)
@@ -970,7 +1253,7 @@ struct type {
#if (MAX_REGISTERS + 9) > MAX_VIRT_REGISTERS
#error "MAX_VIRT_REGISTERS to small"
#endif
-#if (MAX_REGC + REGISTER_BITS) > 27
+#if (MAX_REGC + REGISTER_BITS) >= 26
#error "Too many id bits used"
#endif
@@ -986,6 +1269,11 @@ struct type {
#define SET_INFO(ID, INFO) ((ID) = (((ID) & ~(REG_MASK | REGC_MASK)) | \
(((INFO).reg) & REG_MASK) | ((((INFO).regcm) << REGC_SHIFT) & REGC_MASK)))
+#define ARCH_INPUT_REGS 4
+#define ARCH_OUTPUT_REGS 4
+
+static const struct reg_info arch_input_regs[ARCH_INPUT_REGS];
+static const struct reg_info arch_output_regs[ARCH_OUTPUT_REGS];
static unsigned arch_reg_regcm(struct compile_state *state, int reg);
static unsigned arch_regcm_normalize(struct compile_state *state, unsigned regcm);
static unsigned arch_regcm_reg_normalize(struct compile_state *state, unsigned regcm);
@@ -1005,8 +1293,12 @@ 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 int arch_reg_size(int reg);
static struct triple *transform_to_arch_instruction(
struct compile_state *state, struct triple *ins);
+static struct triple *flatten(
+ struct compile_state *state, struct triple *first, struct triple *ptr);
+
@@ -1026,6 +1318,10 @@ static struct triple *transform_to_arch_instruction(
#define DEBUG_COLOR_GRAPH2 0x00002000
#define DEBUG_COALESCING 0x00004000
#define DEBUG_COALESCING2 0x00008000
+#define DEBUG_VERIFICATION 0x00010000
+#define DEBUG_CALLS 0x00020000
+#define DEBUG_CALLS2 0x00040000
+#define DEBUG_TOKENS 0x80000000
#define DEBUG_DEFAULT ( \
DEBUG_ABORT_ON_ERROR | \
@@ -1035,25 +1331,54 @@ static struct triple *transform_to_arch_instruction(
DEBUG_TRIPLES | \
0 )
-#define COMPILER_ELIMINATE_INEFECTUAL_CODE 0x00000001
-#define COMPILER_SIMPLIFY 0x00000002
-#define COMPILER_SCC_TRANSFORM 0x00000004
-#define COMPILER_INLINE 0x00000008
-#define COMPILER_ALWAYS_INLINE 0x00000010
-#define COMPILER_SIMPLIFY_OP 0x00000020
-#define COMPILER_SIMPLIFY_PHI 0x00000040
-#define COMPILER_SIMPLIFY_LABEL 0x00000080
-#define COMPILER_SIMPLIFY_BRANCH 0x00000100
-#define COMPILER_SIMPLIFY_COPY 0x00000200
-#define COMPILER_SIMPLIFY_ARITH 0x00000400
-#define COMPILER_SIMPLIFY_SHIFT 0x00000800
-#define COMPILER_SIMPLIFY_BITWISE 0x00001000
-#define COMPILER_SIMPLIFY_LOGICAL 0x00002000
+#define DEBUG_ALL ( \
+ DEBUG_ABORT_ON_ERROR | \
+ DEBUG_BASIC_BLOCKS | \
+ DEBUG_FDOMINATORS | \
+ DEBUG_RDOMINATORS | \
+ DEBUG_TRIPLES | \
+ DEBUG_INTERFERENCE | \
+ DEBUG_SCC_TRANSFORM | \
+ DEBUG_SCC_TRANSFORM2 | \
+ DEBUG_REBUILD_SSA_FORM | \
+ DEBUG_INLINE | \
+ DEBUG_RANGE_CONFLICTS | \
+ DEBUG_RANGE_CONFLICTS2 | \
+ DEBUG_COLOR_GRAPH | \
+ DEBUG_COLOR_GRAPH2 | \
+ DEBUG_COALESCING | \
+ DEBUG_COALESCING2 | \
+ DEBUG_VERIFICATION | \
+ DEBUG_CALLS | \
+ DEBUG_CALLS2 | \
+ DEBUG_TOKENS | \
+ 0 )
+
+#define COMPILER_INLINE_MASK 0x00000007
+#define COMPILER_INLINE_ALWAYS 0x00000000
+#define COMPILER_INLINE_NEVER 0x00000001
+#define COMPILER_INLINE_DEFAULTON 0x00000002
+#define COMPILER_INLINE_DEFAULTOFF 0x00000003
+#define COMPILER_INLINE_NOPENALTY 0x00000004
+#define COMPILER_ELIMINATE_INEFECTUAL_CODE 0x00000008
+#define COMPILER_SIMPLIFY 0x00000010
+#define COMPILER_SCC_TRANSFORM 0x00000020
+#define COMPILER_SIMPLIFY_OP 0x00000040
+#define COMPILER_SIMPLIFY_PHI 0x00000080
+#define COMPILER_SIMPLIFY_LABEL 0x00000100
+#define COMPILER_SIMPLIFY_BRANCH 0x00000200
+#define COMPILER_SIMPLIFY_COPY 0x00000400
+#define COMPILER_SIMPLIFY_ARITH 0x00000800
+#define COMPILER_SIMPLIFY_SHIFT 0x00001000
+#define COMPILER_SIMPLIFY_BITWISE 0x00002000
+#define COMPILER_SIMPLIFY_LOGICAL 0x00004000
+#define COMPILER_SIMPLIFY_BITFIELD 0x00008000
+
+#define COMPILER_CPP_ONLY 0x80000000
#define COMPILER_DEFAULT_FLAGS ( \
COMPILER_ELIMINATE_INEFECTUAL_CODE | \
- COMPILER_INLINE | \
- COMPILER_ALWAYS_INLINE | \
+ COMPILER_INLINE_DEFAULTON | \
COMPILER_SIMPLIFY_OP | \
COMPILER_SIMPLIFY_PHI | \
COMPILER_SIMPLIFY_LABEL | \
@@ -1063,6 +1388,7 @@ static struct triple *transform_to_arch_instruction(
COMPILER_SIMPLIFY_SHIFT | \
COMPILER_SIMPLIFY_BITWISE | \
COMPILER_SIMPLIFY_LOGICAL | \
+ COMPILER_SIMPLIFY_BITFIELD | \
0 )
#define GLOBAL_SCOPE_DEPTH 1
@@ -1080,13 +1406,25 @@ static void init_compiler_state(struct compiler_state *compiler)
compiler->flags = COMPILER_DEFAULT_FLAGS;
compiler->debug = 0;
compiler->max_allocation_passes = MAX_ALLOCATION_PASSES;
-
+ compiler->include_path_count = 1;
+ compiler->include_paths = xcmalloc(sizeof(char *), "include_paths");
+ compiler->define_count = 1;
+ compiler->defines = xcmalloc(sizeof(char *), "defines");
+ compiler->undef_count = 1;
+ compiler->undefs = xcmalloc(sizeof(char *), "undefs");
}
struct compiler_flag {
const char *name;
unsigned long flag;
};
+
+struct compiler_arg {
+ const char *name;
+ unsigned long mask;
+ struct compiler_flag flags[16];
+};
+
static int set_flag(
const struct compiler_flag *ptr, unsigned long *flags,
int act, const char *flag)
@@ -1107,50 +1445,180 @@ static int set_flag(
return result;
}
+static int set_arg(
+ const struct compiler_arg *ptr, unsigned long *flags, const char *arg)
+{
+ const char *val;
+ int result = -1;
+ int len;
+ val = strchr(arg, '=');
+ if (val) {
+ len = val - arg;
+ val++;
+ for(; ptr->name; ptr++) {
+ if (strncmp(ptr->name, arg, len) == 0) {
+ break;
+ }
+ }
+ if (ptr->name) {
+ *flags &= ~ptr->mask;
+ result = set_flag(&ptr->flags[0], flags, 1, val);
+ }
+ }
+ return result;
+}
+
+
+static void flag_usage(FILE *fp, const struct compiler_flag *ptr,
+ const char *prefix, const char *invert_prefix)
+{
+ for(;ptr->name; ptr++) {
+ fprintf(fp, "%s%s\n", prefix, ptr->name);
+ if (invert_prefix) {
+ fprintf(fp, "%s%s\n", invert_prefix, ptr->name);
+ }
+ }
+}
+
+static void arg_usage(FILE *fp, const struct compiler_arg *ptr,
+ const char *prefix)
+{
+ for(;ptr->name; ptr++) {
+ const struct compiler_flag *flag;
+ for(flag = &ptr->flags[0]; flag->name; flag++) {
+ fprintf(fp, "%s%s=%s\n",
+ prefix, ptr->name, flag->name);
+ }
+ }
+}
+
+static int append_string(size_t *max, const char ***vec, const char *str,
+ const char *name)
+{
+ size_t count;
+ count = ++(*max);
+ *vec = xrealloc(*vec, sizeof(char *)*count, "name");
+ (*vec)[count -1] = 0;
+ (*vec)[count -2] = str;
+ return 0;
+}
+
+static void arg_error(char *fmt, ...);
+static const char *identifier(const char *str, const char *end);
+
+static int append_include_path(struct compiler_state *compiler, const char *str)
+{
+ int result;
+ if (!exists(str, ".")) {
+ arg_error("Nonexistent include path: `%s'\n",
+ str);
+ }
+ result = append_string(&compiler->include_path_count,
+ &compiler->include_paths, str, "include_paths");
+ return result;
+}
+
+static int append_define(struct compiler_state *compiler, const char *str)
+{
+ const char *end, *rest;
+ int result;
+
+ end = strchr(str, '=');
+ if (!end) {
+ end = str + strlen(str);
+ }
+ rest = identifier(str, end);
+ if (rest != end) {
+ int len = end - str - 1;
+ arg_error("Invalid name cannot define macro: `%*.*s'\n",
+ len, len, str);
+ }
+ result = append_string(&compiler->define_count,
+ &compiler->defines, str, "defines");
+ return result;
+}
+
+static int append_undef(struct compiler_state *compiler, const char *str)
+{
+ const char *end, *rest;
+ int result;
+
+ end = str + strlen(str);
+ rest = identifier(str, end);
+ if (rest != end) {
+ int len = end - str - 1;
+ arg_error("Invalid name cannot undefine macro: `%*.*s'\n",
+ len, len, str);
+ }
+ result = append_string(&compiler->undef_count,
+ &compiler->undefs, str, "undefs");
+ return result;
+}
+
+static const struct compiler_flag romcc_flags[] = {
+ { "cpp-only", COMPILER_CPP_ONLY },
+ { "eliminate-inefectual-code", COMPILER_ELIMINATE_INEFECTUAL_CODE },
+ { "simplify", COMPILER_SIMPLIFY },
+ { "scc-transform", COMPILER_SCC_TRANSFORM },
+ { "simplify-op", COMPILER_SIMPLIFY_OP },
+ { "simplify-phi", COMPILER_SIMPLIFY_PHI },
+ { "simplify-label", COMPILER_SIMPLIFY_LABEL },
+ { "simplify-branch", COMPILER_SIMPLIFY_BRANCH },
+ { "simplify-copy", COMPILER_SIMPLIFY_COPY },
+ { "simplify-arith", COMPILER_SIMPLIFY_ARITH },
+ { "simplify-shift", COMPILER_SIMPLIFY_SHIFT },
+ { "simplify-bitwise", COMPILER_SIMPLIFY_BITWISE },
+ { "simplify-logical", COMPILER_SIMPLIFY_LOGICAL },
+ { "simplify-bitfield", COMPILER_SIMPLIFY_BITFIELD },
+ { 0, 0 },
+};
+static const struct compiler_arg romcc_args[] = {
+ { "inline-policy", COMPILER_INLINE_MASK,
+ {
+ { "always", COMPILER_INLINE_ALWAYS, },
+ { "never", COMPILER_INLINE_NEVER, },
+ { "defaulton", COMPILER_INLINE_DEFAULTON, },
+ { "defaultoff", COMPILER_INLINE_DEFAULTOFF, },
+ { "nopenalty", COMPILER_INLINE_NOPENALTY, },
+ { 0, 0 },
+ },
+ },
+ { 0, 0 },
+};
+static const struct compiler_flag romcc_opt_flags[] = {
+ { "-O", COMPILER_SIMPLIFY },
+ { "-O2", COMPILER_SIMPLIFY | COMPILER_SCC_TRANSFORM },
+ { "-E", COMPILER_CPP_ONLY },
+ { 0, 0, },
+};
+static const struct compiler_flag romcc_debug_flags[] = {
+ { "all", DEBUG_ALL },
+ { "abort-on-error", DEBUG_ABORT_ON_ERROR },
+ { "basic-blocks", DEBUG_BASIC_BLOCKS },
+ { "fdominators", DEBUG_FDOMINATORS },
+ { "rdominators", DEBUG_RDOMINATORS },
+ { "triples", DEBUG_TRIPLES },
+ { "interference", DEBUG_INTERFERENCE },
+ { "scc-transform", DEBUG_SCC_TRANSFORM },
+ { "scc-transform2", DEBUG_SCC_TRANSFORM2 },
+ { "rebuild-ssa-form", DEBUG_REBUILD_SSA_FORM },
+ { "inline", DEBUG_INLINE },
+ { "live-range-conflicts", DEBUG_RANGE_CONFLICTS },
+ { "live-range-conflicts2", DEBUG_RANGE_CONFLICTS2 },
+ { "color-graph", DEBUG_COLOR_GRAPH },
+ { "color-graph2", DEBUG_COLOR_GRAPH2 },
+ { "coalescing", DEBUG_COALESCING },
+ { "coalescing2", DEBUG_COALESCING2 },
+ { "verification", DEBUG_VERIFICATION },
+ { "calls", DEBUG_CALLS },
+ { "calls2", DEBUG_CALLS2 },
+ { "tokens", DEBUG_TOKENS },
+ { 0, 0 },
+};
+
static int compiler_encode_flag(
struct compiler_state *compiler, const char *flag)
{
- static const struct compiler_flag flags[] = {
- { "eliminate-inefectual-code", COMPILER_ELIMINATE_INEFECTUAL_CODE },
- { "simplify", COMPILER_SIMPLIFY },
- { "scc-transform", COMPILER_SCC_TRANSFORM },
- { "inline", COMPILER_INLINE },
- { "always-inline", COMPILER_ALWAYS_INLINE },
- { "simplify-op", COMPILER_SIMPLIFY_OP },
- { "simplify-phi", COMPILER_SIMPLIFY_PHI },
- { "simplify-label", COMPILER_SIMPLIFY_LABEL },
- { "simplify-branch", COMPILER_SIMPLIFY_BRANCH },
- { "simplify-copy", COMPILER_SIMPLIFY_COPY },
- { "simplify-arith", COMPILER_SIMPLIFY_ARITH },
- { "simplify-shift", COMPILER_SIMPLIFY_SHIFT },
- { "simplify-bitwise", COMPILER_SIMPLIFY_BITWISE },
- { "simplify-logical", COMPILER_SIMPLIFY_LOGICAL },
- { 0, 0 },
- };
- static const struct compiler_flag opt_flags[] = {
- { "-O", COMPILER_SIMPLIFY },
- { "-O2", COMPILER_SIMPLIFY | COMPILER_SCC_TRANSFORM },
- { 0, 0, },
- };
- static const struct compiler_flag debug_flags[] = {
- { "abort-on-error", DEBUG_ABORT_ON_ERROR },
- { "basic-blocks", DEBUG_BASIC_BLOCKS },
- { "fdominators", DEBUG_FDOMINATORS },
- { "rdominators", DEBUG_RDOMINATORS },
- { "triples", DEBUG_TRIPLES },
- { "interference", DEBUG_INTERFERENCE },
- { "scc-transform", DEBUG_SCC_TRANSFORM },
- { "scc-transform2", DEBUG_SCC_TRANSFORM2 },
- { "rebuild-ssa-form", DEBUG_REBUILD_SSA_FORM },
- { "inline", DEBUG_INLINE },
- { "live-range-conflicts", DEBUG_RANGE_CONFLICTS },
- { "live-range-conflicts2", DEBUG_RANGE_CONFLICTS2 },
- { "color-graph", DEBUG_COLOR_GRAPH },
- { "color-graph2", DEBUG_COLOR_GRAPH2 },
- { "coalescing", DEBUG_COALESCING },
- { "coalescing2", DEBUG_COALESCING2 },
- { 0, 0 },
- };
int act;
int result;
@@ -1161,7 +1629,19 @@ static int compiler_encode_flag(
act = 0;
}
if (strncmp(flag, "-O", 2) == 0) {
- result = set_flag(opt_flags, &compiler->flags, act, flag);
+ result = set_flag(romcc_opt_flags, &compiler->flags, act, flag);
+ }
+ else if (strncmp(flag, "-E", 2) == 0) {
+ result = set_flag(romcc_opt_flags, &compiler->flags, act, flag);
+ }
+ else if (strncmp(flag, "-I", 2) == 0) {
+ result = append_include_path(compiler, flag + 2);
+ }
+ else if (strncmp(flag, "-D", 2) == 0) {
+ result = append_define(compiler, flag + 2);
+ }
+ else if (strncmp(flag, "-U", 2) == 0) {
+ result = append_undef(compiler, flag + 2);
}
else if (act && strncmp(flag, "label-prefix=", 13) == 0) {
result = 0;
@@ -1182,26 +1662,57 @@ static int compiler_encode_flag(
}
else if (strncmp(flag, "debug-", 6) == 0) {
flag += 6;
- result = set_flag(debug_flags, &compiler->debug, act, flag);
+ result = set_flag(romcc_debug_flags, &compiler->debug, act, flag);
}
else {
- result = set_flag(flags, &compiler->flags, act, flag);
+ result = set_flag(romcc_flags, &compiler->flags, act, flag);
+ if (result < 0) {
+ result = set_arg(romcc_args, &compiler->flags, flag);
+ }
}
return result;
}
+static void compiler_usage(FILE *fp)
+{
+ flag_usage(fp, romcc_opt_flags, "", 0);
+ flag_usage(fp, romcc_flags, "-f", "-fno-");
+ arg_usage(fp, romcc_args, "-f");
+ flag_usage(fp, romcc_debug_flags, "-fdebug-", "-fno-debug-");
+ fprintf(fp, "-flabel-prefix=<prefix for assembly language labels>\n");
+ fprintf(fp, "--label-prefix=<prefix for assembly language labels>\n");
+ fprintf(fp, "-I<include path>\n");
+ fprintf(fp, "-D<macro>[=defn]\n");
+ fprintf(fp, "-U<macro>\n");
+}
+
static void do_cleanup(struct compile_state *state)
{
if (state->output) {
fclose(state->output);
unlink(state->compiler->ofilename);
+ state->output = 0;
+ }
+ if (state->dbgout) {
+ fflush(state->dbgout);
+ }
+ if (state->errout) {
+ fflush(state->errout);
+ }
+}
+
+static struct compile_state *exit_state;
+static void exit_cleanup(void)
+{
+ if (exit_state) {
+ do_cleanup(exit_state);
}
}
static int get_col(struct file_state *file)
{
int col;
- char *ptr, *end;
+ const char *ptr, *end;
ptr = file->line_start;
end = file->pos;
for(col = 0; ptr < end; ptr++) {
@@ -1235,18 +1746,19 @@ static void loc(FILE *fp, struct compile_state *state, struct triple *triple)
}
static void internal_error(struct compile_state *state, struct triple *ptr,
- char *fmt, ...)
+ const char *fmt, ...)
{
+ FILE *fp = state->errout;
va_list args;
va_start(args, fmt);
- loc(stderr, state, ptr);
- fputc('\n', stderr);
+ loc(fp, state, ptr);
+ fputc('\n', fp);
if (ptr) {
- fprintf(stderr, "%p %s ", ptr, tops(ptr->op));
+ fprintf(fp, "%p %-10s ", ptr, tops(ptr->op));
}
- fprintf(stderr, "Internal compiler error: ");
- vfprintf(stderr, fmt, args);
- fprintf(stderr, "\n");
+ fprintf(fp, "Internal compiler error: ");
+ vfprintf(fp, fmt, args);
+ fprintf(fp, "\n");
va_end(args);
do_cleanup(state);
abort();
@@ -1254,35 +1766,37 @@ static void internal_error(struct compile_state *state, struct triple *ptr,
static void internal_warning(struct compile_state *state, struct triple *ptr,
- char *fmt, ...)
+ const char *fmt, ...)
{
+ FILE *fp = state->errout;
va_list args;
va_start(args, fmt);
- loc(stderr, state, ptr);
+ loc(fp, state, ptr);
if (ptr) {
- fprintf(stderr, "%p %s ", ptr, tops(ptr->op));
+ fprintf(fp, "%p %-10s ", ptr, tops(ptr->op));
}
- fprintf(stderr, "Internal compiler warning: ");
- vfprintf(stderr, fmt, args);
- fprintf(stderr, "\n");
+ fprintf(fp, "Internal compiler warning: ");
+ vfprintf(fp, fmt, args);
+ fprintf(fp, "\n");
va_end(args);
}
static void error(struct compile_state *state, struct triple *ptr,
- char *fmt, ...)
+ const char *fmt, ...)
{
+ FILE *fp = state->errout;
va_list args;
va_start(args, fmt);
- loc(stderr, state, ptr);
- fputc('\n', stderr);
+ loc(fp, state, ptr);
+ fputc('\n', fp);
if (ptr && (state->compiler->debug & DEBUG_ABORT_ON_ERROR)) {
- fprintf(stderr, "%p %s ", ptr, tops(ptr->op));
+ fprintf(fp, "%p %-10s ", ptr, tops(ptr->op));
}
- vfprintf(stderr, fmt, args);
+ vfprintf(fp, fmt, args);
va_end(args);
- fprintf(stderr, "\n");
+ fprintf(fp, "\n");
do_cleanup(state);
if (state->compiler->debug & DEBUG_ABORT_ON_ERROR) {
abort();
@@ -1291,14 +1805,18 @@ static void error(struct compile_state *state, struct triple *ptr,
}
static void warning(struct compile_state *state, struct triple *ptr,
- char *fmt, ...)
+ const char *fmt, ...)
{
+ FILE *fp = state->errout;
va_list args;
va_start(args, fmt);
- loc(stderr, state, ptr);
- fprintf(stderr, "warning: ");
- vfprintf(stderr, fmt, args);
- fprintf(stderr, "\n");
+ loc(fp, state, ptr);
+ fprintf(fp, "warning: ");
+ if (ptr && (state->compiler->debug & DEBUG_ABORT_ON_ERROR)) {
+ fprintf(fp, "%p %-10s ", ptr, tops(ptr->op));
+ }
+ vfprintf(fp, fmt, args);
+ fprintf(fp, "\n");
va_end(args);
}
@@ -1320,6 +1838,29 @@ static void valid_ins(struct compile_state *state, struct triple *ptr)
valid_op(state, ptr->op);
}
+static void valid_param_count(struct compile_state *state, struct triple *ins)
+{
+ int lhs, rhs, misc, targ;
+ valid_ins(state, ins);
+ lhs = table_ops[ins->op].lhs;
+ rhs = table_ops[ins->op].rhs;
+ misc = table_ops[ins->op].misc;
+ targ = table_ops[ins->op].targ;
+
+ if ((lhs >= 0) && (ins->lhs != lhs)) {
+ internal_error(state, ins, "Bad lhs count");
+ }
+ if ((rhs >= 0) && (ins->rhs != rhs)) {
+ internal_error(state, ins, "Bad rhs count");
+ }
+ if ((misc >= 0) && (ins->misc != misc)) {
+ internal_error(state, ins, "Bad misc count");
+ }
+ if ((targ >= 0) && (ins->targ != targ)) {
+ internal_error(state, ins, "Bad targ count");
+ }
+}
+
static void process_trigraphs(struct compile_state *state)
{
char *src, *dest, *end;
@@ -1381,6 +1922,7 @@ static void splice_lines(struct compile_state *state)
}
static struct type void_type;
+static struct type unknown_type;
static void use_triple(struct triple *used, struct triple *user)
{
struct triple_set **ptr, *new;
@@ -1543,16 +2085,20 @@ static struct occurance dummy_occurance = {
.parent = 0,
};
-/* The zero triple is used as a place holder when we are removing pointers
+/* The undef triple is used as a place holder when we are removing pointers
* from a triple. Having allows certain sanity checks to pass even
* when the original triple that was pointed to is gone.
*/
-static struct triple zero_triple = {
- .next = &zero_triple,
- .prev = &zero_triple,
+static struct triple unknown_triple = {
+ .next = &unknown_triple,
+ .prev = &unknown_triple,
.use = 0,
- .op = OP_INTCONST,
- .sizes = TRIPLE_SIZES(0, 0, 0, 0),
+ .op = OP_UNKNOWNVAL,
+ .lhs = 0,
+ .rhs = 0,
+ .misc = 0,
+ .targ = 0,
+ .type = &unknown_type,
.id = -1, /* An invalid id */
.u = { .cval = 0, },
.occurance = &dummy_occurance,
@@ -1560,12 +2106,15 @@ static struct triple zero_triple = {
};
-static unsigned short triple_sizes(struct compile_state *state,
+static size_t registers_of(struct compile_state *state, struct type *type);
+
+static struct triple *alloc_triple(struct compile_state *state,
int op, struct type *type, int lhs_wanted, int rhs_wanted,
struct occurance *occurance)
{
+ size_t size, extra_count, min_count;
int lhs, rhs, misc, targ;
- struct triple dummy;
+ struct triple *ret, dummy;
dummy.op = op;
dummy.occurance = occurance;
valid_op(state, op);
@@ -1573,60 +2122,65 @@ static unsigned short triple_sizes(struct compile_state *state,
rhs = table_ops[op].rhs;
misc = table_ops[op].misc;
targ = table_ops[op].targ;
-
-
- if (op == OP_FCALL) {
+
+ switch(op) {
+ case OP_FCALL:
rhs = rhs_wanted;
- lhs = 0;
- if ((type->type & TYPE_MASK) == TYPE_STRUCT) {
- lhs = type->elements;
- }
- }
- else if (op == OP_VAL_VEC) {
- rhs = type->elements;
- }
- else if (op == OP_PHI) {
+ break;
+ case OP_PHI:
rhs = rhs_wanted;
- }
- else if (op == OP_ASM) {
+ break;
+ case OP_ADECL:
+ lhs = registers_of(state, type);
+ break;
+ case OP_TUPLE:
+ lhs = registers_of(state, type);
+ break;
+ case OP_ASM:
rhs = rhs_wanted;
lhs = lhs_wanted;
+ break;
}
if ((rhs < 0) || (rhs > MAX_RHS)) {
- internal_error(state, &dummy, "bad rhs %d", rhs);
+ internal_error(state, &dummy, "bad rhs count %d", rhs);
}
if ((lhs < 0) || (lhs > MAX_LHS)) {
- internal_error(state, &dummy, "bad lhs");
+ internal_error(state, &dummy, "bad lhs count %d", lhs);
}
if ((misc < 0) || (misc > MAX_MISC)) {
- internal_error(state, &dummy, "bad misc");
+ internal_error(state, &dummy, "bad misc count %d", misc);
}
if ((targ < 0) || (targ > MAX_TARG)) {
- internal_error(state, &dummy, "bad targs");
+ internal_error(state, &dummy, "bad targs count %d", targ);
}
- return TRIPLE_SIZES(lhs, rhs, misc, targ);
-}
-
-static struct triple *alloc_triple(struct compile_state *state,
- int op, struct type *type, int lhs, int rhs,
- struct occurance *occurance)
-{
- size_t size, sizes, extra_count, min_count;
- struct triple *ret;
- sizes = triple_sizes(state, op, type, lhs, rhs, occurance);
min_count = sizeof(ret->param)/sizeof(ret->param[0]);
- extra_count = TRIPLE_SIZE(sizes);
+ extra_count = lhs + rhs + misc + targ;
extra_count = (extra_count < min_count)? 0 : extra_count - min_count;
size = sizeof(*ret) + sizeof(ret->param[0]) * extra_count;
ret = xcmalloc(size, "tripple");
ret->op = op;
- ret->sizes = sizes;
+ ret->lhs = lhs;
+ ret->rhs = rhs;
+ ret->misc = misc;
+ ret->targ = targ;
ret->type = type;
ret->next = ret;
ret->prev = ret;
ret->occurance = occurance;
+ /* A simple sanity check */
+ if ((ret->op != op) ||
+ (ret->lhs != lhs) ||
+ (ret->rhs != rhs) ||
+ (ret->misc != misc) ||
+ (ret->targ != targ) ||
+ (ret->type != type) ||
+ (ret->next != ret) ||
+ (ret->prev != ret) ||
+ (ret->occurance != occurance)) {
+ internal_error(state, ret, "huh?");
+ }
return ret;
}
@@ -1634,9 +2188,9 @@ struct triple *dup_triple(struct compile_state *state, struct triple *src)
{
struct triple *dup;
int src_lhs, src_rhs, src_size;
- src_lhs = TRIPLE_LHS(src->sizes);
- src_rhs = TRIPLE_RHS(src->sizes);
- src_size = TRIPLE_SIZE(src->sizes);
+ src_lhs = src->lhs;
+ src_rhs = src->rhs;
+ src_size = TRIPLE_SIZE(src);
get_occurance(src->occurance);
dup = alloc_triple(state, src->op, src->type, src_lhs, src_rhs,
src->occurance);
@@ -1662,7 +2216,7 @@ static struct triple *build_triple(struct compile_state *state,
struct triple *ret;
size_t count;
ret = alloc_triple(state, op, type, -1, -1, occurance);
- count = TRIPLE_SIZE(ret->sizes);
+ count = TRIPLE_SIZE(ret);
if (count > 0) {
ret->param[0] = left;
}
@@ -1678,7 +2232,7 @@ static struct triple *triple(struct compile_state *state,
struct triple *ret;
size_t count;
ret = new_triple(state, op, type, -1, -1);
- count = TRIPLE_SIZE(ret->sizes);
+ count = TRIPLE_SIZE(ret);
if (count >= 1) {
ret->param[0] = left;
}
@@ -1706,6 +2260,9 @@ static struct triple *branch(struct compile_state *state,
return ret;
}
+static int triple_is_label(struct compile_state *state, struct triple *ins);
+static int triple_is_call(struct compile_state *state, struct triple *ins);
+static int triple_is_cbranch(struct compile_state *state, struct triple *ins);
static void insert_triple(struct compile_state *state,
struct triple *first, struct triple *ptr)
{
@@ -1717,8 +2274,9 @@ static void insert_triple(struct compile_state *state,
ptr->prev = first->prev;
ptr->prev->next = ptr;
ptr->next->prev = ptr;
-
- if ((ptr->prev->op == OP_CBRANCH) || (ptr->prev->op == OP_CALL)) {
+
+ if (triple_is_cbranch(state, ptr->prev) ||
+ triple_is_call(state, ptr->prev)) {
unuse_triple(first, ptr->prev);
use_triple(ptr, ptr->prev);
}
@@ -1736,32 +2294,34 @@ static int triple_stores_block(struct compile_state *state, struct triple *ins)
return stores_block;
}
+static int triple_is_branch(struct compile_state *state, struct triple *ins);
static struct block *block_of_triple(struct compile_state *state,
struct triple *ins)
{
struct triple *first;
- if (!ins || ins == &zero_triple) {
+ if (!ins || ins == &unknown_triple) {
return 0;
}
first = state->first;
- while(ins != first && !triple_stores_block(state, ins)) {
+ while(ins != first && !triple_is_branch(state, ins->prev) &&
+ !triple_stores_block(state, ins))
+ {
if (ins == ins->prev) {
internal_error(state, ins, "ins == ins->prev?");
}
ins = ins->prev;
}
- if (!triple_stores_block(state, ins)) {
- internal_error(state, ins, "Cannot find block");
- }
- return ins->u.block;
+ return triple_stores_block(state, ins)? ins->u.block: 0;
}
+static void generate_lhs_pieces(struct compile_state *state, struct triple *ins);
static struct triple *pre_triple(struct compile_state *state,
struct triple *base,
int op, struct type *type, struct triple *left, struct triple *right)
{
struct block *block;
struct triple *ret;
+ int i;
/* If I am an OP_PIECE jump to the real instruction */
if (base->op == OP_PIECE) {
base = MISC(base, 0);
@@ -1769,11 +2329,19 @@ static struct triple *pre_triple(struct compile_state *state,
block = block_of_triple(state, base);
get_occurance(base->occurance);
ret = build_triple(state, op, type, left, right, base->occurance);
+ generate_lhs_pieces(state, ret);
if (triple_stores_block(state, ret)) {
ret->u.block = block;
}
insert_triple(state, base, ret);
- if (block->first == base) {
+ for(i = 0; i < ret->lhs; i++) {
+ struct triple *piece;
+ piece = LHS(ret, i);
+ insert_triple(state, base, piece);
+ use_triple(ret, piece);
+ use_triple(piece, ret);
+ }
+ if (block && (block->first == base)) {
block->first = ret;
}
return ret;
@@ -1784,14 +2352,14 @@ static struct triple *post_triple(struct compile_state *state,
int op, struct type *type, struct triple *left, struct triple *right)
{
struct block *block;
- struct triple *ret;
- int zlhs;
+ struct triple *ret, *next;
+ int zlhs, i;
/* 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);
+ zlhs = base->lhs;
if (zlhs) {
base = LHS(base, zlhs - 1);
}
@@ -1799,16 +2367,67 @@ static struct triple *post_triple(struct compile_state *state,
block = block_of_triple(state, base);
get_occurance(base->occurance);
ret = build_triple(state, op, type, left, right, base->occurance);
+ generate_lhs_pieces(state, ret);
if (triple_stores_block(state, ret)) {
ret->u.block = block;
}
- insert_triple(state, base->next, ret);
- if (block->last == base) {
+ next = base->next;
+ insert_triple(state, next, ret);
+ zlhs = ret->lhs;
+ for(i = 0; i < zlhs; i++) {
+ struct triple *piece;
+ piece = LHS(ret, i);
+ insert_triple(state, next, piece);
+ use_triple(ret, piece);
+ use_triple(piece, ret);
+ }
+ if (block && (block->last == base)) {
block->last = ret;
+ if (zlhs) {
+ block->last = LHS(ret, zlhs - 1);
+ }
}
return ret;
}
+static struct type *reg_type(
+ struct compile_state *state, struct type *type, int reg);
+
+static void generate_lhs_piece(
+ struct compile_state *state, struct triple *ins, int index)
+{
+ struct type *piece_type;
+ struct triple *piece;
+ get_occurance(ins->occurance);
+ piece_type = reg_type(state, ins->type, index * REG_SIZEOF_REG);
+
+ if ((piece_type->type & TYPE_MASK) == TYPE_BITFIELD) {
+ piece_type = piece_type->left;
+ }
+#if 0
+{
+ static void name_of(FILE *fp, struct type *type);
+ FILE * fp = state->errout;
+ fprintf(fp, "piece_type(%d): ", index);
+ name_of(fp, piece_type);
+ fprintf(fp, "\n");
+}
+#endif
+ piece = alloc_triple(state, OP_PIECE, piece_type, -1, -1, ins->occurance);
+ piece->u.cval = index;
+ LHS(ins, piece->u.cval) = piece;
+ MISC(piece, 0) = ins;
+}
+
+static void generate_lhs_pieces(struct compile_state *state, struct triple *ins)
+{
+ int i, zlhs;
+ zlhs = ins->lhs;
+ for(i = 0; i < zlhs; i++) {
+ generate_lhs_piece(state, ins, i);
+ }
+}
+
static struct triple *label(struct compile_state *state)
{
/* Labels don't get a type */
@@ -1817,34 +2436,80 @@ static struct triple *label(struct compile_state *state)
return result;
}
+static struct triple *mkprog(struct compile_state *state, ...)
+{
+ struct triple *prog, *head, *arg;
+ va_list args;
+ int i;
+
+ head = label(state);
+ prog = new_triple(state, OP_PROG, &void_type, -1, -1);
+ RHS(prog, 0) = head;
+ va_start(args, state);
+ i = 0;
+ while((arg = va_arg(args, struct triple *)) != 0) {
+ if (++i >= 100) {
+ internal_error(state, 0, "too many arguments to mkprog");
+ }
+ flatten(state, head, arg);
+ }
+ va_end(args);
+ prog->type = head->prev->type;
+ return prog;
+}
+static void name_of(FILE *fp, struct type *type);
static void display_triple(FILE *fp, struct triple *ins)
{
struct occurance *ptr;
const char *reg;
- char pre, post;
- pre = post = ' ';
- if (ins->id & TRIPLE_FLAG_PRE_SPLIT) {
- pre = '^';
- }
- if (ins->id & TRIPLE_FLAG_POST_SPLIT) {
- post = 'v';
- }
- reg = arch_reg_str(ID_REG(ins->id));
- if (ins->op == OP_INTCONST) {
- fprintf(fp, "(%p) %c%c %-7s %-2d %-10s <0x%08lx> ",
- ins, pre, post, reg, ins->template_id, tops(ins->op),
+ char pre, post, vol;
+ pre = post = vol = ' ';
+ if (ins) {
+ if (ins->id & TRIPLE_FLAG_PRE_SPLIT) {
+ pre = '^';
+ }
+ if (ins->id & TRIPLE_FLAG_POST_SPLIT) {
+ post = ',';
+ }
+ if (ins->id & TRIPLE_FLAG_VOLATILE) {
+ vol = 'v';
+ }
+ reg = arch_reg_str(ID_REG(ins->id));
+ }
+ if (ins == 0) {
+ fprintf(fp, "(%p) <nothing> ", ins);
+ }
+ else if (ins->op == OP_INTCONST) {
+ fprintf(fp, "(%p) %c%c%c %-7s %-2d %-10s <0x%08lx> ",
+ ins, pre, post, vol, reg, ins->template_id, tops(ins->op),
(unsigned long)(ins->u.cval));
}
else if (ins->op == OP_ADDRCONST) {
- fprintf(fp, "(%p) %c%c %-7s %-2d %-10s %-10p <0x%08lx>",
- ins, pre, post, reg, ins->template_id, tops(ins->op),
+ fprintf(fp, "(%p) %c%c%c %-7s %-2d %-10s %-10p <0x%08lx>",
+ ins, pre, post, vol, reg, ins->template_id, tops(ins->op),
+ MISC(ins, 0), (unsigned long)(ins->u.cval));
+ }
+ else if (ins->op == OP_INDEX) {
+ fprintf(fp, "(%p) %c%c%c %-7s %-2d %-10s %-10p <0x%08lx>",
+ ins, pre, post, vol, reg, ins->template_id, tops(ins->op),
+ RHS(ins, 0), (unsigned long)(ins->u.cval));
+ }
+ else if (ins->op == OP_PIECE) {
+ fprintf(fp, "(%p) %c%c%c %-7s %-2d %-10s %-10p <0x%08lx>",
+ ins, pre, post, vol, reg, ins->template_id, tops(ins->op),
MISC(ins, 0), (unsigned long)(ins->u.cval));
}
else {
int i, count;
- fprintf(fp, "(%p) %c%c %-7s %-2d %-10s",
- ins, pre, post, reg, ins->template_id, tops(ins->op));
- count = TRIPLE_SIZE(ins->sizes);
+ fprintf(fp, "(%p) %c%c%c %-7s %-2d %-10s",
+ ins, pre, post, vol, reg, ins->template_id, tops(ins->op));
+ if (table_ops[ins->op].flags & BITFIELD) {
+ fprintf(fp, " <%2d-%2d:%2d>",
+ ins->u.bitfield.offset,
+ ins->u.bitfield.offset + ins->u.bitfield.size,
+ ins->u.bitfield.size);
+ }
+ count = TRIPLE_SIZE(ins);
for(i = 0; i < count; i++) {
fprintf(fp, " %-10p", ins->param[i]);
}
@@ -1852,33 +2517,44 @@ static void display_triple(FILE *fp, struct triple *ins)
fprintf(fp, " ");
}
}
- fprintf(fp, " @");
- for(ptr = ins->occurance; ptr; ptr = ptr->parent) {
- fprintf(fp, " %s,%s:%d.%d",
- ptr->function,
- ptr->filename,
- ptr->line,
- ptr->col);
- }
- fprintf(fp, "\n");
-#if 0
- {
+ if (ins) {
struct triple_set *user;
- for(user = ptr->use; user; user = user->next) {
- fprintf(fp, "use: %p\n", user->member);
+#if DEBUG_DISPLAY_TYPES
+ fprintf(fp, " <");
+ name_of(fp, ins->type);
+ fprintf(fp, "> ");
+#endif
+#if DEBUG_DISPLAY_USES
+ fprintf(fp, " [");
+ for(user = ins->use; user; user = user->next) {
+ fprintf(fp, " %-10p", user->member);
}
- }
+ fprintf(fp, " ]");
#endif
+ fprintf(fp, " @");
+ for(ptr = ins->occurance; ptr; ptr = ptr->parent) {
+ fprintf(fp, " %s,%s:%d.%d",
+ ptr->function,
+ ptr->filename,
+ ptr->line,
+ ptr->col);
+ }
+ if (ins->op == OP_ASM) {
+ fprintf(fp, "\n\t%s", ins->u.ainfo->str);
+ }
+ }
+ fprintf(fp, "\n");
fflush(fp);
}
+static int equiv_types(struct type *left, struct type *right);
static void display_triple_changes(
FILE *fp, const struct triple *new, const struct triple *orig)
{
int new_count, orig_count;
- new_count = TRIPLE_SIZE(new->sizes);
- orig_count = TRIPLE_SIZE(orig->sizes);
+ new_count = TRIPLE_SIZE(new);
+ orig_count = TRIPLE_SIZE(orig);
if ((new->op != orig->op) ||
(new_count != orig_count) ||
(memcmp(orig->param, new->param,
@@ -1887,7 +2563,7 @@ static void display_triple_changes(
{
struct occurance *ptr;
int i, min_count, indent;
- fprintf(fp, "(%p)", orig);
+ fprintf(fp, "(%p %p)", new, orig);
if (orig->op == new->op) {
fprintf(fp, " %-11s", tops(orig->op));
} else {
@@ -1927,6 +2603,17 @@ static void display_triple_changes(
for(;indent < 36; indent++) {
putc(' ', fp);
}
+
+#if DEBUG_DISPLAY_TYPES
+ fprintf(fp, " <");
+ name_of(fp, new->type);
+ if (!equiv_types(new->type, orig->type)) {
+ fprintf(fp, " -- ");
+ name_of(fp, orig->type);
+ }
+ fprintf(fp, "> ");
+#endif
+
fprintf(fp, " @");
for(ptr = orig->occurance; ptr; ptr = ptr->parent) {
fprintf(fp, " %s,%s:%d.%d",
@@ -1941,17 +2628,6 @@ static void display_triple_changes(
}
}
-static void display_func(FILE *fp, struct triple *func)
-{
- struct triple *first, *ins;
- fprintf(fp, "display_func %s\n", func->type->type_ident->name);
- first = ins = RHS(func, 0);
- do {
- display_triple(fp, ins);
- ins = ins->next;
- } while(ins != first);
-}
-
static int triple_is_pure(struct compile_state *state, struct triple *ins, unsigned id)
{
/* Does the triple have no side effects.
@@ -1962,31 +2638,80 @@ static int triple_is_pure(struct compile_state *state, struct triple *ins, unsig
valid_ins(state, ins);
pure = PURE_BITS(table_ops[ins->op].flags);
if ((pure != PURE) && (pure != IMPURE)) {
- internal_error(state, 0, "Purity of %s not known\n",
+ internal_error(state, 0, "Purity of %s not known",
tops(ins->op));
}
return (pure == PURE) && !(id & TRIPLE_FLAG_VOLATILE);
}
+static int triple_is_branch_type(struct compile_state *state,
+ struct triple *ins, unsigned type)
+{
+ /* Is this one of the passed branch types? */
+ valid_ins(state, ins);
+ return (BRANCH_BITS(table_ops[ins->op].flags) == type);
+}
+
static int triple_is_branch(struct compile_state *state, struct triple *ins)
{
/* Is this triple a branch instruction? */
valid_ins(state, ins);
- return (table_ops[ins->op].flags & BRANCH) != 0;
+ return (BRANCH_BITS(table_ops[ins->op].flags) != 0);
}
-static int triple_is_cond_branch(struct compile_state *state, struct triple *ins)
+static int triple_is_cbranch(struct compile_state *state, struct triple *ins)
{
/* Is this triple a conditional branch instruction? */
- valid_ins(state, ins);
- return (table_ops[ins->op].flags & CBRANCH) != 0;
+ return triple_is_branch_type(state, ins, CBRANCH);
}
-static int triple_is_uncond_branch(struct compile_state *state, struct triple *ins)
+static int triple_is_ubranch(struct compile_state *state, struct triple *ins)
{
/* Is this triple a unconditional branch instruction? */
+ unsigned type;
+ valid_ins(state, ins);
+ type = BRANCH_BITS(table_ops[ins->op].flags);
+ return (type != 0) && (type != CBRANCH);
+}
+
+static int triple_is_call(struct compile_state *state, struct triple *ins)
+{
+ /* Is this triple a call instruction? */
+ return triple_is_branch_type(state, ins, CALLBRANCH);
+}
+
+static int triple_is_ret(struct compile_state *state, struct triple *ins)
+{
+ /* Is this triple a return instruction? */
+ return triple_is_branch_type(state, ins, RETBRANCH);
+}
+
+static int triple_is_simple_ubranch(struct compile_state *state, struct triple *ins)
+{
+ /* Is this triple an unconditional branch and not a call or a
+ * return? */
+ return triple_is_branch_type(state, ins, UBRANCH);
+}
+
+static int triple_is_end(struct compile_state *state, struct triple *ins)
+{
+ return triple_is_branch_type(state, ins, ENDBRANCH);
+}
+
+static int triple_is_label(struct compile_state *state, struct triple *ins)
+{
valid_ins(state, ins);
- return (table_ops[ins->op].flags & CBRANCH) == 0;
+ return (ins->op == OP_LABEL);
+}
+
+static struct triple *triple_to_block_start(
+ struct compile_state *state, struct triple *start)
+{
+ while(!triple_is_branch(state, start->prev) &&
+ (!triple_is_label(state, start) || !start->use)) {
+ start = start->prev;
+ }
+ return start;
}
static int triple_is_def(struct compile_state *state, struct triple *ins)
@@ -1997,6 +2722,9 @@ static int triple_is_def(struct compile_state *state, struct triple *ins)
int is_def;
valid_ins(state, ins);
is_def = (table_ops[ins->op].flags & DEF) == DEF;
+ if (ins->lhs >= 1) {
+ is_def = 0;
+ }
return is_def;
}
@@ -2008,6 +2736,19 @@ static int triple_is_structural(struct compile_state *state, struct triple *ins)
return is_structural;
}
+static int triple_is_part(struct compile_state *state, struct triple *ins)
+{
+ int is_part;
+ valid_ins(state, ins);
+ is_part = (table_ops[ins->op].flags & PART) == PART;
+ return is_part;
+}
+
+static int triple_is_auto_var(struct compile_state *state, struct triple *ins)
+{
+ return (ins->op == OP_PIECE) && (MISC(ins, 0)->op == OP_ADECL);
+}
+
static struct triple **triple_iter(struct compile_state *state,
size_t count, struct triple **vector,
struct triple *ins, struct triple **last)
@@ -2029,34 +2770,44 @@ static struct triple **triple_iter(struct compile_state *state,
static struct triple **triple_lhs(struct compile_state *state,
struct triple *ins, struct triple **last)
{
- return triple_iter(state, TRIPLE_LHS(ins->sizes), &LHS(ins,0),
+ return triple_iter(state, ins->lhs, &LHS(ins,0),
ins, last);
}
static struct triple **triple_rhs(struct compile_state *state,
struct triple *ins, struct triple **last)
{
- return triple_iter(state, TRIPLE_RHS(ins->sizes), &RHS(ins,0),
+ return triple_iter(state, ins->rhs, &RHS(ins,0),
ins, last);
}
static struct triple **triple_misc(struct compile_state *state,
struct triple *ins, struct triple **last)
{
- return triple_iter(state, TRIPLE_MISC(ins->sizes), &MISC(ins,0),
+ return triple_iter(state, ins->misc, &MISC(ins,0),
ins, last);
}
-static struct triple **triple_targ(struct compile_state *state,
- struct triple *ins, struct triple **last)
+static struct triple **do_triple_targ(struct compile_state *state,
+ struct triple *ins, struct triple **last, int call_edges, int next_edges)
{
size_t count;
struct triple **ret, **vector;
+ int next_is_targ;
ret = 0;
- count = TRIPLE_TARG(ins->sizes);
+ count = ins->targ;
+ next_is_targ = 0;
+ if (triple_is_cbranch(state, ins)) {
+ next_is_targ = 1;
+ }
+ if (!call_edges && triple_is_call(state, ins)) {
+ count = 0;
+ }
+ if (next_edges && triple_is_call(state, ins)) {
+ next_is_targ = 1;
+ }
vector = &TARG(ins, 0);
- if (!ret &&
- ((ins->op == OP_CALL) || (table_ops[ins->op].flags & CBRANCH))) {
+ if (!ret && next_is_targ) {
if (!last) {
ret = &ins->next;
} else if (last == &ins->next) {
@@ -2074,10 +2825,10 @@ static struct triple **triple_targ(struct compile_state *state,
last = 0;
}
}
- if (!ret && (ins->op == OP_RET)) {
+ if (!ret && triple_is_ret(state, ins) && call_edges) {
struct triple_set *use;
for(use = ins->use; use; use = use->next) {
- if (use->member->op != OP_CALL) {
+ if (!triple_is_call(state, use->member)) {
continue;
}
if (!last) {
@@ -2092,11 +2843,108 @@ static struct triple **triple_targ(struct compile_state *state,
return ret;
}
+static struct triple **triple_targ(struct compile_state *state,
+ struct triple *ins, struct triple **last)
+{
+ return do_triple_targ(state, ins, last, 1, 1);
+}
+
+static struct triple **triple_edge_targ(struct compile_state *state,
+ struct triple *ins, struct triple **last)
+{
+ return do_triple_targ(state, ins, last,
+ state->functions_joined, !state->functions_joined);
+}
+
+static struct triple *after_lhs(struct compile_state *state, struct triple *ins)
+{
+ struct triple *next;
+ int lhs, i;
+ lhs = ins->lhs;
+ next = ins->next;
+ for(i = 0; i < lhs; i++) {
+ struct triple *piece;
+ piece = LHS(ins, i);
+ if (next != piece) {
+ 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);
+ }
+ next = next->next;
+ }
+ return next;
+}
+
+/* Function piece accessor functions */
+static struct triple *do_farg(struct compile_state *state,
+ struct triple *func, unsigned index)
+{
+ struct type *ftype;
+ struct triple *first, *arg;
+ unsigned i;
+
+ ftype = func->type;
+ if((index < 0) || (index >= (ftype->elements + 2))) {
+ internal_error(state, func, "bad argument index: %d", index);
+ }
+ first = RHS(func, 0);
+ arg = first->next;
+ for(i = 0; i < index; i++, arg = after_lhs(state, arg)) {
+ /* do nothing */
+ }
+ if (arg->op != OP_ADECL) {
+ internal_error(state, 0, "arg not adecl?");
+ }
+ return arg;
+}
+static struct triple *fresult(struct compile_state *state, struct triple *func)
+{
+ return do_farg(state, func, 0);
+}
+static struct triple *fretaddr(struct compile_state *state, struct triple *func)
+{
+ return do_farg(state, func, 1);
+}
+static struct triple *farg(struct compile_state *state,
+ struct triple *func, unsigned index)
+{
+ return do_farg(state, func, index + 2);
+}
+
+
+static void display_func(struct compile_state *state, FILE *fp, struct triple *func)
+{
+ struct triple *first, *ins;
+ fprintf(fp, "display_func %s\n", func->type->type_ident->name);
+ first = ins = RHS(func, 0);
+ do {
+ if (triple_is_label(state, ins) && ins->use) {
+ fprintf(fp, "%p:\n", ins);
+ }
+ display_triple(fp, ins);
+
+ if (triple_is_branch(state, ins)) {
+ fprintf(fp, "\n");
+ }
+ if (ins->next->prev != ins) {
+ internal_error(state, ins->next, "bad prev");
+ }
+ ins = ins->next;
+ } while(ins != first);
+}
+
static void verify_use(struct compile_state *state,
struct triple *user, struct triple *used)
{
int size, i;
- size = TRIPLE_SIZE(user->sizes);
+ size = TRIPLE_SIZE(user);
for(i = 0; i < size; i++) {
if (user->param[i] == used) {
break;
@@ -2119,7 +2967,8 @@ static int find_rhs_use(struct compile_state *state,
struct triple **param;
int size, i;
verify_use(state, user, used);
- size = TRIPLE_RHS(user->sizes);
+#warning "AUDIT ME ->rhs"
+ size = user->rhs;
param = &RHS(user, 0);
for(i = 0; i < size; i++) {
if (param[i] == used) {
@@ -2133,7 +2982,7 @@ static void free_triple(struct compile_state *state, struct triple *ptr)
{
size_t size;
size = sizeof(*ptr) - sizeof(ptr->param) +
- (sizeof(ptr->param[0])*TRIPLE_SIZE(ptr->sizes));
+ (sizeof(ptr->param[0])*TRIPLE_SIZE(ptr));
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
if (ptr->use) {
@@ -2149,6 +2998,9 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
struct triple_set *set, *next;
struct triple **expr;
struct block *block;
+ if (ptr == &unknown_triple) {
+ return;
+ }
valid_ins(state, ptr);
/* Make certain the we are not the first or last element of a block */
block = block_of_triple(state, ptr);
@@ -2195,25 +3047,25 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
expr = triple_rhs(state, set->member, 0);
for(; expr; expr = triple_rhs(state, set->member, expr)) {
if (*expr == ptr) {
- *expr = &zero_triple;
+ *expr = &unknown_triple;
}
}
expr = triple_lhs(state, set->member, 0);
for(; expr; expr = triple_lhs(state, set->member, expr)) {
if (*expr == ptr) {
- *expr = &zero_triple;
+ *expr = &unknown_triple;
}
}
expr = triple_misc(state, set->member, 0);
for(; expr; expr = triple_misc(state, set->member, expr)) {
if (*expr == ptr) {
- *expr = &zero_triple;
+ *expr = &unknown_triple;
}
}
expr = triple_targ(state, set->member, 0);
for(; expr; expr = triple_targ(state, set->member, expr)) {
if (*expr == ptr) {
- *expr = &zero_triple;
+ *expr = &unknown_triple;
}
}
unuse_triple(ptr, set->member);
@@ -2339,7 +3191,8 @@ static void print_blocks(struct compile_state *state, const char *func, FILE *fp
#define TOK_FIRST_MACRO TOK_DEFINE
#define TOK_LAST_MACRO TOK_ENDIF
-#define TOK_EOF 111
+#define TOK_DEFINED 111
+#define TOK_EOF 112
static const char *tokens[] = {
[TOK_UNKNOWN ] = "unknown",
@@ -2449,6 +3302,7 @@ static const char *tokens[] = {
[TOK_ELIF ] = "elif",
[TOK_ENDIF ] = "endif",
+[TOK_DEFINED ] = "defined",
[TOK_EOF ] = "EOF",
};
@@ -2530,37 +3384,43 @@ static void hash_keyword(
entry->tok = tok;
}
-static void symbol(
+static void romcc_symbol(
struct compile_state *state, struct hash_entry *ident,
- struct symbol **chain, struct triple *def, struct type *type)
+ struct symbol **chain, struct triple *def, struct type *type, int depth)
{
struct symbol *sym;
- if (*chain && ((*chain)->scope_depth == state->scope_depth)) {
+ if (*chain && ((*chain)->scope_depth >= depth)) {
error(state, 0, "%s already defined", ident->name);
}
sym = xcmalloc(sizeof(*sym), "symbol");
sym->ident = ident;
sym->def = def;
sym->type = type;
- sym->scope_depth = state->scope_depth;
+ sym->scope_depth = depth;
sym->next = *chain;
*chain = sym;
}
-static void label_symbol(struct compile_state *state,
- struct hash_entry *ident, struct triple *label)
+static void symbol(
+ struct compile_state *state, struct hash_entry *ident,
+ struct symbol **chain, struct triple *def, struct type *type)
{
- struct symbol *sym;
- if (ident->sym_label) {
- error(state, 0, "label %s already defined", ident->name);
+ romcc_symbol(state, ident, chain, def, type, state->scope_depth);
+}
+
+static void var_symbol(struct compile_state *state,
+ struct hash_entry *ident, struct triple *def)
+{
+ if ((def->type->type & TYPE_MASK) == TYPE_PRODUCT) {
+ internal_error(state, 0, "bad var type");
}
- sym = xcmalloc(sizeof(*sym), "label");
- sym->ident = ident;
- sym->def = label;
- sym->type = &void_type;
- sym->scope_depth = FUNCTION_SCOPE_DEPTH;
- sym->next = 0;
- ident->sym_label = sym;
+ symbol(state, ident, &ident->sym_ident, def, def->type);
+}
+
+static void label_symbol(struct compile_state *state,
+ struct hash_entry *ident, struct triple *label, int depth)
+{
+ romcc_symbol(state, ident, &ident->sym_label, label, &void_type, depth);
}
static void start_scope(struct compile_state *state)
@@ -2568,7 +3428,8 @@ static void start_scope(struct compile_state *state)
state->scope_depth++;
}
-static void end_scope_syms(struct symbol **chain, int depth)
+static void end_scope_syms(struct compile_state *state,
+ struct symbol **chain, int depth)
{
struct symbol *sym, *next;
sym = *chain;
@@ -2592,9 +3453,9 @@ static void end_scope(struct compile_state *state)
struct hash_entry *entry;
entry = state->hash_table[i];
while(entry) {
- end_scope_syms(&entry->sym_label, depth);
- end_scope_syms(&entry->sym_tag, depth);
- end_scope_syms(&entry->sym_ident, depth);
+ end_scope_syms(state, &entry->sym_label, depth);
+ end_scope_syms(state, &entry->sym_tag, depth);
+ end_scope_syms(state, &entry->sym_ident, depth);
entry = entry->next;
}
}
@@ -2659,6 +3520,140 @@ static void register_macro_keywords(struct compile_state *state)
hash_keyword(state, "endif", TOK_ENDIF);
}
+
+static void undef_macro(struct compile_state *state, struct hash_entry *ident)
+{
+ if (ident->sym_define != 0) {
+ struct macro *macro;
+ struct macro_arg *arg, *anext;
+ macro = ident->sym_define;
+ ident->sym_define = 0;
+
+ /* Free the macro arguments... */
+ anext = macro->args;
+ while(anext) {
+ arg = anext;
+ anext = arg->next;
+ xfree(arg);
+ }
+
+ /* Free the macro buffer */
+ xfree(macro->buf);
+
+ /* Now free the macro itself */
+ xfree(macro);
+ }
+}
+
+static void define_macro(
+ struct compile_state *state,
+ struct hash_entry *ident,
+ const char *value, int value_len, int value_off,
+ struct macro_arg *args)
+{
+ struct macro *macro;
+ struct macro_arg *arg;
+ macro = ident->sym_define;
+ if (macro != 0) {
+ /* Explicitly allow identical redefinitions of the same macro */
+ if ((macro->buf_len == value_len) &&
+ (memcmp(macro->buf, value, value_len))) {
+ return;
+ }
+ error(state, 0, "macro %s already defined\n", ident->name);
+ }
+#if 0
+ fprintf(state->errout, "%s: `%*.*s'\n",
+ ident->name,
+ value_len - value_off,
+ value_len - value_off,
+ value + value_off);
+#endif
+ macro = xmalloc(sizeof(*macro), "macro");
+ macro->ident = ident;
+ macro->buf_len = value_len;
+ macro->buf_off = value_off;
+ macro->args = args;
+ macro->buf = xmalloc(macro->buf_len + 2, "macro buf");
+
+ macro->argc = 0;
+ for(arg = args; arg; arg = arg->next) {
+ macro->argc += 1;
+ }
+
+ memcpy(macro->buf, value, macro->buf_len);
+ macro->buf[macro->buf_len] = '\n';
+ macro->buf[macro->buf_len+1] = '\0';
+
+ ident->sym_define = macro;
+}
+
+static void register_builtin_macro(struct compile_state *state,
+ const char *name, const char *value)
+{
+ struct hash_entry *ident;
+
+ if (value[0] == '(') {
+ internal_error(state, 0, "Builtin macros with arguments not supported");
+ }
+ ident = lookup(state, name, strlen(name));
+ define_macro(state, ident, value, strlen(value), 0, 0);
+}
+
+static void register_builtin_macros(struct compile_state *state)
+{
+ char buf[30];
+ char scratch[30];
+ time_t now;
+ struct tm *tm;
+ now = time(NULL);
+ tm = localtime(&now);
+
+ register_builtin_macro(state, "__ROMCC__", VERSION_MAJOR);
+ register_builtin_macro(state, "__ROMCC_MINOR__", VERSION_MINOR);
+ register_builtin_macro(state, "__FILE__", "\"This should be the filename\"");
+ register_builtin_macro(state, "__LINE__", "54321");
+
+ strftime(scratch, sizeof(scratch), "%b %e %Y", tm);
+ sprintf(buf, "\"%s\"", scratch);
+ register_builtin_macro(state, "__DATE__", buf);
+
+ strftime(scratch, sizeof(scratch), "%H:%M:%S", tm);
+ sprintf(buf, "\"%s\"", scratch);
+ register_builtin_macro(state, "__TIME__", buf);
+
+ /* I can't be a conforming implementation of C :( */
+ register_builtin_macro(state, "__STDC__", "0");
+ /* In particular I don't conform to C99 */
+ register_builtin_macro(state, "__STDC_VERSION__", "199901L");
+
+}
+
+static void process_cmdline_macros(struct compile_state *state)
+{
+ const char **macro, *name;
+ struct hash_entry *ident;
+ for(macro = state->compiler->defines; (name = *macro); macro++) {
+ const char *body;
+ size_t name_len;
+
+ name_len = strlen(name);
+ body = strchr(name, '=');
+ if (!body) {
+ body = "\0";
+ } else {
+ name_len = body - name;
+ body++;
+ }
+ ident = lookup(state, name, name_len);
+ define_macro(state, ident, body, strlen(body), 0, 0);
+ }
+ for(macro = state->compiler->undefs; (name = *macro); macro++) {
+ ident = lookup(state, name, strlen(name));
+ undef_macro(state, ident);
+ }
+}
+
static int spacep(int c)
{
int ret = 0;
@@ -2766,6 +3761,20 @@ static int letterp(int c)
return ret;
}
+static const char *identifier(const char *str, const char *end)
+{
+ if (letterp(*str)) {
+ for(; str < end; str++) {
+ int c;
+ c = *str;
+ if (!letterp(c) && !digitp(c)) {
+ break;
+ }
+ }
+ }
+ return str;
+}
+
static int char_value(struct compile_state *state,
const signed char **strp, const signed char *end)
{
@@ -2785,7 +3794,7 @@ static int char_value(struct compile_state *state,
case '\\': c = '\\'; str++; break;
case '?': c = '?'; str++; break;
case '\'': c = '\''; str++; break;
- case '"': c = '"'; break;
+ case '"': c = '"'; str++; break;
case 'x':
c = 0;
str++;
@@ -2813,7 +3822,7 @@ static int char_value(struct compile_state *state,
return c;
}
-static char *after_digits(char *ptr, char *end)
+static const char *after_digits(const char *ptr, const char *end)
{
while((ptr < end) && digitp(*ptr)) {
ptr++;
@@ -2821,7 +3830,7 @@ static char *after_digits(char *ptr, char *end)
return ptr;
}
-static char *after_octdigits(char *ptr, char *end)
+static const char *after_octdigits(const char *ptr, const char *end)
{
while((ptr < end) && octdigitp(*ptr)) {
ptr++;
@@ -2829,7 +3838,7 @@ static char *after_octdigits(char *ptr, char *end)
return ptr;
}
-static char *after_hexdigits(char *ptr, char *end)
+static const char *after_hexdigits(const char *ptr, const char *end)
{
while((ptr < end) && hexdigitp(*ptr)) {
ptr++;
@@ -2838,7 +3847,7 @@ static char *after_hexdigits(char *ptr, char *end)
}
static void save_string(struct compile_state *state,
- struct token *tk, char *start, char *end, const char *id)
+ struct token *tk, const char *start, const char *end, const char *id)
{
char *str;
int str_len;
@@ -2852,17 +3861,27 @@ static void save_string(struct compile_state *state,
tk->val.str = str;
tk->str_len = str_len;
}
-static void next_token(struct compile_state *state, int index)
+
+static int lparen_peek(struct compile_state *state, struct file_state *file)
{
- struct file_state *file;
- struct token *tk;
- char *token;
+ const char *tokp, *end;
+ /* Is the next token going to be an lparen?
+ * Whitespace tokens are significant for seeing if a macro
+ * should be expanded.
+ */
+ tokp = file->pos;
+ end = file->buf + file->size;
+ return (tokp < end) && (*tokp == '(');
+}
+
+static void raw_next_token(struct compile_state *state,
+ struct file_state *file, struct token *tk)
+{
+ const char *token;
int c, c1, c2, c3;
- char *tokp, *end;
+ const char *tokp, *end;
int tok;
-next_token:
- file = state->file;
- tk = &state->token[index];
+
tk->str_len = 0;
tk->ident = 0;
token = tokp = file->pos;
@@ -2919,7 +3938,7 @@ next_token:
/* Comments */
else if ((c == '/') && (c1 == '*')) {
int line;
- char *line_start;
+ const char *line_start;
line = file->line;
line_start = file->line_start;
for(tokp += 2; (end - tokp) >= 2; tokp++) {
@@ -2945,7 +3964,7 @@ next_token:
else if ((c == '"') ||
((c == 'L') && (c1 == '"'))) {
int line;
- char *line_start;
+ const char *line_start;
int wchar;
line = file->line;
line_start = file->line_start;
@@ -2985,7 +4004,7 @@ next_token:
else if ((c == '\'') ||
((c == 'L') && (c1 == '\''))) {
int line;
- char *line_start;
+ const char *line_start;
int wchar;
line = file->line;
line_start = file->line_start;
@@ -3036,7 +4055,7 @@ next_token:
*/
else if (digitp(c) || ((c == '.') && (digitp(c1)))) {
- char *next, *new;
+ const char *next, *new;
int is_float;
is_float = 0;
if (c != '.') {
@@ -3107,14 +4126,15 @@ next_token:
/* identifiers */
else if (letterp(c)) {
tok = TOK_IDENT;
- for(tokp += 1; tokp < end; tokp++) {
- c = *tokp;
- if (!letterp(c) && !digitp(c)) {
- break;
- }
- }
+ tokp = identifier(tokp, end);
tokp -= 1;
tk->ident = lookup(state, token, tokp +1 - token);
+ /* See if this identifier can be macro expanded */
+ tk->val.notmacro = 0;
+ if ((tokp < end) && (tokp[1] == '$')) {
+ tokp++;
+ tk->val.notmacro = 1;
+ }
}
/* C99 alternate macro characters */
else if ((c == '%') && (c1 == ':') && (c2 == '%') && (c3 == ':')) {
@@ -3174,51 +4194,469 @@ next_token:
else if (c == '.') { tok = TOK_DOT; }
else if (c == '~') { tok = TOK_TILDE; }
else if (c == '#') { tok = TOK_MACRO; }
- if (tok == TOK_MACRO) {
- /* Only match preprocessor directives at the start of a line */
- char *ptr;
- for(ptr = file->line_start; spacep(*ptr); ptr++)
- ;
- if (ptr != tokp) {
- tok = TOK_UNKNOWN;
- }
- }
- if (tok == TOK_UNKNOWN) {
- error(state, 0, "unknown token");
- }
file->pos = tokp + 1;
tk->tok = tok;
if (tok == TOK_IDENT) {
ident_to_keyword(state, tk);
}
+}
+
+static void next_token(struct compile_state *state, struct token *tk)
+{
+ struct file_state *file;
+ file = state->file;
/* Don't return space tokens. */
- if (tok == TOK_SPACE) {
- goto next_token;
+ do {
+ raw_next_token(state, file, tk);
+ if (tk->tok == TOK_MACRO) {
+ /* Only match preprocessor directives at the start of a line */
+ const char *ptr;
+ for(ptr = file->line_start; spacep(*ptr); ptr++)
+ ;
+ if (ptr != file->pos - 1) {
+ tk->tok = TOK_UNKNOWN;
+ }
+ }
+ if (tk->tok == TOK_UNKNOWN) {
+ error(state, 0, "unknown token");
+ }
+ } while(tk->tok == TOK_SPACE);
+}
+
+static void check_tok(struct compile_state *state, struct token *tk, int tok)
+{
+ if (tk->tok != tok) {
+ const char *name1, *name2;
+ name1 = tokens[tk->tok];
+ name2 = "";
+ if (tk->tok == TOK_IDENT) {
+ name2 = tk->ident->name;
+ }
+ error(state, 0, "\tfound %s %s expected %s",
+ name1, name2, tokens[tok]);
+ }
+}
+
+struct macro_arg_value {
+ struct hash_entry *ident;
+ unsigned char *value;
+ size_t len;
+};
+static struct macro_arg_value *read_macro_args(
+ struct compile_state *state, struct macro *macro,
+ struct file_state *file, struct token *tk)
+{
+ struct macro_arg_value *argv;
+ struct macro_arg *arg;
+ int paren_depth;
+ int i;
+
+ if (macro->argc == 0) {
+ do {
+ raw_next_token(state, file, tk);
+ } while(tk->tok == TOK_SPACE);
+ return 0;
+ }
+ argv = xcmalloc(sizeof(*argv) * macro->argc, "macro args");
+ for(i = 0, arg = macro->args; arg; arg = arg->next, i++) {
+ argv[i].value = 0;
+ argv[i].len = 0;
+ argv[i].ident = arg->ident;
+ }
+ paren_depth = 0;
+ i = 0;
+
+ for(;;) {
+ const char *start;
+ size_t len;
+ start = file->pos;
+ raw_next_token(state, file, tk);
+
+ if (!paren_depth && (tk->tok == TOK_COMMA) &&
+ (argv[i].ident != state->i___VA_ARGS__))
+ {
+ i++;
+ if (i >= macro->argc) {
+ error(state, 0, "too many args to %s\n",
+ macro->ident->name);
+ }
+ continue;
+ }
+
+ if (tk->tok == TOK_LPAREN) {
+ paren_depth++;
+ }
+
+ if (tk->tok == TOK_RPAREN) {
+ if (paren_depth == 0) {
+ break;
+ }
+ paren_depth--;
+ }
+ if (tk->tok == TOK_EOF) {
+ error(state, 0, "End of file encountered while parsing macro arguments");
+ }
+
+ len = file->pos - start;
+ argv[i].value = xrealloc(
+ argv[i].value, argv[i].len + len, "macro args");
+ memcpy(argv[i].value + argv[i].len, start, len);
+ argv[i].len += len;
+ }
+ if (i != macro->argc -1) {
+ error(state, 0, "missing %s arg %d\n",
+ macro->ident->name, i +2);
+ }
+ return argv;
+}
+
+
+static void free_macro_args(struct macro *macro, struct macro_arg_value *argv)
+{
+ int i;
+ for(i = 0; i < macro->argc; i++) {
+ xfree(argv[i].value);
+ }
+ xfree(argv);
+}
+
+struct macro_buf {
+ char *str;
+ size_t len, pos;
+};
+
+static void append_macro_text(struct compile_state *state,
+ struct macro *macro, struct macro_buf *buf,
+ const char *fstart, size_t flen)
+{
+#if 0
+ fprintf(state->errout, "append: `%*.*s' `%*.*s'\n",
+ buf->pos, buf->pos, buf->str,
+ flen, flen, fstart);
+#endif
+ if ((buf->pos + flen) < buf->len) {
+ memcpy(buf->str + buf->pos, fstart, flen);
+ } else {
+ buf->str = xrealloc(buf->str, buf->len + flen, macro->ident->name);
+ memcpy(buf->str + buf->pos, fstart, flen);
+ buf->len += flen;
+ }
+ buf->pos += flen;
+}
+
+static int compile_macro(struct compile_state *state,
+ struct file_state **filep, struct token *tk);
+
+static void macro_expand_args(struct compile_state *state,
+ struct macro *macro, struct macro_arg_value *argv, struct token *tk)
+{
+ size_t i;
+
+ for(i = 0; i < macro->argc; i++) {
+ struct file_state fmacro, *file;
+ struct macro_buf buf;
+ const char *fstart;
+ size_t flen;
+
+ fmacro.basename = argv[i].ident->name;
+ fmacro.dirname = "";
+ fmacro.size = argv[i].len;
+ fmacro.buf = argv[i].value;
+ fmacro.pos = fmacro.buf;
+ fmacro.line_start = fmacro.buf;
+ fmacro.line = 1;
+ fmacro.report_line = 1;
+ fmacro.report_name = fmacro.basename;
+ fmacro.report_dir = fmacro.dirname;
+ fmacro.prev = 0;
+
+ buf.len = argv[i].len;
+ buf.str = xmalloc(buf.len, argv[i].ident->name);
+ buf.pos = 0;
+
+ file = &fmacro;
+ for(;;) {
+ fstart = file->pos;
+ raw_next_token(state, file, tk);
+ flen = file->pos - fstart;
+
+ if (tk->tok == TOK_EOF) {
+ struct file_state *old;
+ old = file;
+ file = file->prev;
+ if (!file) {
+ break;
+ }
+ /* old->basename is used keep it */
+ xfree(old->dirname);
+ xfree(old->buf);
+ xfree(old);
+ continue;
+ }
+ else if (tk->ident && tk->ident->sym_define) {
+ if (compile_macro(state, &file, tk)) {
+ continue;
+ }
+ }
+
+ append_macro_text(state, macro, &buf,
+ fstart, flen);
+ }
+
+ xfree(argv[i].value);
+ argv[i].value = buf.str;
+ argv[i].len = buf.pos;
+ }
+ return;
+}
+
+static void expand_macro(struct compile_state *state,
+ struct macro *macro, struct macro_buf *buf,
+ struct macro_arg_value *argv, struct token *tk)
+{
+ struct file_state fmacro;
+ const char space[] = " ";
+ const char *fstart;
+ size_t flen;
+ size_t i, j;
+ fmacro.basename = macro->ident->name;
+ fmacro.dirname = "";
+ fmacro.size = macro->buf_len - macro->buf_off;;
+ fmacro.buf = macro->buf + macro->buf_off;
+ fmacro.pos = fmacro.buf;
+ fmacro.line_start = fmacro.buf;
+ fmacro.line = 1;
+ fmacro.report_line = 1;
+ fmacro.report_name = fmacro.basename;
+ fmacro.report_dir = fmacro.dirname;
+ fmacro.prev = 0;
+
+ buf->len = macro->buf_len + 3;
+ buf->str = xmalloc(buf->len, macro->ident->name);
+ buf->pos = 0;
+
+ fstart = fmacro.pos;
+ raw_next_token(state, &fmacro, tk);
+ while(tk->tok != TOK_EOF) {
+ flen = fmacro.pos - fstart;
+ switch(tk->tok) {
+ case TOK_IDENT:
+ for(i = 0; i < macro->argc; i++) {
+ if (argv[i].ident == tk->ident) {
+ break;
+ }
+ }
+ if (i >= macro->argc) {
+ break;
+ }
+ /* Substitute macro parameter */
+ fstart = argv[i].value;
+ flen = argv[i].len;
+ break;
+ case TOK_MACRO:
+ if (!macro->buf_off) {
+ break;
+ }
+ do {
+ raw_next_token(state, &fmacro, tk);
+ } while(tk->tok == TOK_SPACE);
+ check_tok(state, tk, TOK_IDENT);
+ for(i = 0; i < macro->argc; i++) {
+ if (argv[i].ident == tk->ident) {
+ break;
+ }
+ }
+ if (i >= macro->argc) {
+ error(state, 0, "parameter `%s' not found",
+ tk->ident->name);
+ }
+ /* Stringize token */
+ append_macro_text(state, macro, buf, "\"", 1);
+ for(j = 0; j < argv[i].len; j++) {
+ char *str = argv[i].value + j;
+ size_t len = 1;
+ if (*str == '\\') {
+ str = "\\";
+ len = 2;
+ }
+ else if (*str == '"') {
+ str = "\\\"";
+ len = 2;
+ }
+ append_macro_text(state, macro, buf, str, len);
+ }
+ append_macro_text(state, macro, buf, "\"", 1);
+ fstart = 0;
+ flen = 0;
+ break;
+ case TOK_CONCATENATE:
+ /* Concatenate tokens */
+ /* Delete the previous whitespace token */
+ if (buf->str[buf->pos - 1] == ' ') {
+ buf->pos -= 1;
+ }
+ /* Skip the next sequence of whitspace tokens */
+ do {
+ fstart = fmacro.pos;
+ raw_next_token(state, &fmacro, tk);
+ } while(tk->tok == TOK_SPACE);
+ /* Restart at the top of the loop.
+ * I need to process the non white space token.
+ */
+ continue;
+ break;
+ case TOK_SPACE:
+ /* Collapse multiple spaces into one */
+ if (buf->str[buf->pos - 1] != ' ') {
+ fstart = space;
+ flen = 1;
+ } else {
+ fstart = 0;
+ flen = 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ append_macro_text(state, macro, buf, fstart, flen);
+
+ fstart = fmacro.pos;
+ raw_next_token(state, &fmacro, tk);
}
}
-static void compile_macro(struct compile_state *state, struct token *tk)
+static void tag_macro_name(struct compile_state *state,
+ struct macro *macro, struct macro_buf *buf,
+ struct token *tk)
+{
+ /* Guard all instances of the macro name in the replacement
+ * text from further macro expansion.
+ */
+ struct file_state fmacro;
+ const char *fstart;
+ size_t flen;
+ fmacro.basename = macro->ident->name;
+ fmacro.dirname = "";
+ fmacro.size = buf->pos;
+ fmacro.buf = buf->str;
+ fmacro.pos = fmacro.buf;
+ fmacro.line_start = fmacro.buf;
+ fmacro.line = 1;
+ fmacro.report_line = 1;
+ fmacro.report_name = fmacro.basename;
+ fmacro.report_dir = fmacro.dirname;
+ fmacro.prev = 0;
+
+ buf->len = macro->buf_len + 3;
+ buf->str = xmalloc(buf->len, macro->ident->name);
+ buf->pos = 0;
+
+ fstart = fmacro.pos;
+ raw_next_token(state, &fmacro, tk);
+ while(tk->tok != TOK_EOF) {
+ flen = fmacro.pos - fstart;
+ if ((tk->tok == TOK_IDENT) &&
+ (tk->ident == macro->ident) &&
+ (tk->val.notmacro == 0)) {
+ append_macro_text(state, macro, buf, fstart, flen);
+ fstart = "$";
+ flen = 1;
+ }
+
+ append_macro_text(state, macro, buf, fstart, flen);
+
+ fstart = fmacro.pos;
+ raw_next_token(state, &fmacro, tk);
+ }
+ xfree(fmacro.buf);
+}
+
+static int compile_macro(struct compile_state *state,
+ struct file_state **filep, struct token *tk)
{
struct file_state *file;
struct hash_entry *ident;
+ struct macro *macro;
+ struct macro_arg_value *argv;
+ struct macro_buf buf;
+
+#if 0
+ fprintf(state->errout, "macro: %s\n", tk->ident->name);
+#endif
ident = tk->ident;
+ macro = ident->sym_define;
+
+ /* If this token comes from a macro expansion ignore it */
+ if (tk->val.notmacro) {
+ return 0;
+ }
+ /* If I am a function like macro and the identifier is not followed
+ * by a left parenthesis, do nothing.
+ */
+ if ((macro->buf_off != 0) && !lparen_peek(state, *filep)) {
+ return 0;
+ }
+
+ /* Read in the macro arguments */
+ argv = 0;
+ if (macro->buf_off) {
+ raw_next_token(state, *filep, tk);
+ check_tok(state, tk, TOK_LPAREN);
+
+ argv = read_macro_args(state, macro, *filep, tk);
+
+ check_tok(state, tk, TOK_RPAREN);
+ }
+ /* Macro expand the macro arguments */
+ macro_expand_args(state, macro, argv, tk);
+
+ buf.str = 0;
+ buf.len = 0;
+ buf.pos = 0;
+ if (ident == state->i___FILE__) {
+ buf.len = strlen(state->file->basename) + 1 + 2 + 3;
+ buf.str = xmalloc(buf.len, ident->name);
+ sprintf(buf.str, "\"%s\"", state->file->basename);
+ buf.pos = strlen(buf.str);
+ }
+ else if (ident == state->i___LINE__) {
+ buf.len = 30;
+ buf.str = xmalloc(buf.len, ident->name);
+ sprintf(buf.str, "%d", state->file->line);
+ buf.pos = strlen(buf.str);
+ }
+ else {
+ expand_macro(state, macro, &buf, argv, tk);
+ }
+ /* Tag the macro name with a $ so it will no longer
+ * be regonized as a canidate for macro expansion.
+ */
+ tag_macro_name(state, macro, &buf, tk);
+ append_macro_text(state, macro, &buf, "\n\0", 2);
+
+#if 0
+ fprintf(state->errout, "%s: %d -> `%*.*s'\n",
+ ident->name, buf.pos, buf.pos, (int)(buf.pos), buf.str);
+#endif
+
+ free_macro_args(macro, argv);
+
file = xmalloc(sizeof(*file), "file_state");
- file->basename = xstrdup(tk->ident->name);
+ file->basename = xstrdup(ident->name);
file->dirname = xstrdup("");
- file->size = ident->sym_define->buf_len;
- file->buf = xmalloc(file->size +2, file->basename);
- memcpy(file->buf, ident->sym_define->buf, file->size);
- file->buf[file->size] = '\n';
- file->buf[file->size + 1] = '\0';
+ file->buf = buf.str;
+ file->size = buf.pos - 2;
file->pos = file->buf;
file->line_start = file->pos;
file->line = 1;
file->report_line = 1;
file->report_name = file->basename;
file->report_dir = file->dirname;
- file->prev = state->file;
- state->file = file;
+ file->prev = *filep;
+ *filep = file;
+ return 1;
}
@@ -3228,7 +4666,9 @@ static int mpeek(struct compile_state *state, int index)
int rescan;
tk = &state->token[index + 1];
if (tk->tok == -1) {
- next_token(state, index + 1);
+ do {
+ raw_next_token(state, state->file, tk);
+ } while(tk->tok == TOK_SPACE);
}
do {
rescan = 0;
@@ -3244,37 +4684,90 @@ static int mpeek(struct compile_state *state, int index)
xfree(file->dirname);
xfree(file->buf);
xfree(file);
- next_token(state, index + 1);
+ next_token(state, tk);
rescan = 1;
}
else if (tk->ident && tk->ident->sym_define) {
- compile_macro(state, tk);
- next_token(state, index + 1);
- rescan = 1;
+ rescan = compile_macro(state, &state->file, tk);
+ if (rescan) {
+ next_token(state, tk);
+ }
+
}
} while(rescan);
/* Don't show the token on the next line */
if (state->macro_line < state->macro_file->line) {
return TOK_EOF;
}
- return state->token[index +1].tok;
+ return tk->tok;
}
static void meat(struct compile_state *state, int index, int tok)
{
- int next_tok;
int i;
+ int next_tok;
next_tok = mpeek(state, index);
if (next_tok != tok) {
- const char *name1, *name2;
- name1 = tokens[next_tok];
- name2 = "";
- if (next_tok == TOK_IDENT) {
- name2 = state->token[index + 1].ident->name;
+ check_tok(state, &state->token[index + 1], tok);
+ }
+
+ /* Free the old token value */
+ if (state->token[index].str_len) {
+ memset((void *)(state->token[index].val.str), -1,
+ state->token[index].str_len);
+ xfree(state->token[index].val.str);
+ }
+ for(i = index; i < sizeof(state->token)/sizeof(state->token[0]) - 1; i++) {
+ state->token[i] = state->token[i + 1];
+ }
+ memset(&state->token[i], 0, sizeof(state->token[i]));
+ state->token[i].tok = -1;
+}
+
+static int mpeek_raw(struct compile_state *state, int index)
+{
+ struct token *tk;
+ int rescan;
+ tk = &state->token[index + 1];
+ if (tk->tok == -1) {
+ do {
+ raw_next_token(state, state->file, tk);
+ } while(tk->tok == TOK_SPACE);
+ }
+ do {
+ rescan = 0;
+ if ((tk->tok == TOK_EOF) &&
+ (state->file != state->macro_file) &&
+ (state->file->prev)) {
+ struct file_state *file = state->file;
+ state->file = file->prev;
+ /* file->basename is used keep it */
+ if (file->report_dir != file->dirname) {
+ xfree(file->report_dir);
+ }
+ xfree(file->dirname);
+ xfree(file->buf);
+ xfree(file);
+ next_token(state, tk);
+ rescan = 1;
}
- error(state, 0, "found %s %s expected %s",
- name1, name2, tokens[tok]);
+ } while(rescan);
+ /* Don't show the token on the next line */
+ if (state->macro_line < state->macro_file->line) {
+ return TOK_EOF;
}
+ return tk->tok;
+}
+
+static void meat_raw(struct compile_state *state, int index, int tok)
+{
+ int next_tok;
+ int i;
+ next_tok = mpeek_raw(state, index);
+ if (next_tok != tok) {
+ check_tok(state, &state->token[index + 1], tok);
+ }
+
/* Free the old token value */
if (state->token[index].str_len) {
memset((void *)(state->token[index].val.str), -1,
@@ -3295,12 +4788,6 @@ static long_t mprimary_expr(struct compile_state *state, int index)
long_t val;
int tok;
tok = mpeek(state, index);
- while(state->token[index + 1].ident &&
- state->token[index + 1].ident->sym_define) {
- meat(state, index, tok);
- compile_macro(state, &state->token[index]);
- tok = mpeek(state, index);
- }
switch(tok) {
case TOK_LPAREN:
meat(state, index, TOK_LPAREN);
@@ -3331,7 +4818,13 @@ static long_t mprimary_expr(struct compile_state *state, int index)
static long_t munary_expr(struct compile_state *state, int index)
{
long_t val;
- switch(mpeek(state, index)) {
+ int tok;
+ tok = mpeek(state, index);
+ if ((tok == TOK_IDENT) &&
+ (state->token[index + 1].ident == state->i_defined)) {
+ tok = TOK_DEFINED;
+ }
+ switch(tok) {
case TOK_PLUS:
meat(state, index, TOK_PLUS);
val = munary_expr(state, index);
@@ -3352,6 +4845,24 @@ static long_t munary_expr(struct compile_state *state, int index)
val = munary_expr(state, index);
val = ! val;
break;
+ case TOK_DEFINED:
+ {
+ struct hash_entry *ident;
+ int parens;
+ meat(state, index, TOK_IDENT);
+ parens = 0;
+ if (mpeek_raw(state, index) == TOK_LPAREN) {
+ meat(state, index, TOK_LPAREN);
+ parens = 1;
+ }
+ meat_raw(state, index, TOK_IDENT);
+ ident = state->token[index].ident;
+ val = ident->sym_define != 0;
+ if (parens) {
+ meat(state, index, TOK_RPAREN);
+ }
+ break;
+ }
default:
val = mprimary_expr(state, index);
break;
@@ -3516,7 +5027,7 @@ static long_t mand_expr(struct compile_state *state, int index)
{
long_t val;
val = meq_expr(state, index);
- if (mpeek(state, index) == TOK_AND) {
+ while (mpeek(state, index) == TOK_AND) {
long_t right;
meat(state, index, TOK_AND);
right = meq_expr(state, index);
@@ -3529,7 +5040,7 @@ static long_t mxor_expr(struct compile_state *state, int index)
{
long_t val;
val = mand_expr(state, index);
- if (mpeek(state, index) == TOK_XOR) {
+ while (mpeek(state, index) == TOK_XOR) {
long_t right;
meat(state, index, TOK_XOR);
right = mand_expr(state, index);
@@ -3542,7 +5053,7 @@ static long_t mor_expr(struct compile_state *state, int index)
{
long_t val;
val = mxor_expr(state, index);
- if (mpeek(state, index) == TOK_OR) {
+ while (mpeek(state, index) == TOK_OR) {
long_t right;
meat(state, index, TOK_OR);
right = mxor_expr(state, index);
@@ -3555,7 +5066,7 @@ static long_t mland_expr(struct compile_state *state, int index)
{
long_t val;
val = mor_expr(state, index);
- if (mpeek(state, index) == TOK_LOGAND) {
+ while (mpeek(state, index) == TOK_LOGAND) {
long_t right;
meat(state, index, TOK_LOGAND);
right = mor_expr(state, index);
@@ -3567,7 +5078,7 @@ static long_t mlor_expr(struct compile_state *state, int index)
{
long_t val;
val = mland_expr(state, index);
- if (mpeek(state, index) == TOK_LOGOR) {
+ while (mpeek(state, index) == TOK_LOGOR) {
long_t right;
meat(state, index, TOK_LOGOR);
right = mland_expr(state, index);
@@ -3580,6 +5091,78 @@ static long_t mcexpr(struct compile_state *state, int index)
{
return mlor_expr(state, index);
}
+
+static void eat_tokens(struct compile_state *state, int targ_tok)
+{
+ if (state->eat_depth > 0) {
+ internal_error(state, 0, "Already eating...");
+ }
+ state->eat_depth = state->if_depth;
+ state->eat_targ = targ_tok;
+}
+static int if_eat(struct compile_state *state)
+{
+ return state->eat_depth > 0;
+}
+static int if_value(struct compile_state *state)
+{
+ int index, offset;
+ index = state->if_depth / CHAR_BIT;
+ offset = state->if_depth % CHAR_BIT;
+ return !!(state->if_bytes[index] & (1 << (offset)));
+}
+static void set_if_value(struct compile_state *state, int value)
+{
+ int index, offset;
+ index = state->if_depth / CHAR_BIT;
+ offset = state->if_depth % CHAR_BIT;
+
+ state->if_bytes[index] &= ~(1 << offset);
+ if (value) {
+ state->if_bytes[index] |= (1 << offset);
+ }
+}
+static void in_if(struct compile_state *state, const char *name)
+{
+ if (state->if_depth <= 0) {
+ error(state, 0, "%s without #if", name);
+ }
+}
+static void enter_if(struct compile_state *state)
+{
+ state->if_depth += 1;
+ if (state->if_depth > MAX_CPP_IF_DEPTH) {
+ error(state, 0, "#if depth too great");
+ }
+}
+static void reenter_if(struct compile_state *state, const char *name)
+{
+ in_if(state, name);
+ if ((state->eat_depth == state->if_depth) &&
+ (state->eat_targ == TOK_ELSE)) {
+ state->eat_depth = 0;
+ state->eat_targ = 0;
+ }
+}
+static void enter_else(struct compile_state *state, const char *name)
+{
+ in_if(state, name);
+ if ((state->eat_depth == state->if_depth) &&
+ (state->eat_targ == TOK_ELSE)) {
+ state->eat_depth = 0;
+ state->eat_targ = 0;
+ }
+}
+static void exit_if(struct compile_state *state, const char *name)
+{
+ in_if(state, name);
+ if (state->eat_depth == state->if_depth) {
+ state->eat_depth = 0;
+ state->eat_targ = 0;
+ }
+ state->if_depth -= 1;
+}
+
static void preprocess(struct compile_state *state, int index)
{
/* Doing much more with the preprocessor would require
@@ -3596,7 +5179,7 @@ static void preprocess(struct compile_state *state, int index)
state->macro_line = line = file->line;
state->macro_file = file;
- next_token(state, index);
+ next_token(state, tk);
ident_to_macro(state, tk);
if (tk->tok == TOK_IDENT) {
error(state, 0, "undefined preprocessing directive `%s'",
@@ -3607,7 +5190,7 @@ static void preprocess(struct compile_state *state, int index)
{
int override_line;
override_line = strtoul(tk->val.str, 0, 10);
- next_token(state, index);
+ next_token(state, tk);
/* I have a cpp line marker parse it */
if (tk->tok == TOK_LIT_STRING) {
const char *token, *base;
@@ -3634,10 +5217,9 @@ static void preprocess(struct compile_state *state, int index)
file->report_name = name;
file->report_dir = dir;
}
- }
break;
+ }
case TOK_LINE:
- meat(state, index, TOK_LINE);
meat(state, index, TOK_LIT_INT);
file->report_line = strtoul(tk->val.str, 0, 10) -1;
if (mpeek(state, index) == TOK_LIT_STRING) {
@@ -3667,152 +5249,184 @@ static void preprocess(struct compile_state *state, int index)
}
break;
case TOK_UNDEF:
+ {
+ struct hash_entry *ident;
+ if (if_eat(state)) /* quit early when #if'd out */
+ break;
+
+ meat_raw(state, index, TOK_IDENT);
+ ident = tk->ident;
+
+ undef_macro(state, ident);
+ break;
+ }
case TOK_PRAGMA:
- if (state->if_value < 0) {
+ if (if_eat(state)) /* quit early when #if'd out */
break;
- }
warning(state, 0, "Ignoring preprocessor directive: %s",
tk->ident->name);
break;
case TOK_ELIF:
- error(state, 0, "#elif not supported");
-#warning "FIXME multiple #elif and #else in an #if do not work properly"
- if (state->if_depth == 0) {
- error(state, 0, "#elif without #if");
- }
+ reenter_if(state, "#elif");
+ if (if_eat(state)) /* quit early when #if'd out */
+ break;
/* If the #if was taken the #elif just disables the following code */
- if (state->if_value >= 0) {
- state->if_value = - state->if_value;
+ if (if_value(state)) {
+ eat_tokens(state, TOK_ENDIF);
}
/* If the previous #if was not taken see if the #elif enables the
* trailing code.
*/
- else if ((state->if_value < 0) &&
- (state->if_depth == - state->if_value))
- {
- if (mcexpr(state, index) != 0) {
- state->if_value = state->if_depth;
- }
- else {
- state->if_value = - state->if_depth;
+ else {
+ set_if_value(state, mcexpr(state, index) != 0);
+ if (!if_value(state)) {
+ eat_tokens(state, TOK_ELSE);
}
}
break;
case TOK_IF:
- state->if_depth++;
- if (state->if_value < 0) {
+ enter_if(state);
+ if (if_eat(state)) /* quit early when #if'd out */
break;
- }
- if (mcexpr(state, index) != 0) {
- state->if_value = state->if_depth;
- }
- else {
- state->if_value = - state->if_depth;
+ set_if_value(state, mcexpr(state, index) != 0);
+ if (!if_value(state)) {
+ eat_tokens(state, TOK_ELSE);
}
break;
case TOK_IFNDEF:
- state->if_depth++;
- if (state->if_value < 0) {
+ enter_if(state);
+ if (if_eat(state)) /* quit early when #if'd out */
break;
- }
- next_token(state, index);
+ next_token(state, tk);
if ((line != file->line) || (tk->tok != TOK_IDENT)) {
error(state, 0, "Invalid macro name");
}
- if (tk->ident->sym_define == 0) {
- state->if_value = state->if_depth;
- }
- else {
- state->if_value = - state->if_depth;
+ set_if_value(state, tk->ident->sym_define == 0);
+ if (!if_value(state)) {
+ eat_tokens(state, TOK_ELSE);
}
break;
case TOK_IFDEF:
- state->if_depth++;
- if (state->if_value < 0) {
+ enter_if(state);
+ if (if_eat(state)) /* quit early when #if'd out */
break;
- }
- next_token(state, index);
+ next_token(state, tk);
if ((line != file->line) || (tk->tok != TOK_IDENT)) {
error(state, 0, "Invalid macro name");
}
- if (tk->ident->sym_define != 0) {
- state->if_value = state->if_depth;
- }
- else {
- state->if_value = - state->if_depth;
+ set_if_value(state, tk->ident->sym_define != 0);
+ if (!if_value(state)) {
+ eat_tokens(state, TOK_ELSE);
}
break;
case TOK_ELSE:
- if (state->if_depth == 0) {
- error(state, 0, "#else without #if");
- }
- if ((state->if_value >= 0) ||
- ((state->if_value < 0) &&
- (state->if_depth == -state->if_value)))
- {
- state->if_value = - state->if_value;
+ enter_else(state, "#else");
+ if (!if_eat(state) && if_value(state)) {
+ eat_tokens(state, TOK_ENDIF);
}
break;
case TOK_ENDIF:
- if (state->if_depth == 0) {
- error(state, 0, "#endif without #if");
- }
- if ((state->if_value >= 0) ||
- ((state->if_value < 0) &&
- (state->if_depth == -state->if_value)))
- {
- state->if_value = state->if_depth - 1;
- }
- state->if_depth--;
+ exit_if(state, "#endif");
break;
case TOK_DEFINE:
{
struct hash_entry *ident;
- struct macro *macro;
- char *ptr;
-
- if (state->if_value < 0) /* quit early when #if'd out */
+ struct macro_arg *args, **larg;
+ const char *start, *mstart, *ptr;
+
+ if (if_eat(state)) /* quit early when #if'd out */
break;
- meat(state, index, TOK_IDENT);
+ meat_raw(state, index, TOK_IDENT);
ident = tk->ident;
-
+ args = 0;
+ larg = &args;
- if (*file->pos == '(') {
-#warning "FIXME macros with arguments not supported"
- error(state, 0, "Macros with arguments not supported");
- }
+ /* Remember the start of the macro */
+ start = file->pos;
- /* Find the end of the line to get an estimate of
- * the macro's length.
- */
- for(ptr = file->pos; *ptr != '\n'; ptr++)
+ /* Find the end of the line. */
+ for(ptr = start; *ptr != '\n'; ptr++)
;
- if (ident->sym_define != 0) {
- error(state, 0, "macro %s already defined\n", ident->name);
+ /* remove the trailing whitespace */
+ while(spacep(*ptr)) {
+ ptr--;
+ }
+
+ /* Remove leading whitespace */
+ while(spacep(*start) && (start < ptr)) {
+ start++;
}
- macro = xmalloc(sizeof(*macro), "macro");
- macro->ident = ident;
- macro->buf_len = ptr - file->pos +1;
- macro->buf = xmalloc(macro->buf_len +2, "macro buf");
+ /* Remember where the macro starts */
+ mstart = start;
- memcpy(macro->buf, file->pos, macro->buf_len);
- macro->buf[macro->buf_len] = '\n';
- macro->buf[macro->buf_len +1] = '\0';
+ /* Parse macro parameters */
+ if (lparen_peek(state, state->file)) {
+ meat_raw(state, index, TOK_LPAREN);
+
+ for(;;) {
+ struct macro_arg *narg, *arg;
+ struct hash_entry *aident;
+ int tok;
- ident->sym_define = macro;
+ tok = mpeek_raw(state, index);
+ if (!args && (tok == TOK_RPAREN)) {
+ break;
+ }
+ else if (tok == TOK_DOTS) {
+ meat_raw(state, index, TOK_DOTS);
+ aident = state->i___VA_ARGS__;
+ }
+ else {
+ meat_raw(state, index, TOK_IDENT);
+ aident = tk->ident;
+ }
+
+ narg = xcmalloc(sizeof(*arg), "macro arg");
+ narg->ident = aident;
+
+ /* Verify I don't have a duplicate identifier */
+ for(arg = args; arg; arg = arg->next) {
+ if (arg->ident == narg->ident) {
+ error(state, 0, "Duplicate macro arg `%s'",
+ narg->ident->name);
+ }
+ }
+ /* Add the new argument to the end of the list */
+ *larg = narg;
+ larg = &narg->next;
+
+ if ((aident == state->i___VA_ARGS__) ||
+ (mpeek(state, index) != TOK_COMMA)) {
+ break;
+ }
+ meat_raw(state, index, TOK_COMMA);
+ }
+ meat_raw(state, index, TOK_RPAREN);
+
+ /* Get the start of the macro body */
+ mstart = file->pos;
+
+ /* Remove leading whitespace */
+ while(spacep(*mstart) && (mstart < ptr)) {
+ mstart++;
+ }
+ }
+ define_macro(state, ident, start, ptr - start + 1,
+ mstart - start, args);
break;
}
case TOK_ERROR:
{
- char *end;
+ const char *end;
int len;
+
/* Find the end of the line */
for(end = file->pos; *end != '\n'; end++)
;
len = (end - file->pos);
- if (state->if_value >= 0) {
+ if (!if_eat(state)) {
error(state, 0, "%*.*s", len, len, file->pos);
}
file->pos = end;
@@ -3820,13 +5434,14 @@ static void preprocess(struct compile_state *state, int index)
}
case TOK_WARNING:
{
- char *end;
+ const char *end;
int len;
+
/* Find the end of the line */
for(end = file->pos; *end != '\n'; end++)
;
len = (end - file->pos);
- if (state->if_value >= 0) {
+ if (!if_eat(state)) {
warning(state, 0, "%*.*s", len, len, file->pos);
}
file->pos = end;
@@ -3835,11 +5450,11 @@ static void preprocess(struct compile_state *state, int index)
case TOK_INCLUDE:
{
char *name;
- char *ptr;
+ const char *ptr;
int local;
local = 0;
name = 0;
- next_token(state, index);
+ next_token(state, tk);
if (tk->tok == TOK_LIT_STRING) {
const char *token;
int name_len;
@@ -3855,7 +5470,7 @@ static void preprocess(struct compile_state *state, int index)
local = 1;
}
else if (tk->tok == TOK_LESS) {
- char *start, *end;
+ const char *start, *end;
start = file->pos;
for(end = start; *end != '\n'; end++) {
if (*end == '>') {
@@ -3885,11 +5500,11 @@ static void preprocess(struct compile_state *state, int index)
error(state, 0, "garbage after include directive");
}
}
- if (state->if_value >= 0) {
+ if (!if_eat(state)) {
compile_file(state, name, local);
}
xfree(name);
- next_token(state, index);
+ next_token(state, tk);
return;
}
default:
@@ -3902,8 +5517,8 @@ static void preprocess(struct compile_state *state, int index)
}
/* Consume the rest of the macro line */
do {
- tok = mpeek(state, index);
- meat(state, index, tok);
+ tok = mpeek_raw(state, index);
+ meat_raw(state, index, tok);
} while(tok != TOK_EOF);
return;
}
@@ -3915,7 +5530,7 @@ static void token(struct compile_state *state, int index)
int rescan;
tk = &state->token[index];
- next_token(state, index);
+ next_token(state, tk);
do {
rescan = 0;
file = state->file;
@@ -3925,7 +5540,7 @@ static void token(struct compile_state *state, int index)
xfree(file->dirname);
xfree(file->buf);
xfree(file);
- next_token(state, index);
+ next_token(state, tk);
rescan = 1;
}
else if (tk->tok == TOK_MACRO) {
@@ -3933,12 +5548,13 @@ static void token(struct compile_state *state, int index)
rescan = 1;
}
else if (tk->ident && tk->ident->sym_define) {
- compile_macro(state, tk);
- next_token(state, index);
- rescan = 1;
+ rescan = compile_macro(state, &state->file, tk);
+ if (rescan) {
+ next_token(state, tk);
+ }
}
- else if (state->if_value < 0) {
- next_token(state, index);
+ else if (if_eat(state)) {
+ next_token(state, tk);
rescan = 1;
}
} while(rescan);
@@ -3965,19 +5581,10 @@ static int peek2(struct compile_state *state)
static void eat(struct compile_state *state, int tok)
{
- int next_tok;
int i;
- next_tok = peek(state);
- if (next_tok != tok) {
- const char *name1, *name2;
- name1 = tokens[next_tok];
- name2 = "";
- if (next_tok == TOK_IDENT) {
- name2 = state->token[1].ident->name;
- }
- error(state, 0, "\tfound %s %s expected %s",
- name1, name2 ,tokens[tok]);
- }
+ peek(state);
+ check_tok(state, &state->token[1], tok);
+
/* Free the old token value */
if (state->token[0].str_len) {
xfree((void *)(state->token[0].val.str));
@@ -3989,17 +5596,9 @@ static void eat(struct compile_state *state, int tok)
state->token[i].tok = -1;
}
-#warning "FIXME do not hardcode the include paths"
-static char *include_paths[] = {
- "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/include",
- "/home/eric/projects/linuxbios/checkin/solo/freebios2/src/arch/i386/include",
- "/home/eric/projects/linuxbios/checkin/solo/freebios2/src",
- 0
-};
-
static void compile_file(struct compile_state *state, const char *filename, int local)
{
- char cwd[4096];
+ char cwd[MAX_CWD_SIZE];
const char *subdir, *base;
int subdir_len;
struct file_state *file;
@@ -4023,16 +5622,15 @@ static void compile_file(struct compile_state *state, const char *filename, int
if (getcwd(cwd, sizeof(cwd)) == 0) {
die("cwd buffer to small");
}
-
if (subdir[0] == '/') {
file->dirname = xmalloc(subdir_len + 1, "dirname");
memcpy(file->dirname, subdir, subdir_len);
file->dirname[subdir_len] = '\0';
}
else {
- char *dir;
+ const char *dir;
int dirlen;
- char **path;
+ const char **path;
/* Find the appropriate directory... */
dir = 0;
if (!state->file && exists(cwd, filename)) {
@@ -4041,7 +5639,7 @@ static void compile_file(struct compile_state *state, const char *filename, int
if (local && state->file && exists(state->file->dirname, filename)) {
dir = state->file->dirname;
}
- for(path = include_paths; !dir && *path; path++) {
+ for(path = state->compiler->include_paths; !dir && *path; path++) {
if (exists(*path, filename)) {
dir = *path;
}
@@ -4057,7 +5655,6 @@ static void compile_file(struct compile_state *state, const char *filename, int
file->dirname[dirlen + 1 + subdir_len] = '\0';
}
file->buf = slurp_file(file->dirname, file->basename, &file->size);
- xchdir(cwd);
file->pos = file->buf;
file->line_start = file->pos;
@@ -4086,6 +5683,7 @@ static struct type *new_type(
result->right = right;
result->field_ident = 0;
result->type_ident = 0;
+ result->elements = 0;
return result;
}
@@ -4099,20 +5697,85 @@ static struct type *clone_type(unsigned int specifiers, struct type *old)
return result;
}
-#define SIZEOF_SHORT 2
-#define SIZEOF_INT 4
-#define SIZEOF_LONG (sizeof(long_t))
+static struct type *dup_type(struct compile_state *state, struct type *orig)
+{
+ struct type *new;
+ new = xcmalloc(sizeof(*new), "type");
+ new->type = orig->type;
+ new->field_ident = orig->field_ident;
+ new->type_ident = orig->type_ident;
+ new->elements = orig->elements;
+ if (orig->left) {
+ new->left = dup_type(state, orig->left);
+ }
+ if (orig->right) {
+ new->right = dup_type(state, orig->right);
+ }
+ return new;
+}
-#define ALIGNOF_SHORT 2
-#define ALIGNOF_INT 4
-#define ALIGNOF_LONG (sizeof(long_t))
+
+static struct type *invalid_type(struct compile_state *state, struct type *type)
+{
+ struct type *invalid, *member;
+ invalid = 0;
+ if (!type) {
+ internal_error(state, 0, "type missing?");
+ }
+ switch(type->type & TYPE_MASK) {
+ case TYPE_VOID:
+ case TYPE_CHAR: case TYPE_UCHAR:
+ case TYPE_SHORT: case TYPE_USHORT:
+ case TYPE_INT: case TYPE_UINT:
+ case TYPE_LONG: case TYPE_ULONG:
+ case TYPE_LLONG: case TYPE_ULLONG:
+ case TYPE_POINTER:
+ case TYPE_ENUM:
+ break;
+ case TYPE_BITFIELD:
+ invalid = invalid_type(state, type->left);
+ break;
+ case TYPE_ARRAY:
+ invalid = invalid_type(state, type->left);
+ break;
+ case TYPE_STRUCT:
+ case TYPE_TUPLE:
+ member = type->left;
+ while(member && (invalid == 0) &&
+ ((member->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ invalid = invalid_type(state, member->left);
+ member = member->right;
+ }
+ if (!invalid) {
+ invalid = invalid_type(state, member);
+ }
+ break;
+ case TYPE_UNION:
+ case TYPE_JOIN:
+ member = type->left;
+ while(member && (invalid == 0) &&
+ ((member->type & TYPE_MASK) == TYPE_OVERLAP)) {
+ invalid = invalid_type(state, member->left);
+ member = member->right;
+ }
+ if (!invalid) {
+ invalid = invalid_type(state, member);
+ }
+ break;
+ default:
+ invalid = type;
+ break;
+ }
+ return invalid;
+
+}
#define MASK_UCHAR(X) ((X) & ((ulong_t)0xff))
-#define MASK_USHORT(X) ((X) & (((ulong_t)1 << (SIZEOF_SHORT*8)) - 1))
+#define MASK_USHORT(X) ((X) & (((ulong_t)1 << (SIZEOF_SHORT)) - 1))
static inline ulong_t mask_uint(ulong_t x)
{
if (SIZEOF_INT < SIZEOF_LONG) {
- ulong_t mask = (((ulong_t)1) << ((ulong_t)(SIZEOF_INT*8))) -1;
+ ulong_t mask = (((ulong_t)1) << ((ulong_t)(SIZEOF_INT))) -1;
x &= mask;
}
return x;
@@ -4120,15 +5783,16 @@ static inline ulong_t mask_uint(ulong_t x)
#define MASK_UINT(X) (mask_uint(X))
#define MASK_ULONG(X) (X)
-static struct type void_type = { .type = TYPE_VOID };
-static struct type char_type = { .type = TYPE_CHAR };
-static struct type uchar_type = { .type = TYPE_UCHAR };
-static struct type short_type = { .type = TYPE_SHORT };
-static struct type ushort_type = { .type = TYPE_USHORT };
-static struct type int_type = { .type = TYPE_INT };
-static struct type uint_type = { .type = TYPE_UINT };
-static struct type long_type = { .type = TYPE_LONG };
-static struct type ulong_type = { .type = TYPE_ULONG };
+static struct type void_type = { .type = TYPE_VOID };
+static struct type char_type = { .type = TYPE_CHAR };
+static struct type uchar_type = { .type = TYPE_UCHAR };
+static struct type short_type = { .type = TYPE_SHORT };
+static struct type ushort_type = { .type = TYPE_USHORT };
+static struct type int_type = { .type = TYPE_INT };
+static struct type uint_type = { .type = TYPE_UINT };
+static struct type long_type = { .type = TYPE_LONG };
+static struct type ulong_type = { .type = TYPE_ULONG };
+static struct type unknown_type = { .type = TYPE_UNKNOWN };
static struct type void_ptr_type = {
.type = TYPE_POINTER,
@@ -4141,28 +5805,17 @@ static struct type void_func_type = {
.right = &void_type,
};
+static size_t bits_to_bytes(size_t size)
+{
+ return (size + SIZEOF_CHAR - 1)/SIZEOF_CHAR;
+}
+
static struct triple *variable(struct compile_state *state, struct type *type)
{
struct triple *result;
if ((type->type & STOR_MASK) != STOR_PERM) {
- if ((type->type & TYPE_MASK) != TYPE_STRUCT) {
- result = triple(state, OP_ADECL, type, 0, 0);
- } else {
- struct type *field;
- struct triple **vector;
- ulong_t index;
- result = new_triple(state, OP_VAL_VEC, type, -1, -1);
- vector = &result->param[0];
-
- field = type->left;
- index = 0;
- while((field->type & TYPE_MASK) == TYPE_PRODUCT) {
- vector[index] = variable(state, field->left);
- field = field->right;
- index++;
- }
- vector[index] = variable(state, field);
- }
+ result = triple(state, OP_ADECL, type, 0, 0);
+ generate_lhs_pieces(state, result);
}
else {
result = triple(state, OP_SDECL, type, 0, 0);
@@ -4220,8 +5873,12 @@ static void qual_of(FILE *fp, struct type *type)
static void name_of(FILE *fp, struct type *type)
{
- stor_of(fp, type);
- switch(type->type & TYPE_MASK) {
+ unsigned int base_type;
+ base_type = type->type & TYPE_MASK;
+ if ((base_type != TYPE_PRODUCT) && (base_type != TYPE_OVERLAP)) {
+ stor_of(fp, type);
+ }
+ switch(base_type) {
case TYPE_VOID:
fprintf(fp, "void");
qual_of(fp, type);
@@ -4264,35 +5921,71 @@ static void name_of(FILE *fp, struct type *type)
qual_of(fp, type);
break;
case TYPE_PRODUCT:
- case TYPE_OVERLAP:
name_of(fp, type->left);
fprintf(fp, ", ");
name_of(fp, type->right);
break;
+ case TYPE_OVERLAP:
+ name_of(fp, type->left);
+ fprintf(fp, ",| ");
+ name_of(fp, type->right);
+ break;
case TYPE_ENUM:
- fprintf(fp, "enum %s", type->type_ident->name);
+ fprintf(fp, "enum %s",
+ (type->type_ident)? type->type_ident->name : "");
qual_of(fp, type);
break;
case TYPE_STRUCT:
- fprintf(fp, "struct %s", type->type_ident->name);
+ fprintf(fp, "struct %s { ",
+ (type->type_ident)? type->type_ident->name : "");
+ name_of(fp, type->left);
+ fprintf(fp, " } ");
+ qual_of(fp, type);
+ break;
+ case TYPE_UNION:
+ fprintf(fp, "union %s { ",
+ (type->type_ident)? type->type_ident->name : "");
+ name_of(fp, type->left);
+ fprintf(fp, " } ");
qual_of(fp, type);
break;
case TYPE_FUNCTION:
- {
name_of(fp, type->left);
fprintf(fp, " (*)(");
name_of(fp, type->right);
fprintf(fp, ")");
break;
- }
case TYPE_ARRAY:
name_of(fp, type->left);
fprintf(fp, " [%ld]", (long)(type->elements));
break;
+ case TYPE_TUPLE:
+ fprintf(fp, "tuple { ");
+ name_of(fp, type->left);
+ fprintf(fp, " } ");
+ qual_of(fp, type);
+ break;
+ case TYPE_JOIN:
+ fprintf(fp, "join { ");
+ name_of(fp, type->left);
+ fprintf(fp, " } ");
+ qual_of(fp, type);
+ break;
+ case TYPE_BITFIELD:
+ name_of(fp, type->left);
+ fprintf(fp, " : %d ", type->elements);
+ qual_of(fp, type);
+ break;
+ case TYPE_UNKNOWN:
+ fprintf(fp, "unknown_t");
+ break;
default:
- fprintf(fp, "????: %x", type->type & TYPE_MASK);
+ fprintf(fp, "????: %x", base_type);
break;
}
+ if (type->field_ident && type->field_ident->name) {
+ fprintf(fp, " .%s", type->field_ident->name);
+ }
}
static size_t align_of(struct compile_state *state, struct type *type)
@@ -4303,9 +5996,12 @@ static size_t align_of(struct compile_state *state, struct type *type)
case TYPE_VOID:
align = 1;
break;
+ case TYPE_BITFIELD:
+ align = 1;
+ break;
case TYPE_CHAR:
case TYPE_UCHAR:
- align = 1;
+ align = ALIGNOF_CHAR;
break;
case TYPE_SHORT:
case TYPE_USHORT:
@@ -4318,9 +6014,11 @@ static size_t align_of(struct compile_state *state, struct type *type)
break;
case TYPE_LONG:
case TYPE_ULONG:
- case TYPE_POINTER:
align = ALIGNOF_LONG;
break;
+ case TYPE_POINTER:
+ align = ALIGNOF_POINTER;
+ break;
case TYPE_PRODUCT:
case TYPE_OVERLAP:
{
@@ -4334,6 +6032,9 @@ static size_t align_of(struct compile_state *state, struct type *type)
align = align_of(state, type->left);
break;
case TYPE_STRUCT:
+ case TYPE_TUPLE:
+ case TYPE_UNION:
+ case TYPE_JOIN:
align = align_of(state, type->left);
break;
default:
@@ -4343,15 +6044,111 @@ static size_t align_of(struct compile_state *state, struct type *type)
return align;
}
-static size_t needed_padding(size_t offset, size_t align)
+static size_t reg_align_of(struct compile_state *state, struct type *type)
+{
+ size_t align;
+ align = 0;
+ switch(type->type & TYPE_MASK) {
+ case TYPE_VOID:
+ align = 1;
+ break;
+ case TYPE_BITFIELD:
+ align = 1;
+ break;
+ case TYPE_CHAR:
+ case TYPE_UCHAR:
+ align = REG_ALIGNOF_CHAR;
+ break;
+ case TYPE_SHORT:
+ case TYPE_USHORT:
+ align = REG_ALIGNOF_SHORT;
+ break;
+ case TYPE_INT:
+ case TYPE_UINT:
+ case TYPE_ENUM:
+ align = REG_ALIGNOF_INT;
+ break;
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ align = REG_ALIGNOF_LONG;
+ break;
+ case TYPE_POINTER:
+ align = REG_ALIGNOF_POINTER;
+ break;
+ case TYPE_PRODUCT:
+ case TYPE_OVERLAP:
+ {
+ size_t left_align, right_align;
+ left_align = reg_align_of(state, type->left);
+ right_align = reg_align_of(state, type->right);
+ align = (left_align >= right_align) ? left_align : right_align;
+ break;
+ }
+ case TYPE_ARRAY:
+ align = reg_align_of(state, type->left);
+ break;
+ case TYPE_STRUCT:
+ case TYPE_UNION:
+ case TYPE_TUPLE:
+ case TYPE_JOIN:
+ align = reg_align_of(state, type->left);
+ break;
+ default:
+ error(state, 0, "alignof not yet defined for type\n");
+ break;
+ }
+ return align;
+}
+
+static size_t align_of_in_bytes(struct compile_state *state, struct type *type)
{
- size_t padding;
+ return bits_to_bytes(align_of(state, type));
+}
+static size_t size_of(struct compile_state *state, struct type *type);
+static size_t reg_size_of(struct compile_state *state, struct type *type);
+
+static size_t needed_padding(struct compile_state *state,
+ struct type *type, size_t offset)
+{
+ size_t padding, align;
+ align = align_of(state, type);
+ /* Align to the next machine word if the bitfield does completely
+ * fit into the current word.
+ */
+ if ((type->type & TYPE_MASK) == TYPE_BITFIELD) {
+ size_t size;
+ size = size_of(state, type);
+ if ((offset + type->elements)/size != offset/size) {
+ align = size;
+ }
+ }
+ padding = 0;
+ if (offset % align) {
+ padding = align - (offset % align);
+ }
+ return padding;
+}
+
+static size_t reg_needed_padding(struct compile_state *state,
+ struct type *type, size_t offset)
+{
+ size_t padding, align;
+ align = reg_align_of(state, type);
+ /* Align to the next register word if the bitfield does completely
+ * fit into the current register.
+ */
+ if (((type->type & TYPE_MASK) == TYPE_BITFIELD) &&
+ (((offset + type->elements)/REG_SIZEOF_REG) != (offset/REG_SIZEOF_REG)))
+ {
+ align = REG_SIZEOF_REG;
+ }
padding = 0;
if (offset % align) {
padding = align - (offset % align);
}
return padding;
}
+
static size_t size_of(struct compile_state *state, struct type *type)
{
size_t size;
@@ -4360,9 +6157,12 @@ static size_t size_of(struct compile_state *state, struct type *type)
case TYPE_VOID:
size = 0;
break;
+ case TYPE_BITFIELD:
+ size = type->elements;
+ break;
case TYPE_CHAR:
case TYPE_UCHAR:
- size = 1;
+ size = SIZEOF_CHAR;
break;
case TYPE_SHORT:
case TYPE_USHORT:
@@ -4375,21 +6175,21 @@ static size_t size_of(struct compile_state *state, struct type *type)
break;
case TYPE_LONG:
case TYPE_ULONG:
- case TYPE_POINTER:
size = SIZEOF_LONG;
break;
+ case TYPE_POINTER:
+ size = SIZEOF_POINTER;
+ break;
case TYPE_PRODUCT:
{
- size_t align, pad;
+ size_t pad;
size = 0;
while((type->type & TYPE_MASK) == TYPE_PRODUCT) {
- align = align_of(state, type->left);
- pad = needed_padding(size, align);
+ pad = needed_padding(state, type->left, size);
size = size + pad + size_of(state, type->left);
type = type->right;
}
- align = align_of(state, type);
- pad = needed_padding(size, align);
+ pad = needed_padding(state, type, size);
size = size + pad + size_of(state, type);
break;
}
@@ -4409,45 +6209,209 @@ static size_t size_of(struct compile_state *state, struct type *type)
}
break;
case TYPE_STRUCT:
+ case TYPE_TUPLE:
+ {
+ size_t pad;
+ size = size_of(state, type->left);
+ /* Pad structures so their size is a multiples of their alignment */
+ pad = needed_padding(state, type, size);
+ size = size + pad;
+ break;
+ }
+ case TYPE_UNION:
+ case TYPE_JOIN:
{
- size_t align, pad;
+ size_t pad;
size = size_of(state, type->left);
+ /* Pad unions so their size is a multiple of their alignment */
+ pad = needed_padding(state, type, size);
+ size = size + pad;
+ break;
+ }
+ default:
+ internal_error(state, 0, "sizeof not yet defined for type");
+ break;
+ }
+ return size;
+}
+
+static size_t reg_size_of(struct compile_state *state, struct type *type)
+{
+ size_t size;
+ size = 0;
+ switch(type->type & TYPE_MASK) {
+ case TYPE_VOID:
+ size = 0;
+ break;
+ case TYPE_BITFIELD:
+ size = type->elements;
+ break;
+ case TYPE_CHAR:
+ case TYPE_UCHAR:
+ size = REG_SIZEOF_CHAR;
+ break;
+ case TYPE_SHORT:
+ case TYPE_USHORT:
+ size = REG_SIZEOF_SHORT;
+ break;
+ case TYPE_INT:
+ case TYPE_UINT:
+ case TYPE_ENUM:
+ size = REG_SIZEOF_INT;
+ break;
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ size = REG_SIZEOF_LONG;
+ break;
+ case TYPE_POINTER:
+ size = REG_SIZEOF_POINTER;
+ break;
+ case TYPE_PRODUCT:
+ {
+ size_t pad;
+ size = 0;
+ while((type->type & TYPE_MASK) == TYPE_PRODUCT) {
+ pad = reg_needed_padding(state, type->left, size);
+ size = size + pad + reg_size_of(state, type->left);
+ type = type->right;
+ }
+ pad = reg_needed_padding(state, type, size);
+ size = size + pad + reg_size_of(state, type);
+ break;
+ }
+ case TYPE_OVERLAP:
+ {
+ size_t size_left, size_right;
+ size_left = reg_size_of(state, type->left);
+ size_right = reg_size_of(state, type->right);
+ size = (size_left >= size_right)? size_left : size_right;
+ break;
+ }
+ case TYPE_ARRAY:
+ if (type->elements == ELEMENT_COUNT_UNSPECIFIED) {
+ internal_error(state, 0, "Invalid array type");
+ } else {
+ size = reg_size_of(state, type->left) * type->elements;
+ }
+ break;
+ case TYPE_STRUCT:
+ case TYPE_TUPLE:
+ {
+ size_t pad;
+ size = reg_size_of(state, type->left);
/* Pad structures so their size is a multiples of their alignment */
- align = align_of(state, type);
- pad = needed_padding(size, align);
+ pad = reg_needed_padding(state, type, size);
+ size = size + pad;
+ break;
+ }
+ case TYPE_UNION:
+ case TYPE_JOIN:
+ {
+ size_t pad;
+ size = reg_size_of(state, type->left);
+ /* Pad unions so their size is a multiple of their alignment */
+ pad = reg_needed_padding(state, type, size);
size = size + pad;
break;
}
default:
- internal_error(state, 0, "sizeof not yet defined for type\n");
+ internal_error(state, 0, "sizeof not yet defined for type");
break;
}
return size;
}
+static size_t registers_of(struct compile_state *state, struct type *type)
+{
+ size_t registers;
+ registers = reg_size_of(state, type);
+ registers += REG_SIZEOF_REG - 1;
+ registers /= REG_SIZEOF_REG;
+ return registers;
+}
+
+static size_t size_of_in_bytes(struct compile_state *state, struct type *type)
+{
+ return bits_to_bytes(size_of(state, type));
+}
+
static size_t field_offset(struct compile_state *state,
struct type *type, struct hash_entry *field)
{
struct type *member;
- size_t size, align;
- if ((type->type & TYPE_MASK) != TYPE_STRUCT) {
- internal_error(state, 0, "field_offset only works on structures");
+ size_t size;
+
+ size = 0;
+ member = 0;
+ if ((type->type & TYPE_MASK) == TYPE_STRUCT) {
+ member = type->left;
+ while(member && ((member->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ size += needed_padding(state, member->left, size);
+ if (member->left->field_ident == field) {
+ member = member->left;
+ break;
+ }
+ size += size_of(state, member->left);
+ member = member->right;
+ }
+ size += needed_padding(state, member, size);
+ }
+ else if ((type->type & TYPE_MASK) == TYPE_UNION) {
+ member = type->left;
+ while(member && ((member->type & TYPE_MASK) == TYPE_OVERLAP)) {
+ if (member->left->field_ident == field) {
+ member = member->left;
+ break;
+ }
+ member = member->right;
+ }
+ }
+ else {
+ internal_error(state, 0, "field_offset only works on structures and unions");
+ }
+
+ if (!member || (member->field_ident != field)) {
+ error(state, 0, "member %s not present", field->name);
}
+ return size;
+}
+
+static size_t field_reg_offset(struct compile_state *state,
+ struct type *type, struct hash_entry *field)
+{
+ struct type *member;
+ size_t size;
+
size = 0;
- member = type->left;
- while((member->type & TYPE_MASK) == TYPE_PRODUCT) {
- align = align_of(state, member->left);
- size += needed_padding(size, align);
- if (member->left->field_ident == field) {
- member = member->left;
- break;
+ member = 0;
+ if ((type->type & TYPE_MASK) == TYPE_STRUCT) {
+ member = type->left;
+ while(member && ((member->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ size += reg_needed_padding(state, member->left, size);
+ if (member->left->field_ident == field) {
+ member = member->left;
+ break;
+ }
+ size += reg_size_of(state, member->left);
+ member = member->right;
}
- size += size_of(state, member->left);
- member = member->right;
}
- align = align_of(state, member);
- size += needed_padding(size, align);
- if (member->field_ident != field) {
+ else if ((type->type & TYPE_MASK) == TYPE_UNION) {
+ member = type->left;
+ while(member && ((member->type & TYPE_MASK) == TYPE_OVERLAP)) {
+ if (member->left->field_ident == field) {
+ member = member->left;
+ break;
+ }
+ member = member->right;
+ }
+ }
+ else {
+ internal_error(state, 0, "field_reg_offset only works on structures and unions");
+ }
+
+ size += reg_needed_padding(state, member, size);
+ if (!member || (member->field_ident != field)) {
error(state, 0, "member %s not present", field->name);
}
return size;
@@ -4457,23 +6421,441 @@ static struct type *field_type(struct compile_state *state,
struct type *type, struct hash_entry *field)
{
struct type *member;
- if ((type->type & TYPE_MASK) != TYPE_STRUCT) {
- internal_error(state, 0, "field_type only works on structures");
+
+ member = 0;
+ if ((type->type & TYPE_MASK) == TYPE_STRUCT) {
+ member = type->left;
+ while(member && ((member->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ if (member->left->field_ident == field) {
+ member = member->left;
+ break;
+ }
+ member = member->right;
+ }
}
- member = type->left;
- while((member->type & TYPE_MASK) == TYPE_PRODUCT) {
- if (member->left->field_ident == field) {
- member = member->left;
- break;
+ else if ((type->type & TYPE_MASK) == TYPE_UNION) {
+ member = type->left;
+ while(member && ((member->type & TYPE_MASK) == TYPE_OVERLAP)) {
+ if (member->left->field_ident == field) {
+ member = member->left;
+ break;
+ }
+ member = member->right;
}
- member = member->right;
}
- if (member->field_ident != field) {
+ else {
+ internal_error(state, 0, "field_type only works on structures and unions");
+ }
+
+ if (!member || (member->field_ident != field)) {
error(state, 0, "member %s not present", field->name);
}
return member;
}
+static size_t index_offset(struct compile_state *state,
+ struct type *type, ulong_t index)
+{
+ struct type *member;
+ size_t size;
+ size = 0;
+ if ((type->type & TYPE_MASK) == TYPE_ARRAY) {
+ size = size_of(state, type->left) * index;
+ }
+ else if ((type->type & TYPE_MASK) == TYPE_TUPLE) {
+ ulong_t i;
+ member = type->left;
+ i = 0;
+ while(member && ((member->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ size += needed_padding(state, member->left, size);
+ if (i == index) {
+ member = member->left;
+ break;
+ }
+ size += size_of(state, member->left);
+ i++;
+ member = member->right;
+ }
+ size += needed_padding(state, member, size);
+ if (i != index) {
+ internal_error(state, 0, "Missing member index: %u", index);
+ }
+ }
+ else if ((type->type & TYPE_MASK) == TYPE_JOIN) {
+ ulong_t i;
+ size = 0;
+ member = type->left;
+ i = 0;
+ while(member && ((member->type & TYPE_MASK) == TYPE_OVERLAP)) {
+ if (i == index) {
+ member = member->left;
+ break;
+ }
+ i++;
+ member = member->right;
+ }
+ if (i != index) {
+ internal_error(state, 0, "Missing member index: %u", index);
+ }
+ }
+ else {
+ internal_error(state, 0,
+ "request for index %u in something not an array, tuple or join",
+ index);
+ }
+ return size;
+}
+
+static size_t index_reg_offset(struct compile_state *state,
+ struct type *type, ulong_t index)
+{
+ struct type *member;
+ size_t size;
+ size = 0;
+ if ((type->type & TYPE_MASK) == TYPE_ARRAY) {
+ size = reg_size_of(state, type->left) * index;
+ }
+ else if ((type->type & TYPE_MASK) == TYPE_TUPLE) {
+ ulong_t i;
+ member = type->left;
+ i = 0;
+ while(member && ((member->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ size += reg_needed_padding(state, member->left, size);
+ if (i == index) {
+ member = member->left;
+ break;
+ }
+ size += reg_size_of(state, member->left);
+ i++;
+ member = member->right;
+ }
+ size += reg_needed_padding(state, member, size);
+ if (i != index) {
+ internal_error(state, 0, "Missing member index: %u", index);
+ }
+
+ }
+ else if ((type->type & TYPE_MASK) == TYPE_JOIN) {
+ ulong_t i;
+ size = 0;
+ member = type->left;
+ i = 0;
+ while(member && ((member->type & TYPE_MASK) == TYPE_OVERLAP)) {
+ if (i == index) {
+ member = member->left;
+ break;
+ }
+ i++;
+ member = member->right;
+ }
+ if (i != index) {
+ internal_error(state, 0, "Missing member index: %u", index);
+ }
+ }
+ else {
+ internal_error(state, 0,
+ "request for index %u in something not an array, tuple or join",
+ index);
+ }
+ return size;
+}
+
+static struct type *index_type(struct compile_state *state,
+ struct type *type, ulong_t index)
+{
+ struct type *member;
+ if (index >= type->elements) {
+ internal_error(state, 0, "Invalid element %u requested", index);
+ }
+ if ((type->type & TYPE_MASK) == TYPE_ARRAY) {
+ member = type->left;
+ }
+ else if ((type->type & TYPE_MASK) == TYPE_TUPLE) {
+ ulong_t i;
+ member = type->left;
+ i = 0;
+ while(member && ((member->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ if (i == index) {
+ member = member->left;
+ break;
+ }
+ i++;
+ member = member->right;
+ }
+ if (i != index) {
+ internal_error(state, 0, "Missing member index: %u", index);
+ }
+ }
+ else if ((type->type & TYPE_MASK) == TYPE_JOIN) {
+ ulong_t i;
+ member = type->left;
+ i = 0;
+ while(member && ((member->type & TYPE_MASK) == TYPE_OVERLAP)) {
+ if (i == index) {
+ member = member->left;
+ break;
+ }
+ i++;
+ member = member->right;
+ }
+ if (i != index) {
+ internal_error(state, 0, "Missing member index: %u", index);
+ }
+ }
+ else {
+ member = 0;
+ internal_error(state, 0,
+ "request for index %u in something not an array, tuple or join",
+ index);
+ }
+ return member;
+}
+
+static struct type *unpack_type(struct compile_state *state, struct type *type)
+{
+ /* If I have a single register compound type not a bit-field
+ * find the real type.
+ */
+ struct type *start_type;
+ size_t size;
+ /* Get out early if I need multiple registers for this type */
+ size = reg_size_of(state, type);
+ if (size > REG_SIZEOF_REG) {
+ return type;
+ }
+ /* Get out early if I don't need any registers for this type */
+ if (size == 0) {
+ return &void_type;
+ }
+ /* Loop until I have no more layers I can remove */
+ do {
+ start_type = type;
+ switch(type->type & TYPE_MASK) {
+ case TYPE_ARRAY:
+ /* If I have a single element the unpacked type
+ * is that element.
+ */
+ if (type->elements == 1) {
+ type = type->left;
+ }
+ break;
+ case TYPE_STRUCT:
+ case TYPE_TUPLE:
+ /* If I have a single element the unpacked type
+ * is that element.
+ */
+ if (type->elements == 1) {
+ type = type->left;
+ }
+ /* If I have multiple elements the unpacked
+ * type is the non-void element.
+ */
+ else {
+ struct type *next, *member;
+ struct type *sub_type;
+ sub_type = 0;
+ next = type->left;
+ while(next) {
+ member = next;
+ next = 0;
+ if ((member->type & TYPE_MASK) == TYPE_PRODUCT) {
+ next = member->right;
+ member = member->left;
+ }
+ if (reg_size_of(state, member) > 0) {
+ if (sub_type) {
+ internal_error(state, 0, "true compound type in a register");
+ }
+ sub_type = member;
+ }
+ }
+ if (sub_type) {
+ type = sub_type;
+ }
+ }
+ break;
+
+ case TYPE_UNION:
+ case TYPE_JOIN:
+ /* If I have a single element the unpacked type
+ * is that element.
+ */
+ if (type->elements == 1) {
+ type = type->left;
+ }
+ /* I can't in general unpack union types */
+ break;
+ default:
+ /* If I'm not a compound type I can't unpack it */
+ break;
+ }
+ } while(start_type != type);
+ switch(type->type & TYPE_MASK) {
+ case TYPE_STRUCT:
+ case TYPE_ARRAY:
+ case TYPE_TUPLE:
+ internal_error(state, 0, "irredicible type?");
+ break;
+ }
+ return type;
+}
+
+static int equiv_types(struct type *left, struct type *right);
+static int is_compound_type(struct type *type);
+
+static struct type *reg_type(
+ struct compile_state *state, struct type *type, int reg_offset)
+{
+ struct type *member;
+ size_t size;
+#if 1
+ struct type *invalid;
+ invalid = invalid_type(state, type);
+ if (invalid) {
+ fprintf(state->errout, "type: ");
+ name_of(state->errout, type);
+ fprintf(state->errout, "\n");
+ fprintf(state->errout, "invalid: ");
+ name_of(state->errout, invalid);
+ fprintf(state->errout, "\n");
+ internal_error(state, 0, "bad input type?");
+ }
+#endif
+
+ size = reg_size_of(state, type);
+ if (reg_offset > size) {
+ member = 0;
+ fprintf(state->errout, "type: ");
+ name_of(state->errout, type);
+ fprintf(state->errout, "\n");
+ internal_error(state, 0, "offset outside of type");
+ }
+ else {
+ switch(type->type & TYPE_MASK) {
+ /* Don't do anything with the basic types */
+ case TYPE_VOID:
+ case TYPE_CHAR: case TYPE_UCHAR:
+ case TYPE_SHORT: case TYPE_USHORT:
+ case TYPE_INT: case TYPE_UINT:
+ case TYPE_LONG: case TYPE_ULONG:
+ case TYPE_LLONG: case TYPE_ULLONG:
+ case TYPE_FLOAT: case TYPE_DOUBLE:
+ case TYPE_LDOUBLE:
+ case TYPE_POINTER:
+ case TYPE_ENUM:
+ case TYPE_BITFIELD:
+ member = type;
+ break;
+ case TYPE_ARRAY:
+ member = type->left;
+ size = reg_size_of(state, member);
+ if (size > REG_SIZEOF_REG) {
+ member = reg_type(state, member, reg_offset % size);
+ }
+ break;
+ case TYPE_STRUCT:
+ case TYPE_TUPLE:
+ {
+ size_t offset;
+ offset = 0;
+ member = type->left;
+ while(member && ((member->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ size = reg_size_of(state, member->left);
+ offset += reg_needed_padding(state, member->left, offset);
+ if ((offset + size) > reg_offset) {
+ member = member->left;
+ break;
+ }
+ offset += size;
+ member = member->right;
+ }
+ offset += reg_needed_padding(state, member, offset);
+ member = reg_type(state, member, reg_offset - offset);
+ break;
+ }
+ case TYPE_UNION:
+ case TYPE_JOIN:
+ {
+ struct type *join, **jnext, *mnext;
+ join = new_type(TYPE_JOIN, 0, 0);
+ jnext = &join->left;
+ mnext = type->left;
+ while(mnext) {
+ size_t size;
+ member = mnext;
+ mnext = 0;
+ if ((member->type & TYPE_MASK) == TYPE_OVERLAP) {
+ mnext = member->right;
+ member = member->left;
+ }
+ size = reg_size_of(state, member);
+ if (size > reg_offset) {
+ struct type *part, *hunt;
+ part = reg_type(state, member, reg_offset);
+ /* See if this type is already in the union */
+ hunt = join->left;
+ while(hunt) {
+ struct type *test = hunt;
+ hunt = 0;
+ if ((test->type & TYPE_MASK) == TYPE_OVERLAP) {
+ hunt = test->right;
+ test = test->left;
+ }
+ if (equiv_types(part, test)) {
+ goto next;
+ }
+ }
+ /* Nope add it */
+ if (!*jnext) {
+ *jnext = part;
+ } else {
+ *jnext = new_type(TYPE_OVERLAP, *jnext, part);
+ jnext = &(*jnext)->right;
+ }
+ join->elements++;
+ }
+ next:
+ ;
+ }
+ if (join->elements == 0) {
+ internal_error(state, 0, "No elements?");
+ }
+ member = join;
+ break;
+ }
+ default:
+ member = 0;
+ fprintf(state->errout, "type: ");
+ name_of(state->errout, type);
+ fprintf(state->errout, "\n");
+ internal_error(state, 0, "reg_type not yet defined for type");
+
+ }
+ }
+ /* If I have a single register compound type not a bit-field
+ * find the real type.
+ */
+ member = unpack_type(state, member);
+ ;
+ size = reg_size_of(state, member);
+ if (size > REG_SIZEOF_REG) {
+ internal_error(state, 0, "Cannot find type of single register");
+ }
+#if 1
+ invalid = invalid_type(state, member);
+ if (invalid) {
+ fprintf(state->errout, "type: ");
+ name_of(state->errout, member);
+ fprintf(state->errout, "\n");
+ fprintf(state->errout, "invalid: ");
+ name_of(state->errout, invalid);
+ fprintf(state->errout, "\n");
+ internal_error(state, 0, "returning bad type?");
+ }
+#endif
+ return member;
+}
+
static struct type *next_field(struct compile_state *state,
struct type *type, struct type *prev_member)
{
@@ -4502,37 +6884,63 @@ static struct type *next_field(struct compile_state *state,
return member;
}
-static struct triple *struct_field(struct compile_state *state,
- struct triple *decl, struct hash_entry *field)
+typedef void (*walk_type_fields_cb_t)(struct compile_state *state, struct type *type,
+ size_t ret_offset, size_t mem_offset, void *arg);
+
+static void walk_type_fields(struct compile_state *state,
+ struct type *type, size_t reg_offset, size_t mem_offset,
+ walk_type_fields_cb_t cb, void *arg);
+
+static void walk_struct_fields(struct compile_state *state,
+ struct type *type, size_t reg_offset, size_t mem_offset,
+ walk_type_fields_cb_t cb, void *arg)
{
- struct triple **vector;
- struct type *type;
- ulong_t index;
- type = decl->type;
+ struct type *tptr;
+ ulong_t i;
if ((type->type & TYPE_MASK) != TYPE_STRUCT) {
- return decl;
+ internal_error(state, 0, "walk_struct_fields only works on structures");
+ }
+ tptr = type->left;
+ for(i = 0; i < type->elements; i++) {
+ struct type *mtype;
+ mtype = tptr;
+ if ((mtype->type & TYPE_MASK) == TYPE_PRODUCT) {
+ mtype = mtype->left;
+ }
+ walk_type_fields(state, mtype,
+ reg_offset +
+ field_reg_offset(state, type, mtype->field_ident),
+ mem_offset +
+ field_offset(state, type, mtype->field_ident),
+ cb, arg);
+ tptr = tptr->right;
}
- if (decl->op != OP_VAL_VEC) {
- internal_error(state, 0, "Invalid struct variable");
- }
- if (!field) {
- internal_error(state, 0, "Missing structure field");
- }
- type = type->left;
- vector = &RHS(decl, 0);
- index = 0;
- while((type->type & TYPE_MASK) == TYPE_PRODUCT) {
- if (type->left->field_ident == field) {
- type = type->left;
- break;
- }
- index += 1;
- type = type->right;
- }
- if (type->field_ident != field) {
- internal_error(state, 0, "field %s not found?", field->name);
+
+}
+
+static void walk_type_fields(struct compile_state *state,
+ struct type *type, size_t reg_offset, size_t mem_offset,
+ walk_type_fields_cb_t cb, void *arg)
+{
+ switch(type->type & TYPE_MASK) {
+ case TYPE_STRUCT:
+ walk_struct_fields(state, type, reg_offset, mem_offset, cb, arg);
+ break;
+ case TYPE_CHAR:
+ case TYPE_UCHAR:
+ case TYPE_SHORT:
+ case TYPE_USHORT:
+ case TYPE_INT:
+ case TYPE_UINT:
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ cb(state, type, reg_offset, mem_offset, arg);
+ break;
+ case TYPE_VOID:
+ break;
+ default:
+ internal_error(state, 0, "walk_type_fields not yet implemented for type");
}
- return vector[index];
}
static void arrays_complete(struct compile_state *state, struct type *type)
@@ -4545,10 +6953,37 @@ static void arrays_complete(struct compile_state *state, struct type *type)
}
}
+static unsigned int get_basic_type(struct type *type)
+{
+ unsigned int basic;
+ basic = type->type & TYPE_MASK;
+ /* Convert enums to ints */
+ if (basic == TYPE_ENUM) {
+ basic = TYPE_INT;
+ }
+ /* Convert bitfields to standard types */
+ else if (basic == TYPE_BITFIELD) {
+ if (type->elements <= SIZEOF_CHAR) {
+ basic = TYPE_CHAR;
+ }
+ else if (type->elements <= SIZEOF_SHORT) {
+ basic = TYPE_SHORT;
+ }
+ else if (type->elements <= SIZEOF_INT) {
+ basic = TYPE_INT;
+ }
+ else if (type->elements <= SIZEOF_LONG) {
+ basic = TYPE_LONG;
+ }
+ if (!TYPE_SIGNED(type->left->type)) {
+ basic += 1;
+ }
+ }
+ return basic;
+}
+
static unsigned int do_integral_promotion(unsigned int type)
{
- type &= TYPE_MASK;
- if (type == TYPE_ENUM) type = TYPE_INT;
if (TYPE_INTEGER(type) && (TYPE_RANK(type) < TYPE_RANK(TYPE_INT))) {
type = TYPE_INT;
}
@@ -4558,11 +6993,6 @@ static unsigned int do_integral_promotion(unsigned int type)
static unsigned int do_arithmetic_conversion(
unsigned int left, unsigned int right)
{
- left &= TYPE_MASK;
- right &= TYPE_MASK;
- /* Convert enums to ints */
- if (left == TYPE_ENUM) left = TYPE_INT;
- if (right == TYPE_ENUM) right = TYPE_INT;
if ((left == TYPE_LDOUBLE) || (right == TYPE_LDOUBLE)) {
return TYPE_LDOUBLE;
}
@@ -4611,33 +7041,57 @@ static int equiv_types(struct type *left, struct type *right)
if (type == TYPE_VOID) {
return 1;
}
+ /* For bitfields we need to compare the sizes */
+ else if (type == TYPE_BITFIELD) {
+ return (left->elements == right->elements) &&
+ (TYPE_SIGNED(left->left->type) == TYPE_SIGNED(right->left->type));
+ }
/* if the basic types match and it is an arithmetic type we are done */
- if (TYPE_ARITHMETIC(type)) {
+ else if (TYPE_ARITHMETIC(type)) {
return 1;
}
/* If it is a pointer type recurse and keep testing */
- if (type == TYPE_POINTER) {
+ else if (type == TYPE_POINTER) {
return equiv_types(left->left, right->left);
}
else if (type == TYPE_ARRAY) {
return (left->elements == right->elements) &&
equiv_types(left->left, right->left);
}
- /* test for struct/union equality */
+ /* test for struct equality */
else if (type == TYPE_STRUCT) {
return left->type_ident == right->type_ident;
}
+ /* test for union equality */
+ else if (type == TYPE_UNION) {
+ return left->type_ident == right->type_ident;
+ }
/* Test for equivalent functions */
else if (type == TYPE_FUNCTION) {
return equiv_types(left->left, right->left) &&
equiv_types(left->right, right->right);
}
/* We only see TYPE_PRODUCT as part of function equivalence matching */
+ /* We also see TYPE_PRODUCT as part of of tuple equivalence matchin */
else if (type == TYPE_PRODUCT) {
return equiv_types(left->left, right->left) &&
equiv_types(left->right, right->right);
}
- /* We should see TYPE_OVERLAP */
+ /* We should see TYPE_OVERLAP when comparing joins */
+ else if (type == TYPE_OVERLAP) {
+ return equiv_types(left->left, right->left) &&
+ equiv_types(left->right, right->right);
+ }
+ /* Test for equivalence of tuples */
+ else if (type == TYPE_TUPLE) {
+ return (left->elements == right->elements) &&
+ equiv_types(left->left, right->left);
+ }
+ /* Test for equivalence of joins */
+ else if (type == TYPE_JOIN) {
+ return (left->elements == right->elements) &&
+ equiv_types(left->left, right->left);
+ }
else {
return 0;
}
@@ -4674,12 +7128,18 @@ static struct type *compatible_types(struct type *left, struct type *right)
result = new_type(qual_type, result, 0);
}
}
- /* test for struct/union equality */
+ /* test for struct equality */
else if (type == TYPE_STRUCT) {
if (left->type_ident == right->type_ident) {
result = left;
}
}
+ /* test for union equality */
+ else if (type == TYPE_UNION) {
+ if (left->type_ident == right->type_ident) {
+ result = left;
+ }
+ }
/* Test for equivalent functions */
else if (type == TYPE_FUNCTION) {
struct type *lf, *rf;
@@ -4704,6 +7164,30 @@ static struct type *compatible_types(struct type *left, struct type *right)
return result;
}
+/* See if left is a equivalent to right or right is a union member of left */
+static int is_subset_type(struct type *left, struct type *right)
+{
+ if (equiv_types(left, right)) {
+ return 1;
+ }
+ if ((left->type & TYPE_MASK) == TYPE_JOIN) {
+ struct type *member, *mnext;
+ mnext = left->left;
+ while(mnext) {
+ member = mnext;
+ mnext = 0;
+ if ((member->type & TYPE_MASK) == TYPE_OVERLAP) {
+ mnext = member->right;
+ member = member->left;
+ }
+ if (is_subset_type( member, right)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
static struct type *compatible_ptrs(struct type *left, struct type *right)
{
struct type *result;
@@ -4732,14 +7216,13 @@ static struct triple *integral_promotion(
if (TYPE_INTEGER(type->type)) {
unsigned int int_type;
int_type = type->type & ~TYPE_MASK;
- int_type |= do_integral_promotion(type->type);
+ int_type |= do_integral_promotion(get_basic_type(type));
if (int_type != type->type) {
if (def->op != OP_LOAD) {
def->type = new_type(int_type, 0, 0);
}
else {
-#warning "FIXME can I just cast all operands like this?"
- def = triple(state, OP_COPY,
+ def = triple(state, OP_CONVERT,
new_type(int_type, 0, 0), def, 0);
}
}
@@ -4785,8 +7268,28 @@ static void bool(struct compile_state *state, struct triple *def)
static int is_signed(struct type *type)
{
+ if ((type->type & TYPE_MASK) == TYPE_BITFIELD) {
+ type = type->left;
+ }
return !!TYPE_SIGNED(type->type);
}
+static int is_compound_type(struct type *type)
+{
+ int is_compound;
+ switch((type->type & TYPE_MASK)) {
+ case TYPE_ARRAY:
+ case TYPE_STRUCT:
+ case TYPE_TUPLE:
+ case TYPE_UNION:
+ case TYPE_JOIN:
+ is_compound = 1;
+ break;
+ default:
+ is_compound = 0;
+ break;
+ }
+ return is_compound;
+}
/* Is this value located in a register otherwise it must be in memory */
static int is_in_reg(struct compile_state *state, struct triple *def)
@@ -4798,21 +7301,20 @@ static int is_in_reg(struct compile_state *state, struct triple *def)
else if ((def->op == OP_SDECL) || (def->op == OP_DEREF)) {
in_reg = 0;
}
- else if (def->op == OP_VAL_VEC) {
- in_reg = is_in_reg(state, RHS(def, 0));
- }
- else if (def->op == OP_DOT) {
- in_reg = is_in_reg(state, RHS(def, 0));
+ else if (triple_is_part(state, def)) {
+ in_reg = is_in_reg(state, MISC(def, 0));
}
else {
- internal_error(state, 0, "unknown expr storage location");
+ internal_error(state, def, "unknown expr storage location");
in_reg = -1;
}
return in_reg;
}
-/* Is this a stable variable location otherwise it must be a temporary */
-static int is_stable(struct compile_state *state, struct triple *def)
+/* Is this an auto or static variable location? Something that can
+ * be assigned to. Otherwise it must must be a pure value, a temporary.
+ */
+static int is_lvalue(struct compile_state *state, struct triple *def)
{
int ret;
ret = 0;
@@ -4826,36 +7328,8 @@ static int is_stable(struct compile_state *state, struct triple *def)
(def->op == OP_LIST)) {
ret = 1;
}
- else if (def->op == OP_DOT) {
- ret = is_stable(state, RHS(def, 0));
- }
- else if (def->op == OP_VAL_VEC) {
- struct triple **vector;
- ulong_t i;
- ret = 1;
- vector = &RHS(def, 0);
- for(i = 0; i < def->type->elements; i++) {
- if (!is_stable(state, vector[i])) {
- ret = 0;
- break;
- }
- }
- }
- return ret;
-}
-
-static int is_lvalue(struct compile_state *state, struct triple *def)
-{
- int ret;
- ret = 1;
- if (!def) {
- return 0;
- }
- if (!is_stable(state, def)) {
- return 0;
- }
- if (def->op == OP_DOT) {
- ret = is_lvalue(state, RHS(def, 0));
+ else if (triple_is_part(state, def)) {
+ ret = is_lvalue(state, MISC(def, 0));
}
return ret;
}
@@ -4899,7 +7373,7 @@ static struct triple *int_const(
case TYPE_LONG: case TYPE_ULONG:
break;
default:
- internal_error(state, 0, "constant for unkown type");
+ internal_error(state, 0, "constant for unknown type");
}
result = triple(state, OP_INTCONST, type, 0, 0);
result->u.cval = value;
@@ -4913,27 +7387,50 @@ static struct triple *do_mk_addr_expr(struct compile_state *state,
struct triple *expr, struct type *type, ulong_t offset)
{
struct triple *result;
+ struct type *ptr_type;
clvalue(state, expr);
- type = new_type(TYPE_POINTER | (type->type & QUAL_MASK), type, 0);
+ ptr_type = new_type(TYPE_POINTER | (type->type & QUAL_MASK), type, 0);
+
result = 0;
if (expr->op == OP_ADECL) {
error(state, expr, "address of auto variables not supported");
}
else if (expr->op == OP_SDECL) {
- result = triple(state, OP_ADDRCONST, type, 0, 0);
+ result = triple(state, OP_ADDRCONST, ptr_type, 0, 0);
MISC(result, 0) = expr;
result->u.cval = offset;
}
else if (expr->op == OP_DEREF) {
- result = triple(state, OP_ADD, type,
+ result = triple(state, OP_ADD, ptr_type,
RHS(expr, 0),
int_const(state, &ulong_type, offset));
}
+ else if (expr->op == OP_BLOBCONST) {
+ FINISHME();
+ internal_error(state, expr, "not yet implemented");
+ }
else if (expr->op == OP_LIST) {
error(state, 0, "Function addresses not supported");
}
+ else if (triple_is_part(state, expr)) {
+ struct triple *part;
+ part = expr;
+ expr = MISC(expr, 0);
+ if (part->op == OP_DOT) {
+ offset += bits_to_bytes(
+ field_offset(state, expr->type, part->u.field));
+ }
+ else if (part->op == OP_INDEX) {
+ offset += bits_to_bytes(
+ index_offset(state, expr->type, part->u.cval));
+ }
+ else {
+ internal_error(state, part, "unhandled part type");
+ }
+ result = do_mk_addr_expr(state, expr, type, offset);
+ }
if (!result) {
internal_error(state, expr, "cannot take address of expression");
}
@@ -4955,6 +7452,10 @@ static struct triple *mk_deref_expr(
return triple(state, OP_DEREF, base_type, expr, 0);
}
+/* lvalue conversions always apply except when certain operators
+ * are applied. So I apply apply it when I know no more
+ * operators will be applied.
+ */
static struct triple *lvalue_conversion(struct compile_state *state, struct triple *def)
{
/* Tranform an array to a pointer to the first element */
@@ -4973,7 +7474,7 @@ static struct triple *lvalue_conversion(struct compile_state *state, struct trip
def = addrconst;
}
else {
- def = triple(state, OP_COPY, type, def, 0);
+ def = triple(state, OP_CONVERT, type, def, 0);
}
}
/* Transform a function to a pointer to it */
@@ -4988,20 +7489,21 @@ static struct triple *deref_field(
{
struct triple *result;
struct type *type, *member;
+ ulong_t offset;
if (!field) {
internal_error(state, 0, "No field passed to deref_field");
}
result = 0;
type = expr->type;
- if ((type->type & TYPE_MASK) != TYPE_STRUCT) {
+ if (((type->type & TYPE_MASK) != TYPE_STRUCT) &&
+ ((type->type & TYPE_MASK) != TYPE_UNION)) {
error(state, 0, "request for member %s in something not a struct or union",
field->name);
}
member = field_type(state, type, field);
if ((type->type & STOR_MASK) == STOR_PERM) {
/* Do the pointer arithmetic to get a deref the field */
- ulong_t offset;
- offset = field_offset(state, type, field);
+ offset = bits_to_bytes(field_offset(state, type, field));
result = do_mk_addr_expr(state, expr, member, offset);
result = mk_deref_expr(state, result);
}
@@ -5013,6 +7515,29 @@ static struct triple *deref_field(
return result;
}
+static struct triple *deref_index(
+ struct compile_state *state, struct triple *expr, size_t index)
+{
+ struct triple *result;
+ struct type *type, *member;
+ ulong_t offset;
+
+ result = 0;
+ type = expr->type;
+ member = index_type(state, type, index);
+
+ if ((type->type & STOR_MASK) == STOR_PERM) {
+ offset = bits_to_bytes(index_offset(state, type, index));
+ result = do_mk_addr_expr(state, expr, member, offset);
+ result = mk_deref_expr(state, result);
+ }
+ else {
+ result = triple(state, OP_INDEX, member, expr, 0);
+ result->u.cval = index;
+ }
+ return result;
+}
+
static struct triple *read_expr(struct compile_state *state, struct triple *def)
{
int op;
@@ -5022,7 +7547,7 @@ static struct triple *read_expr(struct compile_state *state, struct triple *def)
#warning "CHECK_ME is this the only place I need to do lvalue conversions?"
/* Transform lvalues into something we can read */
def = lvalue_conversion(state, def);
- if (!is_stable(state, def)) {
+ if (!is_lvalue(state, def)) {
return def;
}
if (is_in_reg(state, def)) {
@@ -5034,7 +7559,11 @@ static struct triple *read_expr(struct compile_state *state, struct triple *def)
}
op = OP_LOAD;
}
- return triple(state, op, def->type, def, 0);
+ def = triple(state, op, def->type, def, 0);
+ if (def->type->type & QUAL_VOLATILE) {
+ def->id |= TRIPLE_FLAG_VOLATILE;
+ }
+ return def;
}
int is_write_compatible(struct compile_state *state,
@@ -5057,19 +7586,22 @@ int is_write_compatible(struct compile_state *state,
compatible = 1;
}
/* test for struct/union equality */
- else if (((dest->type & TYPE_MASK) == TYPE_STRUCT) &&
- ((rval->type & TYPE_MASK) == TYPE_STRUCT) &&
- (dest->type_ident == rval->type_ident)) {
+ else if (equiv_types(dest, rval)) {
compatible = 1;
}
return compatible;
}
-
static void write_compatible(struct compile_state *state,
struct type *dest, struct type *rval)
{
if (!is_write_compatible(state, dest, rval)) {
+ FILE *fp = state->errout;
+ fprintf(fp, "dest: ");
+ name_of(fp, dest);
+ fprintf(fp,"\nrval: ");
+ name_of(fp, rval);
+ fprintf(fp, "\n");
error(state, 0, "Incompatible types in assignment");
}
}
@@ -5109,15 +7641,26 @@ static struct triple *write_expr(
}
write_compatible(state, dest->type, rval->type);
+ if (!equiv_types(dest->type, rval->type)) {
+ rval = triple(state, OP_CONVERT, dest->type, rval, 0);
+ }
/* Now figure out which assignment operator to use */
op = -1;
if (is_in_reg(state, dest)) {
- op = OP_WRITE;
+ def = triple(state, OP_WRITE, dest->type, rval, dest);
+ if (MISC(def, 0) != dest) {
+ internal_error(state, def, "huh?");
+ }
+ if (RHS(def, 0) != rval) {
+ internal_error(state, def, "huh?");
+ }
} else {
- op = OP_STORE;
+ def = triple(state, OP_STORE, dest->type, dest, rval);
+ }
+ if (def->type->type & QUAL_VOLATILE) {
+ def->id |= TRIPLE_FLAG_VOLATILE;
}
- def = triple(state, op, dest->type, dest, rval);
return def;
}
@@ -5162,8 +7705,9 @@ struct type *arithmetic_result(
arithmetic(state, right);
type = new_type(
do_arithmetic_conversion(
- left->type->type,
- right->type->type), 0, 0);
+ get_basic_type(left->type),
+ get_basic_type(right->type)),
+ 0, 0);
return type;
}
@@ -5188,7 +7732,6 @@ struct type *ptr_arithmetic_result(
return type;
}
-
/* boolean helper function */
static struct triple *ltrue_expr(struct compile_state *state,
@@ -5213,11 +7756,70 @@ static struct triple *lfalse_expr(struct compile_state *state,
return triple(state, OP_LFALSE, &int_type, expr, 0);
}
-static struct triple *cond_expr(
+static struct triple *mkland_expr(
+ struct compile_state *state,
+ struct triple *left, struct triple *right)
+{
+ struct triple *def, *val, *var, *jmp, *mid, *end;
+
+ /* Generate some intermediate triples */
+ end = label(state);
+ var = variable(state, &int_type);
+
+ /* Store the left hand side value */
+ left = write_expr(state, var, left);
+
+ /* Jump if the value is false */
+ jmp = branch(state, end,
+ lfalse_expr(state, read_expr(state, var)));
+ mid = label(state);
+
+ /* Store the right hand side value */
+ right = write_expr(state, var, right);
+
+ /* An expression for the computed value */
+ val = read_expr(state, var);
+
+ /* Generate the prog for a logical and */
+ def = mkprog(state, var, left, jmp, mid, right, end, val, 0);
+
+ return def;
+}
+
+static struct triple *mklor_expr(
+ struct compile_state *state,
+ struct triple *left, struct triple *right)
+{
+ struct triple *def, *val, *var, *jmp, *mid, *end;
+
+ /* Generate some intermediate triples */
+ end = label(state);
+ var = variable(state, &int_type);
+
+ /* Store the left hand side value */
+ left = write_expr(state, var, left);
+
+ /* Jump if the value is true */
+ jmp = branch(state, end, read_expr(state, var));
+ mid = label(state);
+
+ /* Store the right hand side value */
+ right = write_expr(state, var, right);
+
+ /* An expression for the computed value*/
+ val = read_expr(state, var);
+
+ /* Generate the prog for a logical or */
+ def = mkprog(state, var, left, jmp, mid, right, end, val, 0);
+
+ return def;
+}
+
+static struct triple *mkcond_expr(
struct compile_state *state,
struct triple *test, struct triple *left, struct triple *right)
{
- struct triple *def;
+ struct triple *def, *val, *var, *jmp1, *jmp2, *top, *mid, *end;
struct type *result_type;
unsigned int left_type, right_type;
bool(state, test);
@@ -5252,18 +7854,37 @@ static struct triple *cond_expr(
if (!result_type) {
error(state, 0, "Incompatible types in conditional expression");
}
- /* Cleanup and invert the test */
- test = lfalse_expr(state, read_expr(state, test));
- def = new_triple(state, OP_COND, result_type, 0, 3);
- def->param[0] = test;
- def->param[1] = left;
- def->param[2] = right;
+ /* Generate some intermediate triples */
+ mid = label(state);
+ end = label(state);
+ var = variable(state, result_type);
+
+ /* Branch if the test is false */
+ jmp1 = branch(state, mid, lfalse_expr(state, read_expr(state, test)));
+ top = label(state);
+
+ /* Store the left hand side value */
+ left = write_expr(state, var, left);
+
+ /* Branch to the end */
+ jmp2 = branch(state, end, 0);
+
+ /* Store the right hand side value */
+ right = write_expr(state, var, right);
+
+ /* An expression for the computed value */
+ val = read_expr(state, var);
+
+ /* Generate the prog for a conditional expression */
+ def = mkprog(state, var, jmp1, top, left, jmp2, mid, right, end, val, 0);
+
return def;
}
static int expr_depth(struct compile_state *state, struct triple *ins)
{
+#warning "FIXME move optimal ordering of subexpressions into the optimizer"
int count;
count = 0;
if (!ins || (ins->id & TRIPLE_FLAG_FLATTENED)) {
@@ -5275,12 +7896,6 @@ static int expr_depth(struct compile_state *state, struct triple *ins)
else if (ins->op == OP_VAL) {
count = expr_depth(state, RHS(ins, 0)) - 1;
}
- else if (ins->op == OP_COMMA) {
- int ldepth, rdepth;
- ldepth = expr_depth(state, RHS(ins, 0));
- rdepth = expr_depth(state, RHS(ins, 1));
- count = (ldepth >= rdepth)? ldepth : rdepth;
- }
else if (ins->op == OP_FCALL) {
/* Don't figure the depth of a call just guess it is huge */
count = 1000;
@@ -5301,9 +7916,6 @@ static int expr_depth(struct compile_state *state, struct triple *ins)
return count + 1;
}
-static struct triple *flatten(
- struct compile_state *state, struct triple *first, struct triple *ptr);
-
static struct triple *flatten_generic(
struct compile_state *state, struct triple *first, struct triple *ptr,
int ignored)
@@ -5314,9 +7926,9 @@ static struct triple *flatten_generic(
} vector[MAX_RHS];
int i, rhs, lhs;
/* Only operations with just a rhs and a lhs should come here */
- rhs = TRIPLE_RHS(ptr->sizes);
- lhs = TRIPLE_LHS(ptr->sizes);
- if (TRIPLE_SIZE(ptr->sizes) != lhs + rhs + ignored) {
+ rhs = ptr->rhs;
+ lhs = ptr->lhs;
+ if (TRIPLE_SIZE(ptr) != lhs + rhs + ignored) {
internal_error(state, ptr, "unexpected args for: %d %s",
ptr->op, tops(ptr->op));
}
@@ -5345,104 +7957,62 @@ static struct triple *flatten_generic(
*vector[i].ins = flatten(state, first, *vector[i].ins);
use_triple(*vector[i].ins, ptr);
}
-
- /* Now flatten the lhs elements */
- for(i = 0; i < lhs; i++) {
- struct triple **ins = &LHS(ptr, i);
- *ins = flatten(state, first, *ins);
- use_triple(*ins, ptr);
+ if (lhs) {
+ insert_triple(state, first, ptr);
+ ptr->id |= TRIPLE_FLAG_FLATTENED;
+ ptr->id &= ~TRIPLE_FLAG_LOCAL;
+
+ /* Now flatten the lhs elements */
+ for(i = 0; i < lhs; i++) {
+ struct triple **ins = &LHS(ptr, i);
+ *ins = flatten(state, first, *ins);
+ use_triple(*ins, ptr);
+ }
}
return ptr;
}
-static struct triple *flatten_land(
+static struct triple *flatten_prog(
struct compile_state *state, struct triple *first, struct triple *ptr)
{
- struct triple *left, *right;
- struct triple *val, *test, *jmp, *label1, *end;
-
- /* Find the triples */
- left = RHS(ptr, 0);
- right = RHS(ptr, 1);
-
- /* Generate the needed triples */
- end = label(state);
-
- /* Thread the triples together */
- val = flatten(state, first, variable(state, ptr->type));
- left = flatten(state, first, write_expr(state, val, left));
- test = flatten(state, first,
- lfalse_expr(state, read_expr(state, val)));
- jmp = flatten(state, first, branch(state, end, test));
- label1 = flatten(state, first, label(state));
- right = flatten(state, first, write_expr(state, val, right));
- TARG(jmp, 0) = flatten(state, first, end);
+ struct triple *head, *body, *val;
+ head = RHS(ptr, 0);
+ RHS(ptr, 0) = 0;
+ val = head->prev;
+ body = head->next;
+ release_triple(state, head);
+ release_triple(state, ptr);
+ val->next = first;
+ body->prev = first->prev;
+ body->prev->next = body;
+ val->next->prev = val;
+
+ if (triple_is_cbranch(state, body->prev) ||
+ triple_is_call(state, body->prev)) {
+ unuse_triple(first, body->prev);
+ use_triple(body, body->prev);
+ }
- /* Now give the caller something to chew on */
- return read_expr(state, val);
-}
-
-static struct triple *flatten_lor(
- struct compile_state *state, struct triple *first, struct triple *ptr)
-{
- struct triple *left, *right;
- struct triple *val, *jmp, *label1, *end;
-
- /* Find the triples */
- left = RHS(ptr, 0);
- right = RHS(ptr, 1);
-
- /* Generate the needed triples */
- end = label(state);
+ if (!(val->id & TRIPLE_FLAG_FLATTENED)) {
+ internal_error(state, val, "val not flattened?");
+ }
- /* Thread the triples together */
- val = flatten(state, first, variable(state, ptr->type));
- left = flatten(state, first, write_expr(state, val, left));
- jmp = flatten(state, first, branch(state, end, left));
- label1 = flatten(state, first, label(state));
- right = flatten(state, first, write_expr(state, val, right));
- TARG(jmp, 0) = flatten(state, first, end);
-
-
- /* Now give the caller something to chew on */
- return read_expr(state, val);
+ return val;
}
-static struct triple *flatten_cond(
- struct compile_state *state, struct triple *first, struct triple *ptr)
-{
- struct triple *test, *left, *right;
- struct triple *val, *mv1, *jmp1, *label1, *mv2, *middle, *jmp2, *end;
-
- /* Find the triples */
- test = RHS(ptr, 0);
- left = RHS(ptr, 1);
- right = RHS(ptr, 2);
- /* Generate the needed triples */
- end = label(state);
- middle = label(state);
-
- /* Thread the triples together */
- val = flatten(state, first, variable(state, ptr->type));
- test = flatten(state, first, test);
- jmp1 = flatten(state, first, branch(state, middle, test));
- label1 = flatten(state, first, label(state));
- left = flatten(state, first, left);
- mv1 = flatten(state, first, write_expr(state, val, left));
- jmp2 = flatten(state, first, branch(state, end, 0));
- TARG(jmp1, 0) = flatten(state, first, middle);
- right = flatten(state, first, right);
- mv2 = flatten(state, first, write_expr(state, val, right));
- TARG(jmp2, 0) = flatten(state, first, end);
-
- /* Now give the caller something to chew on */
- return read_expr(state, val);
-}
-
-static struct triple *flatten_fcall(
+static struct triple *flatten_part(
struct compile_state *state, struct triple *first, struct triple *ptr)
{
+ if (!triple_is_part(state, ptr)) {
+ internal_error(state, ptr, "not a part");
+ }
+ if (ptr->rhs || ptr->lhs || ptr->targ || (ptr->misc != 1)) {
+ internal_error(state, ptr, "unexpected args for: %d %s",
+ ptr->op, tops(ptr->op));
+ }
+ MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
+ use_triple(MISC(ptr, 0), ptr);
return flatten_generic(state, first, ptr, 1);
}
@@ -5459,31 +8029,32 @@ static struct triple *flatten(
return ptr;
}
switch(ptr->op) {
- case OP_COMMA:
- RHS(ptr, 0) = flatten(state, first, RHS(ptr, 0));
- ptr = RHS(ptr, 1);
- break;
case OP_VAL:
RHS(ptr, 0) = flatten(state, first, RHS(ptr, 0));
return MISC(ptr, 0);
break;
- case OP_LAND:
- ptr = flatten_land(state, first, ptr);
- break;
- case OP_LOR:
- ptr = flatten_lor(state, first, ptr);
- break;
- case OP_COND:
- ptr = flatten_cond(state, first, ptr);
+ case OP_PROG:
+ ptr = flatten_prog(state, first, ptr);
break;
case OP_FCALL:
- ptr = flatten_fcall(state, first, ptr);
+ ptr = flatten_generic(state, first, ptr, 1);
+ insert_triple(state, first, ptr);
+ ptr->id |= TRIPLE_FLAG_FLATTENED;
+ ptr->id &= ~TRIPLE_FLAG_LOCAL;
+ if (ptr->next != ptr) {
+ use_triple(ptr->next, ptr);
+ }
break;
case OP_READ:
case OP_LOAD:
RHS(ptr, 0) = flatten(state, first, RHS(ptr, 0));
use_triple(RHS(ptr, 0), ptr);
break;
+ case OP_WRITE:
+ ptr = flatten_generic(state, first, ptr, 1);
+ MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
+ use_triple(MISC(ptr, 0), ptr);
+ break;
case OP_BRANCH:
use_triple(TARG(ptr, 0), ptr);
break;
@@ -5491,6 +8062,9 @@ static struct triple *flatten(
RHS(ptr, 0) = flatten(state, first, RHS(ptr, 0));
use_triple(RHS(ptr, 0), ptr);
use_triple(TARG(ptr, 0), ptr);
+ insert_triple(state, first, ptr);
+ ptr->id |= TRIPLE_FLAG_FLATTENED;
+ ptr->id &= ~TRIPLE_FLAG_LOCAL;
if (ptr->next != ptr) {
use_triple(ptr->next, ptr);
}
@@ -5499,6 +8073,9 @@ static struct triple *flatten(
MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
use_triple(MISC(ptr, 0), ptr);
use_triple(TARG(ptr, 0), ptr);
+ insert_triple(state, first, ptr);
+ ptr->id |= TRIPLE_FLAG_FLATTENED;
+ ptr->id &= ~TRIPLE_FLAG_LOCAL;
if (ptr->next != ptr) {
use_triple(ptr->next, ptr);
}
@@ -5521,28 +8098,39 @@ static struct triple *flatten(
free_triple(state, orig_ptr);
break;
case OP_DOT:
- {
- struct triple *base;
- base = RHS(ptr, 0);
- if (base->op == OP_DEREF) {
- struct triple *left;
+ if (RHS(ptr, 0)->op == OP_DEREF) {
+ struct triple *base, *left;
ulong_t offset;
- offset = field_offset(state, base->type, ptr->u.field);
+ base = MISC(ptr, 0);
+ offset = bits_to_bytes(field_offset(state, base->type, ptr->u.field));
left = RHS(base, 0);
ptr = triple(state, OP_ADD, left->type,
read_expr(state, left),
int_const(state, &ulong_type, offset));
free_triple(state, base);
}
- else if (base->op == OP_VAL_VEC) {
- base = flatten(state, first, base);
- ptr = struct_field(state, base, ptr->u.field);
+ else {
+ ptr = flatten_part(state, first, ptr);
+ }
+ break;
+ case OP_INDEX:
+ if (RHS(ptr, 0)->op == OP_DEREF) {
+ struct triple *base, *left;
+ ulong_t offset;
+ base = MISC(ptr, 0);
+ offset = bits_to_bytes(index_offset(state, base->type, ptr->u.cval));
+ left = RHS(base, 0);
+ ptr = triple(state, OP_ADD, left->type,
+ read_expr(state, left),
+ int_const(state, &long_type, offset));
+ free_triple(state, base);
+ }
+ else {
+ ptr = flatten_part(state, first, ptr);
}
break;
- }
case OP_PIECE:
- MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
- use_triple(MISC(ptr, 0), ptr);
+ ptr = flatten_part(state, first, ptr);
use_triple(ptr, MISC(ptr, 0));
break;
case OP_ADDRCONST:
@@ -5558,6 +8146,7 @@ static struct triple *flatten(
ptr->id &= ~TRIPLE_FLAG_LOCAL;
return ptr;
case OP_ADECL:
+ ptr = flatten_generic(state, first, ptr, 0);
break;
default:
/* Flatten the easy cases we don't override */
@@ -5565,7 +8154,7 @@ static struct triple *flatten(
break;
}
} while(ptr && (ptr != orig_ptr));
- if (ptr) {
+ if (ptr && !(ptr->id & TRIPLE_FLAG_FLATTENED)) {
insert_triple(state, first, ptr);
ptr->id |= TRIPLE_FLAG_FLATTENED;
ptr->id &= ~TRIPLE_FLAG_LOCAL;
@@ -5624,21 +8213,71 @@ static int replace_lhs_use(struct compile_state *state,
return found;
}
+static int replace_misc_use(struct compile_state *state,
+ struct triple *orig, struct triple *new, struct triple *use)
+{
+ struct triple **expr;
+ int found;
+ found = 0;
+ expr = triple_misc(state, use, 0);
+ for(;expr; expr = triple_misc(state, use, expr)) {
+ if (*expr == orig) {
+ *expr = new;
+ found = 1;
+ }
+ }
+ if (found) {
+ unuse_triple(orig, use);
+ use_triple(new, use);
+ }
+ return found;
+}
+
+static int replace_targ_use(struct compile_state *state,
+ struct triple *orig, struct triple *new, struct triple *use)
+{
+ struct triple **expr;
+ int found;
+ found = 0;
+ expr = triple_targ(state, use, 0);
+ for(;expr; expr = triple_targ(state, use, expr)) {
+ if (*expr == orig) {
+ *expr = new;
+ found = 1;
+ }
+ }
+ if (found) {
+ unuse_triple(orig, use);
+ use_triple(new, use);
+ }
+ return found;
+}
+
+static void replace_use(struct compile_state *state,
+ struct triple *orig, struct triple *new, struct triple *use)
+{
+ int found;
+ found = 0;
+ found |= replace_rhs_use(state, orig, new, use);
+ found |= replace_lhs_use(state, orig, new, use);
+ found |= replace_misc_use(state, orig, new, use);
+ found |= replace_targ_use(state, orig, new, use);
+ if (!found) {
+ internal_error(state, use, "use without use");
+ }
+}
+
static void propogate_use(struct compile_state *state,
struct triple *orig, struct triple *new)
{
struct triple_set *user, *next;
for(user = orig->use; user; user = next) {
- struct triple *use;
- int found;
+ /* Careful replace_use modifies the use chain and
+ * removes use. So we must get a copy of the next
+ * entry early.
+ */
next = user->next;
- use = user->member;
- found = 0;
- found |= replace_rhs_use(state, orig, new, use);
- found |= replace_lhs_use(state, orig, new, use);
- if (!found) {
- internal_error(state, use, "use without use");
- }
+ replace_use(state, orig, new, user->member);
}
if (orig->use) {
internal_error(state, orig, "used after propogate_use");
@@ -5650,6 +8289,15 @@ static void propogate_use(struct compile_state *state,
* ===========================
*/
+static struct triple *mk_cast_expr(
+ struct compile_state *state, struct type *type, struct triple *expr)
+{
+ struct triple *def;
+ def = read_expr(state, expr);
+ def = triple(state, OP_CONVERT, type, def, 0);
+ return def;
+}
+
static struct triple *mk_add_expr(
struct compile_state *state, struct triple *left, struct triple *right)
{
@@ -5665,12 +8313,21 @@ static struct triple *mk_add_expr(
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,
- &ulong_type,
- right,
- int_const(state, &ulong_type,
- size_of(state, left->type->left)));
+ struct type *ptr_math;
+ int op;
+ if (is_signed(right->type)) {
+ ptr_math = &long_type;
+ op = OP_SMUL;
+ } else {
+ ptr_math = &ulong_type;
+ op = OP_UMUL;
+ }
+ if (!equiv_types(right->type, ptr_math)) {
+ right = mk_cast_expr(state, ptr_math, right);
+ }
+ right = triple(state, op, ptr_math, right,
+ int_const(state, ptr_math,
+ size_of_in_bytes(state, left->type->left)));
}
return triple(state, OP_ADD, result_type, left, right);
}
@@ -5683,12 +8340,21 @@ static struct triple *mk_sub_expr(
left = read_expr(state, left);
right = read_expr(state, right);
if (is_pointer(left)) {
- right = triple(state,
- is_signed(right->type)? OP_SMUL : OP_UMUL,
- &ulong_type,
- right,
- int_const(state, &ulong_type,
- size_of(state, left->type->left)));
+ struct type *ptr_math;
+ int op;
+ if (is_signed(right->type)) {
+ ptr_math = &long_type;
+ op = OP_SMUL;
+ } else {
+ ptr_math = &ulong_type;
+ op = OP_UMUL;
+ }
+ if (!equiv_types(right->type, ptr_math)) {
+ right = mk_cast_expr(state, ptr_math, right);
+ }
+ right = triple(state, op, ptr_math, right,
+ int_const(state, ptr_math,
+ size_of_in_bytes(state, left->type->left)));
}
return triple(state, OP_SUB, result_type, left, right);
}
@@ -5750,14 +8416,6 @@ static struct triple *mk_subscript_expr(
return mk_deref_expr(state, mk_add_expr(state, left, right));
}
-static struct triple *mk_cast_expr(
- struct compile_state *state, struct type *type, struct triple *expr)
-{
- struct triple *def;
- def = read_expr(state, expr);
- def = triple(state, OP_COPY, type, def, 0);
- return def;
-}
/*
* Compile time evaluation
@@ -5770,14 +8428,22 @@ static int is_const(struct triple *ins)
static int is_simple_const(struct triple *ins)
{
- return IS_CONST_OP(ins->op) && (ins->op != OP_ADDRCONST);
+ /* Is this a constant that u.cval has the value.
+ * Or equivalently is this a constant that read_const
+ * works on.
+ * So far only OP_INTCONST qualifies.
+ */
+ return (ins->op == OP_INTCONST);
}
static int constants_equal(struct compile_state *state,
struct triple *left, struct triple *right)
{
int equal;
- if (!is_const(left) || !is_const(right)) {
+ if ((left->op == OP_UNKNOWNVAL) || (right->op == OP_UNKNOWNVAL)) {
+ equal = 0;
+ }
+ else if (!is_const(left) || !is_const(right)) {
equal = 0;
}
else if (left->op != right->op) {
@@ -5796,13 +8462,14 @@ static int constants_equal(struct compile_state *state,
break;
case OP_BLOBCONST:
{
- size_t lsize, rsize;
+ size_t lsize, rsize, bytes;
lsize = size_of(state, left->type);
rsize = size_of(state, right->type);
if (lsize != rsize) {
break;
}
- if (memcmp(left->u.blob, right->u.blob, lsize) == 0) {
+ bytes = bits_to_bytes(lsize);
+ if (memcmp(left->u.blob, right->u.blob, bytes) == 0) {
equal = 1;
}
break;
@@ -5915,13 +8582,17 @@ static ulong_t read_const(struct compile_state *state,
case TYPE_UINT:
case TYPE_ULONG:
case TYPE_POINTER:
+ case TYPE_BITFIELD:
break;
default:
- internal_error(state, rhs, "bad type to read_const\n");
+ fprintf(state->errout, "type: ");
+ name_of(state->errout, rhs->type);
+ fprintf(state->errout, "\n");
+ internal_warning(state, rhs, "bad type to read_const");
break;
}
if (!is_simple_const(rhs)) {
- internal_error(state, rhs, "bad op to read_const\n");
+ internal_error(state, rhs, "bad op to read_const");
}
return rhs->u.cval;
}
@@ -5935,7 +8606,7 @@ static long_t read_sconst(struct compile_state *state,
int const_ltrue(struct compile_state *state, struct triple *ins, struct triple *rhs)
{
if (!is_const(rhs)) {
- internal_error(state, 0, "non const passed to const_true\n");
+ internal_error(state, 0, "non const passed to const_true");
}
return !is_zero(rhs);
}
@@ -5945,8 +8616,8 @@ int const_eq(struct compile_state *state, struct triple *ins,
{
int result;
if (!is_const(left) || !is_const(right)) {
- internal_error(state, ins, "non const passed to const_eq\n");
- result = 0;
+ internal_warning(state, ins, "non const passed to const_eq");
+ result = -1;
}
else if (left == right) {
result = 1;
@@ -5963,8 +8634,8 @@ int const_eq(struct compile_state *state, struct triple *ins,
(left->u.cval == right->u.cval);
}
else {
- internal_error(state, ins, "incomparable constants passed to const_eq\n");
- result = 0;
+ internal_warning(state, ins, "incomparable constants passed to const_eq");
+ result = -1;
}
return result;
@@ -5975,7 +8646,7 @@ int const_ucmp(struct compile_state *state, struct triple *ins,
{
int result;
if (!is_const(left) || !is_const(right)) {
- internal_error(state, ins, "non const past to ucmp_const\n");
+ internal_warning(state, ins, "non const past to const_ucmp");
result = -2;
}
else if (left == right) {
@@ -6003,7 +8674,7 @@ int const_ucmp(struct compile_state *state, struct triple *ins,
}
}
else {
- internal_error(state, ins, "incomparable constants passed to const_ucmp\n");
+ internal_warning(state, ins, "incomparable constants passed to const_ucmp");
result = -2;
}
return result;
@@ -6014,7 +8685,7 @@ int const_scmp(struct compile_state *state, struct triple *ins,
{
int result;
if (!is_const(left) || !is_const(right)) {
- internal_error(state, ins, "non const past to ucmp_const\n");
+ internal_warning(state, ins, "non const past to ucmp_const");
result = -2;
}
else if (left == right) {
@@ -6032,7 +8703,7 @@ int const_scmp(struct compile_state *state, struct triple *ins,
}
}
else {
- internal_error(state, ins, "incomparable constants passed to const_scmp\n");
+ internal_warning(state, ins, "incomparable constants passed to const_scmp");
result = -2;
}
return result;
@@ -6060,6 +8731,27 @@ static void unuse_lhs(struct compile_state *state, struct triple *ins)
}
}
+static void unuse_misc(struct compile_state *state, struct triple *ins)
+{
+ struct triple **expr;
+ expr = triple_misc(state, ins, 0);
+ for(;expr;expr = triple_misc(state, ins, expr)) {
+ unuse_triple(*expr, ins);
+ *expr = 0;
+ }
+}
+
+static void unuse_targ(struct compile_state *state, struct triple *ins)
+{
+ int i;
+ struct triple **slot;
+ slot = &TARG(ins, 0);
+ for(i = 0; i < ins->targ; i++) {
+ unuse_triple(slot[i], ins);
+ slot[i] = 0;
+ }
+}
+
static void check_lhs(struct compile_state *state, struct triple *ins)
{
struct triple **expr;
@@ -6069,6 +8761,18 @@ static void check_lhs(struct compile_state *state, struct triple *ins)
}
}
+
+static void check_misc(struct compile_state *state, struct triple *ins)
+{
+ struct triple **expr;
+ expr = triple_misc(state, ins, 0);
+ for(;expr;expr = triple_misc(state, ins, expr)) {
+ if (*expr) {
+ internal_error(state, ins, "unexpected misc");
+ }
+ }
+}
+
static void check_targ(struct compile_state *state, struct triple *ins)
{
struct triple **expr;
@@ -6085,18 +8789,48 @@ static void wipe_ins(struct compile_state *state, struct triple *ins)
* in all instructions to hold all others.
*/
check_targ(state, ins);
+ check_misc(state, ins);
+ unuse_rhs(state, ins);
+ unuse_lhs(state, ins);
+ ins->lhs = 0;
+ ins->rhs = 0;
+ ins->misc = 0;
+ ins->targ = 0;
+}
+
+static void wipe_branch(struct compile_state *state, struct triple *ins)
+{
+ /* Becareful which instructions you replace the wiped
+ * instruction with, as there are not enough slots
+ * in all instructions to hold all others.
+ */
unuse_rhs(state, ins);
unuse_lhs(state, ins);
+ unuse_misc(state, ins);
+ unuse_targ(state, ins);
+ ins->lhs = 0;
+ ins->rhs = 0;
+ ins->misc = 0;
+ ins->targ = 0;
}
static void mkcopy(struct compile_state *state,
struct triple *ins, struct triple *rhs)
{
struct block *block;
+ if (!equiv_types(ins->type, rhs->type)) {
+ FILE *fp = state->errout;
+ fprintf(fp, "src type: ");
+ name_of(fp, rhs->type);
+ fprintf(fp, "\ndst type: ");
+ name_of(fp, ins->type);
+ fprintf(fp, "\n");
+ internal_error(state, ins, "mkcopy type mismatch");
+ }
block = block_of_triple(state, ins);
wipe_ins(state, ins);
ins->op = OP_COPY;
- ins->sizes = TRIPLE_SIZES(0, 1, 0, 0);
+ ins->rhs = 1;
ins->u.block = block;
RHS(ins, 0) = rhs;
use_triple(RHS(ins, 0), ins);
@@ -6106,148 +8840,549 @@ static void mkconst(struct compile_state *state,
struct triple *ins, ulong_t value)
{
if (!is_integral(ins) && !is_pointer(ins)) {
- internal_error(state, ins, "unknown type to make constant\n");
+ fprintf(state->errout, "type: ");
+ name_of(state->errout, ins->type);
+ fprintf(state->errout, "\n");
+ internal_error(state, ins, "unknown type to make constant value: %ld",
+ value);
}
wipe_ins(state, ins);
ins->op = OP_INTCONST;
- ins->sizes = TRIPLE_SIZES(0, 0, 0, 0);
ins->u.cval = value;
}
static void mkaddr_const(struct compile_state *state,
struct triple *ins, struct triple *sdecl, ulong_t value)
{
- if (sdecl->op != OP_SDECL) {
+ if ((sdecl->op != OP_SDECL) && (sdecl->op != OP_LABEL)) {
internal_error(state, ins, "bad base for addrconst");
}
wipe_ins(state, ins);
ins->op = OP_ADDRCONST;
- ins->sizes = TRIPLE_SIZES(0, 0, 1, 0);
+ ins->misc = 1;
MISC(ins, 0) = sdecl;
ins->u.cval = value;
use_triple(sdecl, ins);
}
-/* Transform multicomponent variables into simple register variables */
-static void flatten_structures(struct compile_state *state)
+#if DEBUG_DECOMPOSE_PRINT_TUPLES
+static void print_tuple(struct compile_state *state,
+ struct triple *ins, struct triple *tuple)
{
- struct triple *ins, *first;
+ FILE *fp = state->dbgout;
+ fprintf(fp, "%5s %p tuple: %p ", tops(ins->op), ins, tuple);
+ name_of(fp, tuple->type);
+ if (tuple->lhs > 0) {
+ fprintf(fp, " lhs: ");
+ name_of(fp, LHS(tuple, 0)->type);
+ }
+ fprintf(fp, "\n");
+
+}
+#endif
+
+static struct triple *decompose_with_tuple(struct compile_state *state,
+ struct triple *ins, struct triple *tuple)
+{
+ struct triple *next;
+ next = ins->next;
+ flatten(state, next, tuple);
+#if DEBUG_DECOMPOSE_PRINT_TUPLES
+ print_tuple(state, ins, tuple);
+#endif
+
+ if (!is_compound_type(tuple->type) && (tuple->lhs > 0)) {
+ struct triple *tmp;
+ if (tuple->lhs != 1) {
+ internal_error(state, tuple, "plain type in multiple registers?");
+ }
+ tmp = LHS(tuple, 0);
+ release_triple(state, tuple);
+ tuple = tmp;
+ }
+
+ propogate_use(state, ins, tuple);
+ release_triple(state, ins);
+
+ return next;
+}
+
+static struct triple *decompose_unknownval(struct compile_state *state,
+ struct triple *ins)
+{
+ struct triple *tuple;
+ ulong_t i;
+
+#if DEBUG_DECOMPOSE_HIRES
+ FILE *fp = state->dbgout;
+ fprintf(fp, "unknown type: ");
+ name_of(fp, ins->type);
+ fprintf(fp, "\n");
+#endif
+
+ get_occurance(ins->occurance);
+ tuple = alloc_triple(state, OP_TUPLE, ins->type, -1, -1,
+ ins->occurance);
+
+ for(i = 0; i < tuple->lhs; i++) {
+ struct type *piece_type;
+ struct triple *unknown;
+
+ piece_type = reg_type(state, ins->type, i * REG_SIZEOF_REG);
+ get_occurance(tuple->occurance);
+ unknown = alloc_triple(state, OP_UNKNOWNVAL, piece_type, 0, 0,
+ tuple->occurance);
+ LHS(tuple, i) = unknown;
+ }
+ return decompose_with_tuple(state, ins, tuple);
+}
+
+
+static struct triple *decompose_read(struct compile_state *state,
+ struct triple *ins)
+{
+ struct triple *tuple, *lval;
+ ulong_t i;
+
+ lval = RHS(ins, 0);
+
+ if (lval->op == OP_PIECE) {
+ return ins->next;
+ }
+ get_occurance(ins->occurance);
+ tuple = alloc_triple(state, OP_TUPLE, lval->type, -1, -1,
+ ins->occurance);
+
+ if ((tuple->lhs != lval->lhs) &&
+ (!triple_is_def(state, lval) || (tuple->lhs != 1)))
+ {
+ internal_error(state, ins, "lhs size inconsistency?");
+ }
+ for(i = 0; i < tuple->lhs; i++) {
+ struct triple *piece, *read, *bitref;
+ if ((i != 0) || !triple_is_def(state, lval)) {
+ piece = LHS(lval, i);
+ } else {
+ piece = lval;
+ }
+
+ /* See if the piece is really a bitref */
+ bitref = 0;
+ if (piece->op == OP_BITREF) {
+ bitref = piece;
+ piece = RHS(bitref, 0);
+ }
+
+ get_occurance(tuple->occurance);
+ read = alloc_triple(state, OP_READ, piece->type, -1, -1,
+ tuple->occurance);
+ RHS(read, 0) = piece;
+
+ if (bitref) {
+ struct triple *extract;
+ int op;
+ if (is_signed(bitref->type->left)) {
+ op = OP_SEXTRACT;
+ } else {
+ op = OP_UEXTRACT;
+ }
+ get_occurance(tuple->occurance);
+ extract = alloc_triple(state, op, bitref->type, -1, -1,
+ tuple->occurance);
+ RHS(extract, 0) = read;
+ extract->u.bitfield.size = bitref->u.bitfield.size;
+ extract->u.bitfield.offset = bitref->u.bitfield.offset;
+
+ read = extract;
+ }
+
+ LHS(tuple, i) = read;
+ }
+ return decompose_with_tuple(state, ins, tuple);
+}
+
+static struct triple *decompose_write(struct compile_state *state,
+ struct triple *ins)
+{
+ struct triple *tuple, *lval, *val;
+ ulong_t i;
+
+ lval = MISC(ins, 0);
+ val = RHS(ins, 0);
+ get_occurance(ins->occurance);
+ tuple = alloc_triple(state, OP_TUPLE, ins->type, -1, -1,
+ ins->occurance);
+
+ if ((tuple->lhs != lval->lhs) &&
+ (!triple_is_def(state, lval) || tuple->lhs != 1))
+ {
+ internal_error(state, ins, "lhs size inconsistency?");
+ }
+ for(i = 0; i < tuple->lhs; i++) {
+ struct triple *piece, *write, *pval, *bitref;
+ if ((i != 0) || !triple_is_def(state, lval)) {
+ piece = LHS(lval, i);
+ } else {
+ piece = lval;
+ }
+ if ((i == 0) && (tuple->lhs == 1) && (val->lhs == 0)) {
+ pval = val;
+ }
+ else {
+ if (i > val->lhs) {
+ internal_error(state, ins, "lhs size inconsistency?");
+ }
+ pval = LHS(val, i);
+ }
+
+ /* See if the piece is really a bitref */
+ bitref = 0;
+ if (piece->op == OP_BITREF) {
+ struct triple *read, *deposit;
+ bitref = piece;
+ piece = RHS(bitref, 0);
+
+ /* Read the destination register */
+ get_occurance(tuple->occurance);
+ read = alloc_triple(state, OP_READ, piece->type, -1, -1,
+ tuple->occurance);
+ RHS(read, 0) = piece;
+
+ /* Deposit the new bitfield value */
+ get_occurance(tuple->occurance);
+ deposit = alloc_triple(state, OP_DEPOSIT, piece->type, -1, -1,
+ tuple->occurance);
+ RHS(deposit, 0) = read;
+ RHS(deposit, 1) = pval;
+ deposit->u.bitfield.size = bitref->u.bitfield.size;
+ deposit->u.bitfield.offset = bitref->u.bitfield.offset;
+
+ /* Now write the newly generated value */
+ pval = deposit;
+ }
+
+ get_occurance(tuple->occurance);
+ write = alloc_triple(state, OP_WRITE, piece->type, -1, -1,
+ tuple->occurance);
+ MISC(write, 0) = piece;
+ RHS(write, 0) = pval;
+ LHS(tuple, i) = write;
+ }
+ return decompose_with_tuple(state, ins, tuple);
+}
+
+struct decompose_load_info {
+ struct occurance *occurance;
+ struct triple *lval;
+ struct triple *tuple;
+};
+static void decompose_load_cb(struct compile_state *state,
+ struct type *type, size_t reg_offset, size_t mem_offset, void *arg)
+{
+ struct decompose_load_info *info = arg;
+ struct triple *load;
+
+ if (reg_offset > info->tuple->lhs) {
+ internal_error(state, info->tuple, "lhs to small?");
+ }
+ get_occurance(info->occurance);
+ load = alloc_triple(state, OP_LOAD, type, -1, -1, info->occurance);
+ RHS(load, 0) = mk_addr_expr(state, info->lval, mem_offset);
+ LHS(info->tuple, reg_offset/REG_SIZEOF_REG) = load;
+}
+
+static struct triple *decompose_load(struct compile_state *state,
+ struct triple *ins)
+{
+ struct triple *tuple;
+ struct decompose_load_info info;
+
+ if (!is_compound_type(ins->type)) {
+ return ins->next;
+ }
+ get_occurance(ins->occurance);
+ tuple = alloc_triple(state, OP_TUPLE, ins->type, -1, -1,
+ ins->occurance);
+
+ info.occurance = ins->occurance;
+ info.lval = RHS(ins, 0);
+ info.tuple = tuple;
+ walk_type_fields(state, ins->type, 0, 0, decompose_load_cb, &info);
+
+ return decompose_with_tuple(state, ins, tuple);
+}
+
+
+struct decompose_store_info {
+ struct occurance *occurance;
+ struct triple *lval;
+ struct triple *val;
+ struct triple *tuple;
+};
+static void decompose_store_cb(struct compile_state *state,
+ struct type *type, size_t reg_offset, size_t mem_offset, void *arg)
+{
+ struct decompose_store_info *info = arg;
+ struct triple *store;
+
+ if (reg_offset > info->tuple->lhs) {
+ internal_error(state, info->tuple, "lhs to small?");
+ }
+ get_occurance(info->occurance);
+ store = alloc_triple(state, OP_STORE, type, -1, -1, info->occurance);
+ RHS(store, 0) = mk_addr_expr(state, info->lval, mem_offset);
+ RHS(store, 1) = LHS(info->val, reg_offset);
+ LHS(info->tuple, reg_offset/REG_SIZEOF_REG) = store;
+}
+
+static struct triple *decompose_store(struct compile_state *state,
+ struct triple *ins)
+{
+ struct triple *tuple;
+ struct decompose_store_info info;
+
+ if (!is_compound_type(ins->type)) {
+ return ins->next;
+ }
+ get_occurance(ins->occurance);
+ tuple = alloc_triple(state, OP_TUPLE, ins->type, -1, -1,
+ ins->occurance);
+
+ info.occurance = ins->occurance;
+ info.lval = RHS(ins, 0);
+ info.val = RHS(ins, 1);
+ info.tuple = tuple;
+ walk_type_fields(state, ins->type, 0, 0, decompose_store_cb, &info);
+
+ return decompose_with_tuple(state, ins, tuple);
+}
+
+static struct triple *decompose_dot(struct compile_state *state,
+ struct triple *ins)
+{
+ struct triple *tuple, *lval;
+ struct type *type;
+ size_t reg_offset;
+ int i, idx;
+
+ lval = MISC(ins, 0);
+ reg_offset = field_reg_offset(state, lval->type, ins->u.field);
+ idx = reg_offset/REG_SIZEOF_REG;
+ type = field_type(state, lval->type, ins->u.field);
+#if DEBUG_DECOMPOSE_HIRES
+ {
+ FILE *fp = state->dbgout;
+ fprintf(fp, "field type: ");
+ name_of(fp, type);
+ fprintf(fp, "\n");
+ }
+#endif
+
+ get_occurance(ins->occurance);
+ tuple = alloc_triple(state, OP_TUPLE, type, -1, -1,
+ ins->occurance);
+
+ if (((ins->type->type & TYPE_MASK) == TYPE_BITFIELD) &&
+ (tuple->lhs != 1))
+ {
+ internal_error(state, ins, "multi register bitfield?");
+ }
+
+ for(i = 0; i < tuple->lhs; i++, idx++) {
+ struct triple *piece;
+ if (!triple_is_def(state, lval)) {
+ if (idx > lval->lhs) {
+ internal_error(state, ins, "inconsistent lhs count");
+ }
+ piece = LHS(lval, idx);
+ } else {
+ if (idx != 0) {
+ internal_error(state, ins, "bad reg_offset into def");
+ }
+ if (i != 0) {
+ internal_error(state, ins, "bad reg count from def");
+ }
+ piece = lval;
+ }
+
+ /* Remember the offset of the bitfield */
+ if ((type->type & TYPE_MASK) == TYPE_BITFIELD) {
+ get_occurance(ins->occurance);
+ piece = build_triple(state, OP_BITREF, type, piece, 0,
+ ins->occurance);
+ piece->u.bitfield.size = size_of(state, type);
+ piece->u.bitfield.offset = reg_offset % REG_SIZEOF_REG;
+ }
+ else if ((reg_offset % REG_SIZEOF_REG) != 0) {
+ internal_error(state, ins,
+ "request for a nonbitfield sub register?");
+ }
+
+ LHS(tuple, i) = piece;
+ }
+
+ return decompose_with_tuple(state, ins, tuple);
+}
+
+static struct triple *decompose_index(struct compile_state *state,
+ struct triple *ins)
+{
+ struct triple *tuple, *lval;
+ struct type *type;
+ int i, idx;
+
+ lval = MISC(ins, 0);
+ idx = index_reg_offset(state, lval->type, ins->u.cval)/REG_SIZEOF_REG;
+ type = index_type(state, lval->type, ins->u.cval);
+#if DEBUG_DECOMPOSE_HIRES
+{
+ FILE *fp = state->dbgout;
+ fprintf(fp, "index type: ");
+ name_of(fp, type);
+ fprintf(fp, "\n");
+}
+#endif
+
+ get_occurance(ins->occurance);
+ tuple = alloc_triple(state, OP_TUPLE, type, -1, -1,
+ ins->occurance);
+
+ for(i = 0; i < tuple->lhs; i++, idx++) {
+ struct triple *piece;
+ if (!triple_is_def(state, lval)) {
+ if (idx > lval->lhs) {
+ internal_error(state, ins, "inconsistent lhs count");
+ }
+ piece = LHS(lval, idx);
+ } else {
+ if (idx != 0) {
+ internal_error(state, ins, "bad reg_offset into def");
+ }
+ if (i != 0) {
+ internal_error(state, ins, "bad reg count from def");
+ }
+ piece = lval;
+ }
+ LHS(tuple, i) = piece;
+ }
+
+ return decompose_with_tuple(state, ins, tuple);
+}
+
+static void decompose_compound_types(struct compile_state *state)
+{
+ struct triple *ins, *next, *first;
+ FILE *fp;
+ fp = state->dbgout;
first = state->first;
ins = first;
- /* Pass one expand structure values into valvecs.
+
+ /* Pass one expand compound values into pseudo registers.
+ */
+ next = first;
+ do {
+ ins = next;
+ next = ins->next;
+ switch(ins->op) {
+ case OP_UNKNOWNVAL:
+ next = decompose_unknownval(state, ins);
+ break;
+
+ case OP_READ:
+ next = decompose_read(state, ins);
+ break;
+
+ case OP_WRITE:
+ next = decompose_write(state, ins);
+ break;
+
+
+ /* Be very careful with the load/store logic. These
+ * operations must convert from the in register layout
+ * to the in memory layout, which is nontrivial.
+ */
+ case OP_LOAD:
+ next = decompose_load(state, ins);
+ break;
+ case OP_STORE:
+ next = decompose_store(state, ins);
+ break;
+
+ case OP_DOT:
+ next = decompose_dot(state, ins);
+ break;
+ case OP_INDEX:
+ next = decompose_index(state, ins);
+ break;
+
+ }
+#if DEBUG_DECOMPOSE_HIRES
+ fprintf(fp, "decompose next: %p \n", next);
+ fflush(fp);
+ fprintf(fp, "next->op: %d %s\n",
+ next->op, tops(next->op));
+ /* High resolution debugging mode */
+ print_triples(state);
+#endif
+ } while (next != first);
+
+ /* Pass two remove the tuples.
*/
ins = first;
do {
- struct triple *next;
next = ins->next;
- valid_ins(state, ins);
- if ((ins->type->type & TYPE_MASK) == TYPE_STRUCT) {
- if (ins->op == OP_VAL_VEC) {
- /* Do nothing */
- }
- else if ((ins->op == OP_LOAD) || (ins->op == OP_READ)) {
- struct triple *def, **vector;
- struct type *tptr;
- int op;
- ulong_t i;
-
- op = ins->op;
- def = RHS(ins, 0);
- get_occurance(ins->occurance);
- next = alloc_triple(state, OP_VAL_VEC, ins->type, -1, -1,
- ins->occurance);
-
- vector = &RHS(next, 0);
- tptr = next->type->left;
- for(i = 0; i < next->type->elements; i++) {
- struct triple *sfield;
- struct type *mtype;
- mtype = tptr;
- if ((mtype->type & TYPE_MASK) == TYPE_PRODUCT) {
- mtype = mtype->left;
- }
- sfield = deref_field(state, def, mtype->field_ident);
-
- vector[i] = triple(
- state, op, mtype, sfield, 0);
- put_occurance(vector[i]->occurance);
- get_occurance(next->occurance);
- vector[i]->occurance = next->occurance;
- tptr = tptr->right;
- }
- propogate_use(state, ins, next);
- flatten(state, ins, next);
- release_triple(state, ins);
+ if (ins->op == OP_TUPLE) {
+ if (ins->use) {
+ internal_error(state, ins, "tuple used");
}
- else if ((ins->op == OP_STORE) || (ins->op == OP_WRITE)) {
- struct triple *src, *dst, **vector;
- struct type *tptr;
- int op;
- ulong_t i;
-
- op = ins->op;
- src = RHS(ins, 1);
- dst = RHS(ins, 0);
- get_occurance(ins->occurance);
- next = alloc_triple(state, OP_VAL_VEC, ins->type, -1, -1,
- ins->occurance);
-
- vector = &RHS(next, 0);
- tptr = next->type->left;
- for(i = 0; i < ins->type->elements; i++) {
- struct triple *dfield, *sfield;
- struct type *mtype;
- mtype = tptr;
- if ((mtype->type & TYPE_MASK) == TYPE_PRODUCT) {
- mtype = mtype->left;
- }
- sfield = deref_field(state, src, mtype->field_ident);
- dfield = deref_field(state, dst, mtype->field_ident);
- vector[i] = triple(
- state, op, mtype, dfield, sfield);
- put_occurance(vector[i]->occurance);
- get_occurance(next->occurance);
- vector[i]->occurance = next->occurance;
- tptr = tptr->right;
- }
- propogate_use(state, ins, next);
- flatten(state, ins, next);
+ else {
release_triple(state, ins);
}
- }
+ }
ins = next;
} while(ins != first);
- /* Pass two flatten the valvecs.
- */
ins = first;
do {
- struct triple *next;
next = ins->next;
- if (ins->op == OP_VAL_VEC) {
+ if (ins->op == OP_BITREF) {
if (ins->use) {
- internal_error(state, ins, "valvec used\n");
+ internal_error(state, ins, "bitref used");
+ }
+ else {
+ release_triple(state, ins);
}
- release_triple(state, ins);
- }
+ }
ins = next;
} while(ins != first);
+
/* Pass three verify the state and set ->id to 0.
*/
- ins = first;
+ next = first;
do {
+ ins = next;
+ next = ins->next;
ins->id &= ~TRIPLE_FLAG_FLATTENED;
- if ((ins->op != OP_BLOBCONST) && (ins->op != OP_SDECL) &&
- ((ins->type->type & TYPE_MASK) == TYPE_STRUCT)) {
- internal_error(state, ins, "STRUCT_TYPE remains?");
+ if (triple_stores_block(state, ins)) {
+ ins->u.block = 0;
+ }
+ if (triple_is_def(state, ins)) {
+ if (reg_size_of(state, ins->type) > REG_SIZEOF_REG) {
+ internal_error(state, ins, "multi register value remains?");
+ }
}
if (ins->op == OP_DOT) {
internal_error(state, ins, "OP_DOT remains?");
}
- if (ins->op == OP_VAL_VEC) {
- internal_error(state, ins, "OP_VAL_VEC remains?");
+ if (ins->op == OP_INDEX) {
+ internal_error(state, ins, "OP_INDEX remains?");
}
- ins = ins->next;
- } while(ins != first);
+ if (ins->op == OP_BITREF) {
+ internal_error(state, ins, "OP_BITREF remains?");
+ }
+ if (ins->op == OP_TUPLE) {
+ internal_error(state, ins, "OP_TUPLE remains?");
+ }
+ } while(next != first);
}
/* For those operations that cannot be simplified */
@@ -6295,7 +9430,7 @@ static void simplify_umul(struct compile_state *state, struct triple *ins)
RHS(ins, 0) = RHS(ins, 1);
RHS(ins, 1) = tmp;
}
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
ulong_t left, right;
left = read_const(state, ins, RHS(ins, 0));
right = read_const(state, ins, RHS(ins, 1));
@@ -6348,7 +9483,7 @@ static void simplify_sdiv(struct compile_state *state, struct triple *ins)
static void simplify_udiv(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
ulong_t left, right;
left = read_const(state, ins, RHS(ins, 0));
right = read_const(state, ins, RHS(ins, 1));
@@ -6376,7 +9511,7 @@ static void simplify_udiv(struct compile_state *state, struct triple *ins)
static void simplify_smod(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
long_t left, right;
left = read_const(state, ins, RHS(ins, 0));
right = read_const(state, ins, RHS(ins, 1));
@@ -6404,7 +9539,7 @@ static void simplify_smod(struct compile_state *state, struct triple *ins)
static void simplify_umod(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
ulong_t left, right;
left = read_const(state, ins, RHS(ins, 0));
right = read_const(state, ins, RHS(ins, 1));
@@ -6439,7 +9574,7 @@ static void simplify_add(struct compile_state *state, struct triple *ins)
RHS(ins, 0) = RHS(ins, 1);
RHS(ins, 1) = tmp;
}
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
if (RHS(ins, 0)->op == OP_INTCONST) {
ulong_t left, right;
left = read_const(state, ins, RHS(ins, 0));
@@ -6468,7 +9603,7 @@ static void simplify_add(struct compile_state *state, struct triple *ins)
static void simplify_sub(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
if (RHS(ins, 0)->op == OP_INTCONST) {
ulong_t left, right;
left = read_const(state, ins, RHS(ins, 0));
@@ -6491,14 +9626,14 @@ static void simplify_sub(struct compile_state *state, struct triple *ins)
static void simplify_sl(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 1))) {
ulong_t right;
right = read_const(state, ins, RHS(ins, 1));
- if (right >= (size_of(state, ins->type)*8)) {
+ if (right >= (size_of(state, ins->type))) {
warning(state, ins, "left shift count >= width of type");
}
}
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
ulong_t left, right;
left = read_const(state, ins, RHS(ins, 0));
right = read_const(state, ins, RHS(ins, 1));
@@ -6508,14 +9643,14 @@ static void simplify_sl(struct compile_state *state, struct triple *ins)
static void simplify_usr(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 1))) {
ulong_t right;
right = read_const(state, ins, RHS(ins, 1));
- if (right >= (size_of(state, ins->type)*8)) {
+ if (right >= (size_of(state, ins->type))) {
warning(state, ins, "right shift count >= width of type");
}
}
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
ulong_t left, right;
left = read_const(state, ins, RHS(ins, 0));
right = read_const(state, ins, RHS(ins, 1));
@@ -6525,14 +9660,14 @@ static void simplify_usr(struct compile_state *state, struct triple *ins)
static void simplify_ssr(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 1))) {
ulong_t right;
right = read_const(state, ins, RHS(ins, 1));
- if (right >= (size_of(state, ins->type)*8)) {
+ if (right >= (size_of(state, ins->type))) {
warning(state, ins, "right shift count >= width of type");
}
}
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
long_t left, right;
left = read_sconst(state, ins, RHS(ins, 0));
right = read_sconst(state, ins, RHS(ins, 1));
@@ -6542,27 +9677,46 @@ static void simplify_ssr(struct compile_state *state, struct triple *ins)
static void simplify_and(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- ulong_t left, right;
- left = read_const(state, ins, RHS(ins, 0));
- right = read_const(state, ins, RHS(ins, 1));
- mkconst(state, ins, left & right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_simple_const(left) && is_simple_const(right)) {
+ ulong_t lval, rval;
+ lval = read_const(state, ins, left);
+ rval = read_const(state, ins, right);
+ mkconst(state, ins, lval & rval);
+ }
+ else if (is_zero(right) || is_zero(left)) {
+ mkconst(state, ins, 0);
}
}
static void simplify_or(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
- ulong_t left, right;
- left = read_const(state, ins, RHS(ins, 0));
- right = read_const(state, ins, RHS(ins, 1));
- mkconst(state, ins, left | right);
+ struct triple *left, *right;
+ left = RHS(ins, 0);
+ right = RHS(ins, 1);
+
+ if (is_simple_const(left) && is_simple_const(right)) {
+ ulong_t lval, rval;
+ lval = read_const(state, ins, left);
+ rval = read_const(state, ins, right);
+ mkconst(state, ins, lval | rval);
+ }
+#if 0 /* I need to handle type mismatches here... */
+ else if (is_zero(right)) {
+ mkcopy(state, ins, left);
}
+ else if (is_zero(left)) {
+ mkcopy(state, ins, right);
+ }
+#endif
}
static void simplify_xor(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
ulong_t left, right;
left = read_const(state, ins, RHS(ins, 0));
right = read_const(state, ins, RHS(ins, 1));
@@ -6582,7 +9736,7 @@ static void simplify_pos(struct compile_state *state, struct triple *ins)
static void simplify_neg(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0))) {
+ if (is_simple_const(RHS(ins, 0))) {
ulong_t left;
left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, -left);
@@ -6594,7 +9748,7 @@ static void simplify_neg(struct compile_state *state, struct triple *ins)
static void simplify_invert(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0))) {
+ if (is_simple_const(RHS(ins, 0))) {
ulong_t left;
left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, ~left);
@@ -6608,7 +9762,11 @@ static void simplify_eq(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_eq(state, ins, left, right) == 1);
+ int val;
+ val = const_eq(state, ins, left, right);
+ if (val >= 0) {
+ mkconst(state, ins, val == 1);
+ }
}
else if (left == right) {
mkconst(state, ins, 1);
@@ -6622,7 +9780,11 @@ static void simplify_noteq(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_eq(state, ins, left, right) != 1);
+ int val;
+ val = const_eq(state, ins, left, right);
+ if (val >= 0) {
+ mkconst(state, ins, val != 1);
+ }
}
if (left == right) {
mkconst(state, ins, 0);
@@ -6636,7 +9798,11 @@ static void simplify_sless(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_scmp(state, ins, left, right) < 0);
+ int val;
+ val = const_scmp(state, ins, left, right);
+ if ((val >= -1) && (val <= 1)) {
+ mkconst(state, ins, val < 0);
+ }
}
else if (left == right) {
mkconst(state, ins, 0);
@@ -6650,7 +9816,11 @@ static void simplify_uless(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_ucmp(state, ins, left, right) < 0);
+ int val;
+ val = const_ucmp(state, ins, left, right);
+ if ((val >= -1) && (val <= 1)) {
+ mkconst(state, ins, val < 0);
+ }
}
else if (is_zero(right)) {
mkconst(state, ins, 0);
@@ -6667,7 +9837,11 @@ static void simplify_smore(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_scmp(state, ins, left, right) > 0);
+ int val;
+ val = const_scmp(state, ins, left, right);
+ if ((val >= -1) && (val <= 1)) {
+ mkconst(state, ins, val > 0);
+ }
}
else if (left == right) {
mkconst(state, ins, 0);
@@ -6681,7 +9855,11 @@ static void simplify_umore(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_ucmp(state, ins, left, right) > 0);
+ int val;
+ val = const_ucmp(state, ins, left, right);
+ if ((val >= -1) && (val <= 1)) {
+ mkconst(state, ins, val > 0);
+ }
}
else if (is_zero(left)) {
mkconst(state, ins, 0);
@@ -6699,7 +9877,11 @@ static void simplify_slesseq(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_scmp(state, ins, left, right) <= 0);
+ int val;
+ val = const_scmp(state, ins, left, right);
+ if ((val >= -1) && (val <= 1)) {
+ mkconst(state, ins, val <= 0);
+ }
}
else if (left == right) {
mkconst(state, ins, 1);
@@ -6713,7 +9895,11 @@ static void simplify_ulesseq(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_ucmp(state, ins, left, right) <= 0);
+ int val;
+ val = const_ucmp(state, ins, left, right);
+ if ((val >= -1) && (val <= 1)) {
+ mkconst(state, ins, val <= 0);
+ }
}
else if (is_zero(left)) {
mkconst(state, ins, 1);
@@ -6730,7 +9916,11 @@ static void simplify_smoreeq(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_scmp(state, ins, left, right) >= 0);
+ int val;
+ val = const_scmp(state, ins, left, right);
+ if ((val >= -1) && (val <= 1)) {
+ mkconst(state, ins, val >= 0);
+ }
}
else if (left == right) {
mkconst(state, ins, 1);
@@ -6744,7 +9934,11 @@ static void simplify_umoreeq(struct compile_state *state, struct triple *ins)
right = RHS(ins, 1);
if (is_const(left) && is_const(right)) {
- mkconst(state, ins, const_ucmp(state, ins, left, right) >= 0);
+ int val;
+ val = const_ucmp(state, ins, left, right);
+ if ((val >= -1) && (val <= 1)) {
+ mkconst(state, ins, val >= 0);
+ }
}
else if (is_zero(right)) {
mkconst(state, ins, 1);
@@ -6807,26 +10001,149 @@ static void simplify_ltrue (struct compile_state *state, struct triple *ins)
}
+static void simplify_load(struct compile_state *state, struct triple *ins)
+{
+ struct triple *addr, *sdecl, *blob;
+
+ /* If I am doing a load with a constant pointer from a constant
+ * table get the value.
+ */
+ addr = RHS(ins, 0);
+ if ((addr->op == OP_ADDRCONST) && (sdecl = MISC(addr, 0)) &&
+ (sdecl->op == OP_SDECL) && (blob = MISC(sdecl, 0)) &&
+ (blob->op == OP_BLOBCONST)) {
+ unsigned char buffer[SIZEOF_WORD];
+ size_t reg_size, mem_size;
+ const char *src;
+ ulong_t val;
+ reg_size = reg_size_of(state, ins->type);
+ if (reg_size > REG_SIZEOF_REG) {
+ internal_error(state, ins, "load size greater than register");
+ }
+ mem_size = size_of(state, ins->type);
+ src = blob->u.blob;
+ src += addr->u.cval;
+
+ memset(buffer, 0, sizeof(buffer));
+ memcpy(buffer, src, bits_to_bytes(mem_size));
+
+ switch(mem_size) {
+ case SIZEOF_I8: val = *((uint8_t *) buffer); break;
+ case SIZEOF_I16: val = *((uint16_t *)buffer); break;
+ case SIZEOF_I32: val = *((uint32_t *)buffer); break;
+ case SIZEOF_I64: val = *((uint64_t *)buffer); break;
+ default:
+ internal_error(state, ins, "mem_size: %d not handled",
+ mem_size);
+ val = 0;
+ break;
+ }
+ mkconst(state, ins, val);
+ }
+}
+
+static void simplify_uextract(struct compile_state *state, struct triple *ins)
+{
+ if (is_simple_const(RHS(ins, 0))) {
+ ulong_t val;
+ ulong_t mask;
+ val = read_const(state, ins, RHS(ins, 0));
+ mask = 1;
+ mask <<= ins->u.bitfield.size;
+ mask -= 1;
+ val >>= ins->u.bitfield.offset;
+ val &= mask;
+ mkconst(state, ins, val);
+ }
+}
+
+static void simplify_sextract(struct compile_state *state, struct triple *ins)
+{
+ if (is_simple_const(RHS(ins, 0))) {
+ ulong_t val;
+ ulong_t mask;
+ long_t sval;
+ val = read_const(state, ins, RHS(ins, 0));
+ mask = 1;
+ mask <<= ins->u.bitfield.size;
+ mask -= 1;
+ val >>= ins->u.bitfield.offset;
+ val &= mask;
+ val <<= (SIZEOF_LONG - ins->u.bitfield.size);
+ sval = val;
+ sval >>= (SIZEOF_LONG - ins->u.bitfield.size);
+ mkconst(state, ins, sval);
+ }
+}
+
+static void simplify_deposit(struct compile_state *state, struct triple *ins)
+{
+ if (is_simple_const(RHS(ins, 0)) && is_simple_const(RHS(ins, 1))) {
+ ulong_t targ, val;
+ ulong_t mask;
+ targ = read_const(state, ins, RHS(ins, 0));
+ val = read_const(state, ins, RHS(ins, 1));
+ mask = 1;
+ mask <<= ins->u.bitfield.size;
+ mask -= 1;
+ mask <<= ins->u.bitfield.offset;
+ targ &= ~mask;
+ val <<= ins->u.bitfield.offset;
+ val &= mask;
+ targ |= val;
+ mkconst(state, ins, targ);
+ }
+}
+
static void simplify_copy(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0))) {
- switch(RHS(ins, 0)->op) {
+ struct triple *right;
+ right = RHS(ins, 0);
+ if (is_subset_type(ins->type, right->type)) {
+ ins->type = right->type;
+ }
+ if (equiv_types(ins->type, right->type)) {
+ ins->op = OP_COPY;/* I don't need to convert if the types match */
+ } else {
+ if (ins->op == OP_COPY) {
+ internal_error(state, ins, "type mismatch on copy");
+ }
+ }
+ if (is_const(right) && (right->op == OP_ADDRCONST) && is_pointer(ins)) {
+ struct triple *sdecl;
+ ulong_t offset;
+ sdecl = MISC(right, 0);
+ offset = right->u.cval;
+ mkaddr_const(state, ins, sdecl, offset);
+ }
+ else if (is_const(right) && is_write_compatible(state, ins->type, right->type)) {
+ switch(right->op) {
case OP_INTCONST:
{
ulong_t left;
- left = read_const(state, ins, RHS(ins, 0));
+ left = read_const(state, ins, right);
+ /* Ensure I have not overflowed the destination. */
+ if (size_of(state, right->type) > size_of(state, ins->type)) {
+ ulong_t mask;
+ mask = 1;
+ mask <<= size_of(state, ins->type);
+ mask -= 1;
+ left &= mask;
+ }
+ /* Ensure I am properly sign extended */
+ if (size_of(state, right->type) < size_of(state, ins->type) &&
+ is_signed(right->type)) {
+ long_t val;
+ int shift;
+ shift = SIZEOF_LONG - size_of(state, right->type);
+ val = left;
+ val <<= shift;
+ val >>= shift;
+ left = val;
+ }
mkconst(state, ins, left);
break;
}
- case OP_ADDRCONST:
- {
- struct triple *sdecl;
- ulong_t offset;
- sdecl = MISC(RHS(ins, 0), 0);
- offset = RHS(ins, 0)->u.cval;
- mkaddr_const(state, ins, sdecl, offset);
- break;
- }
default:
internal_error(state, ins, "uknown constant");
break;
@@ -6885,7 +10202,7 @@ static struct triple *branch_target(struct compile_state *state, struct triple *
static void simplify_branch(struct compile_state *state, struct triple *ins)
{
- int simplified;
+ int simplified, loops;
if ((ins->op != OP_BRANCH) && (ins->op != OP_CBRANCH)) {
internal_error(state, ins, "not branch");
}
@@ -6900,8 +10217,11 @@ static void simplify_branch(struct compile_state *state, struct triple *ins)
/* If we have a branch to an unconditional branch update
* our target. But watch out for dependencies from phi
- * functions.
+ * functions.
+ * Also only do this a limited number of times so
+ * we don't get into an infinite loop.
*/
+ loops = 0;
do {
struct triple *targ;
simplified = 0;
@@ -6914,18 +10234,19 @@ static void simplify_branch(struct compile_state *state, struct triple *ins)
use_triple(TARG(ins, 0), ins);
simplified = 1;
}
- } while(simplified);
+ } while(simplified && (++loops < 20));
/* If we have a conditional branch with a constant condition
* make it an unconditional branch.
*/
- if ((ins->op == OP_CBRANCH) && is_const(RHS(ins, 0))) {
+ if ((ins->op == OP_CBRANCH) && is_simple_const(RHS(ins, 0))) {
struct triple *targ;
ulong_t value;
value = read_const(state, ins, RHS(ins, 0));
unuse_triple(RHS(ins, 0), ins);
targ = TARG(ins, 0);
- ins->sizes = TRIPLE_SIZES(0, 0, 0, 1);
+ ins->rhs = 0;
+ ins->targ = 1;
ins->op = OP_BRANCH;
if (value) {
unuse_triple(ins->next, ins);
@@ -6936,17 +10257,20 @@ static void simplify_branch(struct compile_state *state, struct triple *ins)
TARG(ins, 0) = ins->next;
}
}
-
- /* If we have a branch to the next instruction
+
+ /* If we have a branch to the next instruction,
* make it a noop.
*/
if (TARG(ins, 0) == ins->next) {
- unuse_triple(ins->next, ins);
+ unuse_triple(TARG(ins, 0), ins);
if (ins->op == OP_CBRANCH) {
unuse_triple(RHS(ins, 0), ins);
unuse_triple(ins->next, ins);
}
- ins->sizes = TRIPLE_SIZES(0, 0, 0, 0);
+ ins->lhs = 0;
+ ins->rhs = 0;
+ ins->misc = 0;
+ ins->targ = 0;
ins->op = OP_NOOP;
if (ins->use) {
internal_error(state, ins, "noop use != 0");
@@ -6999,7 +10323,7 @@ static void simplify_phi(struct compile_state *state, struct triple *ins)
int zrhs, i;
ulong_t cvalue;
slot = &RHS(ins, 0);
- zrhs = TRIPLE_RHS(ins->sizes);
+ zrhs = ins->rhs;
if (zrhs == 0) {
return;
}
@@ -7009,6 +10333,7 @@ static void simplify_phi(struct compile_state *state, struct triple *ins)
for(i = 1; i < zrhs; i++) {
if ( !slot[i] ||
!is_simple_const(slot[i]) ||
+ !equiv_types(slot[0]->type, slot[i]->type) ||
(cvalue != read_const(state, ins, slot[i]))) {
break;
}
@@ -7028,6 +10353,14 @@ static void simplify_phi(struct compile_state *state, struct triple *ins)
}
if (i == zrhs) {
/* If the phi has a single value just copy it */
+ if (!is_subset_type(ins->type, value->type)) {
+ internal_error(state, ins, "bad input type to phi");
+ }
+ /* Make the types match */
+ if (!equiv_types(ins->type, value->type)) {
+ ins->type = value->type;
+ }
+ /* Now make the actual copy */
mkcopy(state, ins, value);
return;
}
@@ -7036,7 +10369,7 @@ static void simplify_phi(struct compile_state *state, struct triple *ins)
static void simplify_bsf(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0))) {
+ if (is_simple_const(RHS(ins, 0))) {
ulong_t left;
left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, bsf(left));
@@ -7045,7 +10378,7 @@ static void simplify_bsf(struct compile_state *state, struct triple *ins)
static void simplify_bsr(struct compile_state *state, struct triple *ins)
{
- if (is_const(RHS(ins, 0))) {
+ if (is_simple_const(RHS(ins, 0))) {
ulong_t left;
left = read_const(state, ins, RHS(ins, 0));
mkconst(state, ins, bsr(left));
@@ -7095,23 +10428,29 @@ static const struct simplify_table {
[OP_LFALSE ] = { simplify_lfalse, COMPILER_SIMPLIFY_LOGICAL },
[OP_LTRUE ] = { simplify_ltrue, COMPILER_SIMPLIFY_LOGICAL },
-[OP_LOAD ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_LOAD ] = { simplify_load, COMPILER_SIMPLIFY_OP },
[OP_STORE ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_UEXTRACT ] = { simplify_uextract, COMPILER_SIMPLIFY_BITFIELD },
+[OP_SEXTRACT ] = { simplify_sextract, COMPILER_SIMPLIFY_BITFIELD },
+[OP_DEPOSIT ] = { simplify_deposit, COMPILER_SIMPLIFY_BITFIELD },
+
[OP_NOOP ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_INTCONST ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_BLOBCONST ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_ADDRCONST ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_UNKNOWNVAL ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_WRITE ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_READ ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_COPY ] = { simplify_copy, COMPILER_SIMPLIFY_COPY },
+[OP_CONVERT ] = { simplify_copy, COMPILER_SIMPLIFY_COPY },
[OP_PIECE ] = { simplify_piece, COMPILER_SIMPLIFY_OP },
[OP_ASM ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_DOT ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
-[OP_VAL_VEC ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
+[OP_INDEX ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_LIST ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
[OP_BRANCH ] = { simplify_branch, COMPILER_SIMPLIFY_BRANCH },
@@ -7136,29 +10475,55 @@ static const struct simplify_table {
[OP_HLT ] = { simplify_noop, COMPILER_SIMPLIFY_OP },
};
+static inline void debug_simplify(struct compile_state *state,
+ simplify_t do_simplify, struct triple *ins)
+{
+#if DEBUG_SIMPLIFY_HIRES
+ if (state->functions_joined && (do_simplify != simplify_noop)) {
+ /* High resolution debugging mode */
+ fprintf(state->dbgout, "simplifing: ");
+ display_triple(state->dbgout, ins);
+ }
+#endif
+ do_simplify(state, ins);
+#if DEBUG_SIMPLIFY_HIRES
+ if (state->functions_joined && (do_simplify != simplify_noop)) {
+ /* High resolution debugging mode */
+ fprintf(state->dbgout, "simplified: ");
+ display_triple(state->dbgout, ins);
+ }
+#endif
+}
static void simplify(struct compile_state *state, struct triple *ins)
{
int op;
simplify_t do_simplify;
+ if (ins == &unknown_triple) {
+ internal_error(state, ins, "simplifying the unknown triple?");
+ }
do {
op = ins->op;
do_simplify = 0;
if ((op < 0) || (op > sizeof(table_simplify)/sizeof(table_simplify[0]))) {
do_simplify = 0;
}
- else if (state->compiler->flags & table_simplify[op].flag) {
+ else {
do_simplify = table_simplify[op].func;
}
- else {
+ if (do_simplify &&
+ !(state->compiler->flags & table_simplify[op].flag)) {
+ do_simplify = simplify_noop;
+ }
+ if (do_simplify && (ins->id & TRIPLE_FLAG_VOLATILE)) {
do_simplify = simplify_noop;
}
if (!do_simplify) {
- internal_error(state, ins, "cannot simplify op: %d %s\n",
+ internal_error(state, ins, "cannot simplify op: %d %s",
op, tops(op));
return;
}
- do_simplify(state, ins);
+ debug_simplify(state, do_simplify, ins);
} while(ins->op != op);
}
@@ -7183,7 +10548,7 @@ static void simplify_all(struct compile_state *state)
}while(ins != first);
rebuild_ssa_form(state);
- print_blocks(state, __func__, stdout);
+ print_blocks(state, __func__, state->dbgout);
}
/*
@@ -7194,7 +10559,7 @@ static void simplify_all(struct compile_state *state)
static void register_builtin_function(struct compile_state *state,
const char *name, int op, struct type *rtype, ...)
{
- struct type *ftype, *atype, *param, **next;
+ struct type *ftype, *atype, *ctype, *crtype, *param, **next;
struct triple *def, *arg, *result, *work, *last, *first, *retvar, *ret;
struct hash_entry *ident;
struct file_state file;
@@ -7222,6 +10587,7 @@ static void register_builtin_function(struct compile_state *state,
/* Find the function type */
ftype = new_type(TYPE_FUNCTION | STOR_INLINE | STOR_STATIC, rtype, 0);
+ ftype->elements = parameters;
next = &ftype->right;
va_start(args, rtype);
for(i = 0; i < parameters; i++) {
@@ -7238,12 +10604,20 @@ static void register_builtin_function(struct compile_state *state,
}
va_end(args);
+ /* Get the initial closure type */
+ ctype = new_type(TYPE_JOIN, &void_type, 0);
+ ctype->elements = 1;
+
+ /* Get the return type */
+ crtype = new_type(TYPE_TUPLE, new_type(TYPE_PRODUCT, ctype, rtype), 0);
+ crtype->elements = 2;
+
/* Generate the needed triples */
def = triple(state, OP_LIST, ftype, 0, 0);
first = label(state);
RHS(def, 0) = first;
- retvar = variable(state, &void_ptr_type);
- retvar = flatten(state, first, retvar);
+ result = flatten(state, first, variable(state, crtype));
+ retvar = flatten(state, first, variable(state, &void_ptr_type));
ret = triple(state, OP_RET, &void_type, read_expr(state, retvar), 0);
/* Now string them together */
@@ -7257,44 +10631,13 @@ static void register_builtin_function(struct compile_state *state,
arg = flatten(state, first, variable(state, atype));
param = param->right;
}
- result = 0;
- if ((rtype->type & TYPE_MASK) != TYPE_VOID) {
- result = flatten(state, first, variable(state, rtype));
- }
- MISC(def, 0) = result;
work = new_triple(state, op, rtype, -1, parameters);
- for(i = 0, arg = first->next->next; i < parameters; i++, arg = arg->next) {
- RHS(work, i) = read_expr(state, arg);
- }
- if (result && ((rtype->type & TYPE_MASK) == TYPE_STRUCT)) {
- struct triple *val;
- /* Populate the LHS with the target registers */
- work = flatten(state, first, work);
- work->type = &void_type;
- param = rtype->left;
- if (rtype->elements != TRIPLE_LHS(work->sizes)) {
- internal_error(state, 0, "Invalid result type");
- }
- val = new_triple(state, OP_VAL_VEC, rtype, -1, -1);
- for(i = 0; i < rtype->elements; i++) {
- struct triple *piece;
- atype = param;
- if ((param->type & TYPE_MASK) == TYPE_PRODUCT) {
- atype = param->left;
- }
- if (!TYPE_ARITHMETIC(atype->type) &&
- !TYPE_PTR(atype->type)) {
- internal_error(state, 0, "Invalid lhs type");
- }
- piece = triple(state, OP_PIECE, atype, work, 0);
- piece->u.cval = i;
- LHS(work, i) = piece;
- RHS(val, i) = piece;
- }
- work = val;
+ generate_lhs_pieces(state, work);
+ for(i = 0; i < parameters; i++) {
+ RHS(work, i) = read_expr(state, farg(state, def, i));
}
- if (result) {
- work = write_expr(state, result, work);
+ if ((rtype->type & TYPE_MASK) != TYPE_VOID) {
+ work = write_expr(state, deref_index(state, result, 1), work);
}
work = flatten(state, first, work);
last = flatten(state, first, label(state));
@@ -7306,18 +10649,20 @@ static void register_builtin_function(struct compile_state *state,
state->file = file.prev;
state->function = 0;
-
+ state->main_function = 0;
+
if (!state->functions) {
state->functions = def;
} else {
insert_triple(state, state->functions, def);
}
if (state->compiler->debug & DEBUG_INLINE) {
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
- display_func(stdout, def);
- fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ FILE *fp = state->dbgout;
+ fprintf(fp, "\n");
+ loc(fp, state, 0);
+ fprintf(fp, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(state, fp, def);
+ fprintf(fp, "__________ %s _________ done\n\n", __FUNCTION__);
}
}
@@ -7440,7 +10785,7 @@ static int istype(int tok);
static struct triple *expr(struct compile_state *state);
static struct triple *assignment_expr(struct compile_state *state);
static struct type *type_name(struct compile_state *state);
-static void statement(struct compile_state *state, struct triple *fist);
+static void statement(struct compile_state *state, struct triple *first);
static struct triple *call_expr(
struct compile_state *state, struct triple *func)
@@ -7550,6 +10895,7 @@ static struct triple *string_constant(struct compile_state *state)
type->elements += 1;
def = triple(state, OP_BLOBCONST, type, 0, 0);
def->u.blob = buf;
+
return def;
}
@@ -7799,7 +11145,7 @@ static struct triple *unary_expr(struct compile_state *state)
type = expr->type;
release_expr(state, expr);
}
- def = int_const(state, &ulong_type, size_of(state, type));
+ def = int_const(state, &ulong_type, size_of_in_bytes(state, type));
break;
}
case TOK_ALIGNOF:
@@ -7820,7 +11166,7 @@ static struct triple *unary_expr(struct compile_state *state)
type = expr->type;
release_expr(state, expr);
}
- def = int_const(state, &ulong_type, align_of(state, type));
+ def = int_const(state, &ulong_type, align_of_in_bytes(state, type));
break;
}
default:
@@ -8086,7 +11432,7 @@ static struct triple *land_expr(struct compile_state *state)
right = read_expr(state, or_expr(state));
bool(state, right);
- def = triple(state, OP_LAND, &int_type,
+ def = mkland_expr(state,
ltrue_expr(state, left),
ltrue_expr(state, right));
}
@@ -8104,8 +11450,8 @@ static struct triple *lor_expr(struct compile_state *state)
eat(state, TOK_LOGOR);
right = read_expr(state, land_expr(state));
bool(state, right);
-
- def = triple(state, OP_LOR, &int_type,
+
+ def = mklor_expr(state,
ltrue_expr(state, left),
ltrue_expr(state, right));
}
@@ -8125,7 +11471,7 @@ static struct triple *conditional_expr(struct compile_state *state)
eat(state, TOK_COLON);
right = read_expr(state, conditional_expr(state));
- def = cond_expr(state, test, left, right);
+ def = mkcond_expr(state, test, left, right);
}
return def;
}
@@ -8262,11 +11608,8 @@ static struct triple *expr(struct compile_state *state)
struct triple *def;
def = assignment_expr(state);
while(peek(state) == TOK_COMMA) {
- struct triple *left, *right;
- left = def;
eat(state, TOK_COMMA);
- right = assignment_expr(state);
- def = triple(state, OP_COMMA, right->type, left, right);
+ def = mkprog(state, def, assignment_expr(state), 0);
}
return def;
}
@@ -8274,9 +11617,9 @@ static struct triple *expr(struct compile_state *state)
static void expr_statement(struct compile_state *state, struct triple *first)
{
if (peek(state) != TOK_SEMI) {
- /* lvalue conversions always apply except when certaion operators
- * are applied so the values so apply them here as I know no more
- * operators will be applied.
+ /* lvalue conversions always apply except when certian operators
+ * are applied. I apply the lvalue conversions here
+ * as I know no more operators will be applied.
*/
flatten(state, first, lvalue_conversion(state, expr(state)));
}
@@ -8464,7 +11807,8 @@ static void return_statement(struct compile_state *state, struct triple *first)
(state->scope_depth == GLOBAL_SCOPE_DEPTH +2));
/* Find the return variable */
- var = MISC(state->main_function, 0);
+ var = fresult(state, state->main_function);
+
/* Find the return destination */
dest = state->i_return->sym_ident->def;
mv = jmp = 0;
@@ -8474,7 +11818,7 @@ static void return_statement(struct compile_state *state, struct triple *first)
}
/* If needed generate an assignment instruction */
if (val) {
- mv = write_expr(state, var, val);
+ mv = write_expr(state, deref_index(state, var, 1), val);
}
/* Now put the code together */
if (mv) {
@@ -8522,7 +11866,7 @@ static void goto_statement(struct compile_state *state, struct triple *first)
*/
struct triple *ins;
ins = label(state);
- label_symbol(state, ident, ins);
+ label_symbol(state, ident, ins, FUNCTION_SCOPE_DEPTH);
}
eat(state, TOK_SEMI);
@@ -8543,7 +11887,7 @@ static void labeled_statement(struct compile_state *state, struct triple *first)
}
else {
ins = label(state);
- label_symbol(state, ident, ins);
+ label_symbol(state, ident, ins, FUNCTION_SCOPE_DEPTH);
}
if (ins->id & TRIPLE_FLAG_FLATTENED) {
error(state, 0, "label %s already defined", ident->name);
@@ -8659,8 +12003,13 @@ static void default_statement(struct compile_state *state, struct triple *first)
/* Generate the needed pieces */
dest = label(state);
+ /* Blame the branch on the default statement */
+ put_occurance(dbranch->occurance);
+ dbranch->occurance = new_occurance(state);
+
/* Thread the pieces together */
TARG(dbranch, 0) = dest;
+ use_triple(dest, dbranch);
flatten(state, first, dest);
statement(state, first);
}
@@ -8674,7 +12023,9 @@ static void asm_statement(struct compile_state *state, struct triple *first)
} out_param[MAX_LHS], in_param[MAX_RHS], clob_param[MAX_LHS];
struct triple *def, *asm_str;
int out, in, clobbers, more, colons, i;
+ int flags;
+ flags = 0;
eat(state, TOK_ASM);
/* For now ignore the qualifiers */
switch(peek(state)) {
@@ -8683,6 +12034,7 @@ static void asm_statement(struct compile_state *state, struct triple *first)
break;
case TOK_VOLATILE:
eat(state, TOK_VOLATILE);
+ flags |= TRIPLE_FLAG_VOLATILE;
break;
}
eat(state, TOK_LPAREN);
@@ -8790,6 +12142,7 @@ static void asm_statement(struct compile_state *state, struct triple *first)
def = new_triple(state, OP_ASM, &void_type, clobbers + out, in);
def->u.ainfo = info;
+ def->id |= flags;
/* Find the register constraints */
for(i = 0; i < out; i++) {
@@ -8835,13 +12188,29 @@ static void asm_statement(struct compile_state *state, struct triple *first)
/* Now build the helper expressions */
for(i = 0; i < in; i++) {
- RHS(def, i) = read_expr(state,in_param[i].expr);
+ RHS(def, i) = read_expr(state, in_param[i].expr);
}
flatten(state, first, def);
for(i = 0; i < (out + clobbers); i++) {
struct type *type;
struct triple *piece;
- type = (i < out)? out_param[i].expr->type : &void_type;
+ if (i < out) {
+ type = out_param[i].expr->type;
+ } else {
+ size_t size = arch_reg_size(info->tmpl.lhs[i].reg);
+ if (size >= SIZEOF_LONG) {
+ type = &ulong_type;
+ }
+ else if (size >= SIZEOF_INT) {
+ type = &uint_type;
+ }
+ else if (size >= SIZEOF_SHORT) {
+ type = &ushort_type;
+ }
+ else {
+ type = &uchar_type;
+ }
+ }
piece = triple(state, OP_PIECE, type, def, 0);
piece->u.cval = i;
LHS(def, i) = piece;
@@ -8974,6 +12343,7 @@ static struct type *param_type_list(struct compile_state *state, struct type *ty
struct type *ftype, **next;
ftype = new_type(TYPE_FUNCTION | (type->type & STOR_MASK), type, param_decl(state));
next = &ftype->right;
+ ftype->elements = 1;
while(peek(state) == TOK_COMMA) {
eat(state, TOK_COMMA);
if (peek(state) == TOK_DOTS) {
@@ -8983,12 +12353,12 @@ static struct type *param_type_list(struct compile_state *state, struct type *ty
else {
*next = new_type(TYPE_PRODUCT, *next, param_decl(state));
next = &((*next)->right);
+ ftype->elements++;
}
}
return ftype;
}
-
static struct type *type_name(struct compile_state *state)
{
struct type *type;
@@ -9087,7 +12457,6 @@ static struct type *declarator(
return type;
}
-
static struct type *typedef_name(
struct compile_state *state, unsigned int specifiers)
{
@@ -9175,17 +12544,24 @@ static struct type *enum_specifier(
static struct type *struct_declarator(
struct compile_state *state, struct type *type, struct hash_entry **ident)
{
- int tok;
- tok = peek(state);
- if (tok != TOK_COLON) {
+ if (peek(state) != TOK_COLON) {
type = declarator(state, type, ident, 1);
}
- if ((tok == TOK_COLON) || (peek(state) == TOK_COLON)) {
+ if (peek(state) == TOK_COLON) {
struct triple *value;
eat(state, TOK_COLON);
value = constant_expr(state);
-#warning "FIXME implement bitfields to reduce register usage"
- error(state, 0, "bitfields not yet implemented");
+ if (value->op != OP_INTCONST) {
+ error(state, 0, "Invalid constant expression");
+ }
+ if (value->u.cval > size_of(state, type)) {
+ error(state, 0, "bitfield larger than base type");
+ }
+ if (!TYPE_INTEGER(type->type) || ((type->type & TYPE_MASK) == TYPE_BITFIELD)) {
+ error(state, 0, "bitfield base not an integer type");
+ }
+ type = new_type(TYPE_BITFIELD, type, 0);
+ type->elements = value->u.cval;
}
return type;
}
@@ -9195,6 +12571,7 @@ static struct type *struct_or_union_specifier(
{
struct type *struct_type;
struct hash_entry *ident;
+ unsigned int type_main;
unsigned int type_join;
int tok;
struct_type = 0;
@@ -9202,15 +12579,17 @@ static struct type *struct_or_union_specifier(
switch(peek(state)) {
case TOK_STRUCT:
eat(state, TOK_STRUCT);
+ type_main = TYPE_STRUCT;
type_join = TYPE_PRODUCT;
break;
case TOK_UNION:
eat(state, TOK_UNION);
+ type_main = TYPE_UNION;
type_join = TYPE_OVERLAP;
- error(state, 0, "unions not yet supported\n");
break;
default:
eat(state, TOK_STRUCT);
+ type_main = TYPE_STRUCT;
type_join = TYPE_PRODUCT;
break;
}
@@ -9251,7 +12630,7 @@ static struct type *struct_or_union_specifier(
eat(state, TOK_SEMI);
} while(peek(state) != TOK_RBRACE);
eat(state, TOK_RBRACE);
- struct_type = new_type(TYPE_STRUCT | spec, struct_type, 0);
+ struct_type = new_type(type_main | spec, struct_type, 0);
struct_type->type_ident = ident;
struct_type->elements = elements;
if (ident) {
@@ -9260,11 +12639,13 @@ static struct type *struct_or_union_specifier(
}
if (ident && ident->sym_tag &&
ident->sym_tag->type &&
- ((ident->sym_tag->type->type & TYPE_MASK) == TYPE_STRUCT)) {
+ ((ident->sym_tag->type->type & TYPE_MASK) == type_main)) {
struct_type = clone_type(spec, ident->sym_tag->type);
}
else if (ident && !struct_type) {
- error(state, 0, "struct %s undeclared", ident->name);
+ error(state, 0, "%s %s undeclared",
+ (type_main == TYPE_STRUCT)?"struct" : "union",
+ ident->name);
}
return struct_type;
}
@@ -9317,6 +12698,69 @@ static unsigned int function_specifier_opt(struct compile_state *state)
return specifiers;
}
+static unsigned int attrib(struct compile_state *state, unsigned int attributes)
+{
+ int tok = peek(state);
+ switch(tok) {
+ case TOK_COMMA:
+ case TOK_LPAREN:
+ /* The empty attribute ignore it */
+ break;
+ case TOK_IDENT:
+ case TOK_ENUM_CONST:
+ case TOK_TYPE_NAME:
+ {
+ struct hash_entry *ident;
+ eat(state, TOK_IDENT);
+ ident = state->token[0].ident;
+
+ if (ident == state->i_noinline) {
+ if (attributes & ATTRIB_ALWAYS_INLINE) {
+ error(state, 0, "both always_inline and noinline attribtes");
+ }
+ attributes |= ATTRIB_NOINLINE;
+ }
+ else if (ident == state->i_always_inline) {
+ if (attributes & ATTRIB_NOINLINE) {
+ error(state, 0, "both noinline and always_inline attribtes");
+ }
+ attributes |= ATTRIB_ALWAYS_INLINE;
+ }
+ else {
+ error(state, 0, "Unknown attribute:%s", ident->name);
+ }
+ break;
+ }
+ default:
+ error(state, 0, "Unexpected token: %s\n", tokens[tok]);
+ break;
+ }
+ return attributes;
+}
+
+static unsigned int attribute_list(struct compile_state *state, unsigned type)
+{
+ type = attrib(state, type);
+ while(peek(state) == TOK_COMMA) {
+ eat(state, TOK_COMMA);
+ type = attrib(state, type);
+ }
+ return type;
+}
+
+static unsigned int attributes_opt(struct compile_state *state, unsigned type)
+{
+ if (peek(state) == TOK_ATTRIBUTE) {
+ eat(state, TOK_ATTRIBUTE);
+ eat(state, TOK_LPAREN);
+ eat(state, TOK_LPAREN);
+ type = attribute_list(state, type);
+ eat(state, TOK_RPAREN);
+ eat(state, TOK_RPAREN);
+ }
+ return type;
+}
+
static unsigned int type_qualifiers(struct compile_state *state)
{
unsigned int specifiers;
@@ -9327,15 +12771,15 @@ static unsigned int type_qualifiers(struct compile_state *state)
switch(peek(state)) {
case TOK_CONST:
eat(state, TOK_CONST);
- specifiers = QUAL_CONST;
+ specifiers |= QUAL_CONST;
break;
case TOK_VOLATILE:
eat(state, TOK_VOLATILE);
- specifiers = QUAL_VOLATILE;
+ specifiers |= QUAL_VOLATILE;
break;
case TOK_RESTRICT:
eat(state, TOK_RESTRICT);
- specifiers = QUAL_RESTRICT;
+ specifiers |= QUAL_RESTRICT;
break;
default:
done = 1;
@@ -9585,6 +13029,9 @@ static struct type *decl_specifiers(struct compile_state *state)
/* function-specifier */
specifiers |= function_specifier_opt(state);
+ /* attributes */
+ specifiers |= attributes_opt(state, 0);
+
/* type qualifier */
specifiers |= type_qualifiers(state);
@@ -9623,7 +13070,9 @@ static struct field_info designator(struct compile_state *state, struct type *ty
case TOK_DOT:
{
struct hash_entry *field;
- if ((type->type & TYPE_MASK) != TYPE_STRUCT) {
+ if (((type->type & TYPE_MASK) != TYPE_STRUCT) &&
+ ((type->type & TYPE_MASK) != TYPE_UNION))
+ {
error(state, 0, "Struct designator not in struct initializer");
}
eat(state, TOK_DOT);
@@ -9656,7 +13105,7 @@ static struct triple *initializer(
(equiv_types(type->left, result->type->left))) {
type->elements = result->type->elements;
}
- if (is_stable(state, result) &&
+ if (is_lvalue(state, result) &&
((result->type->type & TYPE_MASK) == TYPE_ARRAY) &&
(type->type & TYPE_MASK) != TYPE_ARRAY)
{
@@ -9688,7 +13137,7 @@ static struct triple *initializer(
} else {
max_offset = size_of(state, type);
}
- buf = xcmalloc(max_offset, "initializer");
+ buf = xcmalloc(bits_to_bytes(max_offset), "initializer");
eat(state, TOK_LBRACE);
do {
struct triple *value;
@@ -9716,21 +13165,31 @@ static struct triple *initializer(
old_buf = buf;
old_size = max_offset;
max_offset = info.offset + value_size;
- buf = xmalloc(max_offset, "initializer");
- memcpy(buf, old_buf, old_size);
+ buf = xmalloc(bits_to_bytes(max_offset), "initializer");
+ memcpy(buf, old_buf, bits_to_bytes(old_size));
xfree(old_buf);
}
- dest = ((char *)buf) + info.offset;
+ dest = ((char *)buf) + bits_to_bytes(info.offset);
+#if DEBUG_INITIALIZER
+ fprintf(state->errout, "dest = buf + %d max_offset: %d value_size: %d op: %d\n",
+ dest - buf,
+ bits_to_bytes(max_offset),
+ bits_to_bytes(value_size),
+ value->op);
+#endif
if (value->op == OP_BLOBCONST) {
- memcpy(dest, value->u.blob, value_size);
+ memcpy(dest, value->u.blob, bits_to_bytes(value_size));
}
- else if ((value->op == OP_INTCONST) && (value_size == 1)) {
+ else if ((value->op == OP_INTCONST) && (value_size == SIZEOF_I8)) {
+#if DEBUG_INITIALIZER
+ fprintf(state->errout, "byte: %02x\n", value->u.cval & 0xff);
+#endif
*((uint8_t *)dest) = value->u.cval & 0xff;
}
- else if ((value->op == OP_INTCONST) && (value_size == 2)) {
+ else if ((value->op == OP_INTCONST) && (value_size == SIZEOF_I16)) {
*((uint16_t *)dest) = value->u.cval & 0xffff;
}
- else if ((value->op == OP_INTCONST) && (value_size == 4)) {
+ else if ((value->op == OP_INTCONST) && (value_size == SIZEOF_I32)) {
*((uint32_t *)dest) = value->u.cval & 0xffffffff;
}
else {
@@ -9759,7 +13218,7 @@ static struct triple *initializer(
return result;
}
-static void resolve_branches(struct compile_state *state)
+static void resolve_branches(struct compile_state *state, struct triple *first)
{
/* Make a second pass and finish anything outstanding
* with respect to branches. The only outstanding item
@@ -9767,6 +13226,30 @@ static void resolve_branches(struct compile_state *state)
* been defined and to error about them.
*/
int i;
+ struct triple *ins;
+ /* Also error on branches that do not use their targets */
+ ins = first;
+ do {
+ if (!triple_is_ret(state, ins)) {
+ struct triple **expr ;
+ struct triple_set *set;
+ expr = triple_targ(state, ins, 0);
+ for(; expr; expr = triple_targ(state, ins, expr)) {
+ struct triple *targ;
+ targ = *expr;
+ for(set = targ?targ->use:0; set; set = set->next) {
+ if (set->member == ins) {
+ break;
+ }
+ }
+ if (!set) {
+ internal_error(state, ins, "targ not used");
+ }
+ }
+ }
+ ins = ins->next;
+ } while(ins != first);
+ /* See if there are goto to labels that have not been defined */
for(i = 0; i < HASH_TABLE_SIZE; i++) {
struct hash_entry *entry;
for(entry = state->hash_table[i]; entry; entry = entry->next) {
@@ -9786,9 +13269,11 @@ static void resolve_branches(struct compile_state *state)
static struct triple *function_definition(
struct compile_state *state, struct type *type)
{
- struct triple *def, *tmp, *first, *end, *retvar, *ret;
+ struct triple *def, *tmp, *first, *end, *retvar, *result, *ret;
+ struct triple *fname;
+ struct type *fname_type;
struct hash_entry *ident;
- struct type *param;
+ struct type *param, *crtype, *ctype;
int i;
if ((type->type &TYPE_MASK) != TYPE_FUNCTION) {
error(state, 0, "Invalid function header");
@@ -9831,9 +13316,19 @@ static struct triple *function_definition(
ident = state->i_return;
symbol(state, ident, &ident->sym_ident, end, end->type);
+ /* Get the initial closure type */
+ ctype = new_type(TYPE_JOIN, &void_type, 0);
+ ctype->elements = 1;
+
+ /* Add a variable for the return value */
+ crtype = new_type(TYPE_TUPLE,
+ /* Remove all type qualifiers from the return type */
+ new_type(TYPE_PRODUCT, ctype, clone_type(0, type->left)), 0);
+ crtype->elements = 2;
+ result = flatten(state, end, variable(state, crtype));
+
/* Allocate a variable for the return address */
- retvar = variable(state, &void_ptr_type);
- retvar = flatten(state, end, retvar);
+ retvar = flatten(state, end, variable(state, &void_ptr_type));
/* Add in the return instruction */
ret = triple(state, OP_RET, &void_type, read_expr(state, retvar), 0);
@@ -9846,7 +13341,7 @@ static struct triple *function_definition(
while((param->type & TYPE_MASK) == TYPE_PRODUCT) {
ident = param->left->field_ident;
tmp = variable(state, param->left);
- symbol(state, ident, &ident->sym_ident, tmp, tmp->type);
+ var_symbol(state, ident, tmp);
flatten(state, end, tmp);
param = param->right;
}
@@ -9857,15 +13352,19 @@ static struct triple *function_definition(
symbol(state, ident, &ident->sym_ident, tmp, tmp->type);
flatten(state, end, tmp);
}
- /* Add a variable for the return value */
- MISC(def, 0) = 0;
- if ((type->left->type & TYPE_MASK) != TYPE_VOID) {
- /* Remove all type qualifiers from the return type */
- tmp = variable(state, clone_type(0, type->left));
- flatten(state, end, tmp);
- /* Remember where the return value is */
- MISC(def, 0) = tmp;
- }
+
+ /* Add the declaration static const char __func__ [] = "func-name" */
+ fname_type = new_type(TYPE_ARRAY,
+ clone_type(QUAL_CONST | STOR_STATIC, &char_type), 0);
+ fname_type->type |= QUAL_CONST | STOR_STATIC;
+ fname_type->elements = strlen(state->function) + 1;
+
+ fname = triple(state, OP_BLOBCONST, fname_type, 0, 0);
+ fname->u.blob = (void *)state->function;
+ fname = flatten(state, end, fname);
+
+ ident = state->i___func__;
+ symbol(state, ident, &ident->sym_ident, fname, fname_type);
/* Remember which function I am compiling.
* Also assume the last defined function is the main function.
@@ -9876,7 +13375,7 @@ static struct triple *function_definition(
compound_statement(state, end);
/* Finish anything unfinished with branches */
- resolve_branches(state);
+ resolve_branches(state, first);
/* Remove the parameter scope */
end_scope(state);
@@ -9889,11 +13388,12 @@ static struct triple *function_definition(
insert_triple(state, state->functions, def);
}
if (state->compiler->debug & DEBUG_INLINE) {
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
- display_func(stdout, def);
- fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ FILE *fp = state->dbgout;
+ fprintf(fp, "\n");
+ loc(fp, state, 0);
+ fprintf(fp, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(state, fp, def);
+ fprintf(fp, "__________ %s _________ done\n\n", __FUNCTION__);
}
return def;
@@ -9940,7 +13440,7 @@ static struct triple *do_decl(struct compile_state *state,
}
if (ident) {
def = variable(state, type);
- symbol(state, ident, &ident->sym_ident, def, type);
+ var_symbol(state, ident, def);
}
return def;
}
@@ -9955,6 +13455,7 @@ static void decl(struct compile_state *state, struct triple *first)
base_type = decl_specifiers(state);
ident = 0;
type = declarator(state, base_type, &ident, 0);
+ type->type = attributes_opt(state, type->type);
if (global && ident && (peek(state) == TOK_LBRACE)) {
/* function */
type->type_ident = ident;
@@ -10015,6 +13516,36 @@ static void decls(struct compile_state *state)
/*
* Function inlining
*/
+struct triple_reg_set {
+ struct triple_reg_set *next;
+ struct triple *member;
+ struct triple *new;
+};
+struct reg_block {
+ struct block *block;
+ struct triple_reg_set *in;
+ struct triple_reg_set *out;
+ int vertex;
+};
+static void setup_basic_blocks(struct compile_state *, struct basic_blocks *bb);
+static void analyze_basic_blocks(struct compile_state *state, struct basic_blocks *bb);
+static void free_basic_blocks(struct compile_state *, struct basic_blocks *bb);
+static int tdominates(struct compile_state *state, struct triple *dom, struct triple *sub);
+static void walk_blocks(struct compile_state *state, struct basic_blocks *bb,
+ void (*cb)(struct compile_state *state, struct block *block, void *arg),
+ void *arg);
+static void print_block(
+ struct compile_state *state, struct block *block, void *arg);
+static int do_triple_set(struct triple_reg_set **head,
+ struct triple *member, struct triple *new_member);
+static void do_triple_unset(struct triple_reg_set **head, struct triple *member);
+static struct reg_block *compute_variable_lifetimes(
+ struct compile_state *state, struct basic_blocks *bb);
+static void free_variable_lifetimes(struct compile_state *state,
+ struct basic_blocks *bb, struct reg_block *blocks);
+static void print_live_variables(struct compile_state *state,
+ struct basic_blocks *bb, struct reg_block *rb, FILE *fp);
+
static struct triple *call(struct compile_state *state,
struct triple *retvar, struct triple *ret_addr,
@@ -10039,43 +13570,84 @@ static struct triple *call(struct compile_state *state,
return call;
}
-static void mark_live_functions(struct compile_state *state, struct triple *first)
+static void walk_functions(struct compile_state *state,
+ void (*cb)(struct compile_state *state, struct triple *func, void *arg),
+ void *arg)
{
- struct triple *ptr;
- ptr = first;
+ struct triple *func, *first;
+ func = first = state->functions;
do {
- if (ptr->op == OP_FCALL) {
- struct triple *func;
- func = MISC(ptr, 0);
- if (func->u.cval++ == 0) {
- mark_live_functions(state, RHS(func, 0));
- }
- }
- ptr = ptr->next;
- } while(ptr != first);
+ cb(state, func, arg);
+ func = func->next;
+ } while(func != first);
}
-static void walk_functions(struct compile_state *state,
+static void reverse_walk_functions(struct compile_state *state,
void (*cb)(struct compile_state *state, struct triple *func, void *arg),
void *arg)
{
struct triple *func, *first;
func = first = state->functions;
do {
+ func = func->prev;
cb(state, func, arg);
- func = func->next;
} while(func != first);
}
+static void mark_live(struct compile_state *state, struct triple *func, void *arg)
+{
+ struct triple *ptr, *first;
+ if (func->u.cval == 0) {
+ return;
+ }
+ ptr = first = RHS(func, 0);
+ do {
+ if (ptr->op == OP_FCALL) {
+ struct triple *called_func;
+ called_func = MISC(ptr, 0);
+ /* Mark the called function as used */
+ if (!(func->id & TRIPLE_FLAG_FLATTENED)) {
+ called_func->u.cval++;
+ }
+ /* Remove the called function from the list */
+ called_func->prev->next = called_func->next;
+ called_func->next->prev = called_func->prev;
+
+ /* Place the called function before me on the list */
+ called_func->next = func;
+ called_func->prev = func->prev;
+ called_func->prev->next = called_func;
+ called_func->next->prev = called_func;
+ }
+ ptr = ptr->next;
+ } while(ptr != first);
+ func->id |= TRIPLE_FLAG_FLATTENED;
+}
+
+static void mark_live_functions(struct compile_state *state)
+{
+ /* Ensure state->main_function is the last function in
+ * the list of functions.
+ */
+ if ((state->main_function->next != state->functions) ||
+ (state->functions->prev != state->main_function)) {
+ internal_error(state, 0,
+ "state->main_function is not at the end of the function list ");
+ }
+ state->main_function->u.cval = 1;
+ reverse_walk_functions(state, mark_live, 0);
+}
+
static int local_triple(struct compile_state *state,
struct triple *func, struct triple *ins)
{
int local = (ins->id & TRIPLE_FLAG_LOCAL);
#if 0
if (!local) {
- fprintf(stderr, "global: ");
- display_triple(stderr, ins);
+ FILE *fp = state->errout;
+ fprintf(fp, "global: ");
+ display_triple(fp, ins);
}
#endif
return local;
@@ -10089,11 +13661,12 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
struct triple *new, *old;
if (state->compiler->debug & DEBUG_INLINE) {
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
- display_func(stdout, ofunc);
- fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ FILE *fp = state->dbgout;
+ fprintf(fp, "\n");
+ loc(fp, state, 0);
+ fprintf(fp, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(state, fp, ofunc);
+ fprintf(fp, "__________ %s _________ done\n\n", __FUNCTION__);
}
/* Make a new copy of the old function */
@@ -10104,8 +13677,8 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
struct triple *new;
struct occurance *occurance;
int old_lhs, old_rhs;
- old_lhs = TRIPLE_LHS(old->sizes);
- old_rhs = TRIPLE_RHS(old->sizes);
+ old_lhs = old->lhs;
+ old_rhs = old->rhs;
occurance = inline_occurance(state, base_occurance, old->occurance);
if (ofunc->u.cval && (old->op == OP_FCALL)) {
MISC(old, 0)->u.cval += 1;
@@ -10122,14 +13695,11 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
insert_triple(state, nfirst, new);
}
new->id |= TRIPLE_FLAG_FLATTENED;
+ new->id |= old->id & TRIPLE_FLAG_COPY;
/* During the copy remember new as user of old */
use_triple(old, new);
- /* Populate the return type if present */
- if (old == MISC(ofunc, 0)) {
- MISC(nfunc, 0) = new;
- }
/* Remember which instructions are local */
old->id |= TRIPLE_FLAG_LOCAL;
old = old->next;
@@ -10142,7 +13712,7 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
struct triple **oexpr, **nexpr;
int count, i;
/* Lookup where the copy is, to join pointers */
- count = TRIPLE_SIZE(old->sizes);
+ count = TRIPLE_SIZE(old);
for(i = 0; i < count; i++) {
oexpr = &old->param[i];
nexpr = &new->param[i];
@@ -10159,7 +13729,7 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
use_triple(*nexpr, new);
}
if (!*nexpr && *oexpr) {
- internal_error(state, 0, "Could not copy %d\n", i);
+ internal_error(state, 0, "Could not copy %d", i);
}
}
old = old->next;
@@ -10179,91 +13749,592 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
return nfunc;
}
-static struct triple *flatten_inline_call(
- struct compile_state *state, struct triple *first, struct triple *ptr)
+static void expand_inline_call(
+ struct compile_state *state, struct triple *me, struct triple *fcall)
{
/* Inline the function call */
struct type *ptype;
- struct triple *ofunc, *nfunc, *nfirst, *param, *result;
+ struct triple *ofunc, *nfunc, *nfirst, *result, *retvar, *ins;
struct triple *end, *nend;
int pvals, i;
/* Find the triples */
- ofunc = MISC(ptr, 0);
+ ofunc = MISC(fcall, 0);
if (ofunc->op != OP_LIST) {
internal_error(state, 0, "improper function");
}
- nfunc = copy_func(state, ofunc, ptr->occurance);
- nfirst = RHS(nfunc, 0)->next->next;
+ nfunc = copy_func(state, ofunc, fcall->occurance);
/* Prepend the parameter reading into the new function list */
ptype = nfunc->type->right;
- param = RHS(nfunc, 0)->next->next;
- pvals = TRIPLE_RHS(ptr->sizes);
+ pvals = fcall->rhs;
for(i = 0; i < pvals; i++) {
struct type *atype;
- struct triple *arg;
+ struct triple *arg, *param;
atype = ptype;
if ((ptype->type & TYPE_MASK) == TYPE_PRODUCT) {
atype = ptype->left;
}
- while((param->type->type & TYPE_MASK) != (atype->type & TYPE_MASK)) {
- param = param->next;
+ param = farg(state, nfunc, i);
+ if ((param->type->type & TYPE_MASK) != (atype->type & TYPE_MASK)) {
+ internal_error(state, fcall, "param %d type mismatch", i);
}
- arg = RHS(ptr, i);
- flatten(state, nfirst, write_expr(state, param, arg));
+ arg = RHS(fcall, i);
+ flatten(state, fcall, write_expr(state, param, arg));
ptype = ptype->right;
- param = param->next;
}
result = 0;
if ((nfunc->type->left->type & TYPE_MASK) != TYPE_VOID) {
- result = read_expr(state, MISC(nfunc,0));
+ result = read_expr(state,
+ deref_index(state, fresult(state, nfunc), 1));
}
if (state->compiler->debug & DEBUG_INLINE) {
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
- display_func(stdout, nfunc);
- fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
- }
-
- /* Get rid of the extra triples */
- nfirst = RHS(nfunc, 0)->next->next;
- release_triple(state, RHS(nfunc, 0)->prev->prev);
- release_triple(state, RHS(nfunc, 0)->prev);
- release_triple(state, RHS(nfunc, 0)->next);
- free_triple(state, RHS(nfunc, 0));
+ FILE *fp = state->dbgout;
+ fprintf(fp, "\n");
+ loc(fp, state, 0);
+ fprintf(fp, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(state, fp, nfunc);
+ fprintf(fp, "__________ %s _________ done\n\n", __FUNCTION__);
+ }
+
+ /*
+ * Get rid of the extra triples
+ */
+ /* Remove the read of the return address */
+ ins = RHS(nfunc, 0)->prev->prev;
+ if ((ins->op != OP_READ) || (RHS(ins, 0) != fretaddr(state, nfunc))) {
+ internal_error(state, ins, "Not return addres read?");
+ }
+ release_triple(state, ins);
+ /* Remove the return instruction */
+ ins = RHS(nfunc, 0)->prev;
+ if (ins->op != OP_RET) {
+ internal_error(state, ins, "Not return?");
+ }
+ release_triple(state, ins);
+ /* Remove the retaddres variable */
+ retvar = fretaddr(state, nfunc);
+ if ((retvar->lhs != 1) ||
+ (retvar->op != OP_ADECL) ||
+ (retvar->next->op != OP_PIECE) ||
+ (MISC(retvar->next, 0) != retvar)) {
+ internal_error(state, retvar, "Not the return address?");
+ }
+ release_triple(state, retvar->next);
+ release_triple(state, retvar);
+
+ /* Remove the label at the start of the function */
+ ins = RHS(nfunc, 0);
+ if (ins->op != OP_LABEL) {
+ internal_error(state, ins, "Not label?");
+ }
+ nfirst = ins->next;
+ free_triple(state, ins);
+ /* Release the new function header */
RHS(nfunc, 0) = 0;
free_triple(state, nfunc);
/* Append the new function list onto the return list */
- end = first->prev;
+ end = fcall->prev;
nend = nfirst->prev;
end->next = nfirst;
nfirst->prev = end;
- nend->next = first;
- first->prev = nend;
+ nend->next = fcall;
+ fcall->prev = nend;
- return result;
+ /* Now the result reading code */
+ if (result) {
+ result = flatten(state, fcall, result);
+ propogate_use(state, fcall, result);
+ }
+
+ /* Release the original fcall instruction */
+ release_triple(state, fcall);
+
+ return;
}
-static struct triple *flatten_function_call(
- struct compile_state *state, struct triple *first, struct triple *ptr)
+/*
+ *
+ * Type of the result variable.
+ *
+ * result
+ * |
+ * +----------+------------+
+ * | |
+ * union of closures result_type
+ * |
+ * +------------------+---------------+
+ * | |
+ * closure1 ... closuerN
+ * | |
+ * +----+--+-+--------+-----+ +----+----+---+-----+
+ * | | | | | | | | |
+ * var1 var2 var3 ... varN result var1 var2 ... varN result
+ * |
+ * +--------+---------+
+ * | |
+ * union of closures result_type
+ * |
+ * +-----+-------------------+
+ * | |
+ * closure1 ... closureN
+ * | |
+ * +-----+---+----+----+ +----+---+----+-----+
+ * | | | | | | | |
+ * var1 var2 ... varN result var1 var2 ... varN result
+ */
+
+static int add_closure_type(struct compile_state *state,
+ struct triple *func, struct type *closure_type)
+{
+ struct type *type, *ctype, **next;
+ struct triple *var, *new_var;
+ int i;
+
+#if 0
+ FILE *fp = state->errout;
+ fprintf(fp, "original_type: ");
+ name_of(fp, fresult(state, func)->type);
+ fprintf(fp, "\n");
+#endif
+ /* find the original type */
+ var = fresult(state, func);
+ type = var->type;
+ if (type->elements != 2) {
+ internal_error(state, var, "bad return type");
+ }
+
+ /* Find the complete closure type and update it */
+ ctype = type->left->left;
+ next = &ctype->left;
+ while(((*next)->type & TYPE_MASK) == TYPE_OVERLAP) {
+ next = &(*next)->right;
+ }
+ *next = new_type(TYPE_OVERLAP, *next, dup_type(state, closure_type));
+ ctype->elements += 1;
+
+#if 0
+ fprintf(fp, "new_type: ");
+ name_of(fp, type);
+ fprintf(fp, "\n");
+ fprintf(fp, "ctype: %p %d bits: %d ",
+ ctype, ctype->elements, reg_size_of(state, ctype));
+ name_of(fp, ctype);
+ fprintf(fp, "\n");
+#endif
+
+ /* Regenerate the variable with the new type definition */
+ new_var = pre_triple(state, var, OP_ADECL, type, 0, 0);
+ new_var->id |= TRIPLE_FLAG_FLATTENED;
+ for(i = 0; i < new_var->lhs; i++) {
+ LHS(new_var, i)->id |= TRIPLE_FLAG_FLATTENED;
+ }
+
+ /* Point everyone at the new variable */
+ propogate_use(state, var, new_var);
+
+ /* Release the original variable */
+ for(i = 0; i < var->lhs; i++) {
+ release_triple(state, LHS(var, i));
+ }
+ release_triple(state, var);
+
+ /* Return the index of the added closure type */
+ return ctype->elements - 1;
+}
+
+static struct triple *closure_expr(struct compile_state *state,
+ struct triple *func, int closure_idx, int var_idx)
+{
+ return deref_index(state,
+ deref_index(state,
+ deref_index(state, fresult(state, func), 0),
+ closure_idx),
+ var_idx);
+}
+
+
+static void insert_triple_set(
+ struct triple_reg_set **head, struct triple *member)
+{
+ struct triple_reg_set *new;
+ new = xcmalloc(sizeof(*new), "triple_set");
+ new->member = member;
+ new->new = 0;
+ new->next = *head;
+ *head = new;
+}
+
+static int ordered_triple_set(
+ struct triple_reg_set **head, struct triple *member)
+{
+ struct triple_reg_set **ptr;
+ if (!member)
+ return 0;
+ ptr = head;
+ while(*ptr) {
+ if (member == (*ptr)->member) {
+ return 0;
+ }
+ /* keep the list ordered */
+ if (member->id < (*ptr)->member->id) {
+ break;
+ }
+ ptr = &(*ptr)->next;
+ }
+ insert_triple_set(ptr, member);
+ return 1;
+}
+
+
+static void free_closure_variables(struct compile_state *state,
+ struct triple_reg_set **enclose)
+{
+ struct triple_reg_set *entry, *next;
+ for(entry = *enclose; entry; entry = next) {
+ next = entry->next;
+ do_triple_unset(enclose, entry->member);
+ }
+}
+
+static int lookup_closure_index(struct compile_state *state,
+ struct triple *me, struct triple *val)
+{
+ struct triple *first, *ins, *next;
+ first = RHS(me, 0);
+ ins = next = first;
+ do {
+ struct triple *result;
+ struct triple *index0, *index1, *index2, *read, *write;
+ ins = next;
+ next = ins->next;
+ if (ins->op != OP_CALL) {
+ continue;
+ }
+ /* I am at a previous call point examine it closely */
+ if (ins->next->op != OP_LABEL) {
+ internal_error(state, ins, "call not followed by label");
+ }
+ /* Does this call does not enclose any variables? */
+ if ((ins->next->next->op != OP_INDEX) ||
+ (ins->next->next->u.cval != 0) ||
+ (result = MISC(ins->next->next, 0)) ||
+ (result->id & TRIPLE_FLAG_LOCAL)) {
+ continue;
+ }
+ index0 = ins->next->next;
+ /* The pattern is:
+ * 0 index result < 0 >
+ * 1 index 0 < ? >
+ * 2 index 1 < ? >
+ * 3 read 2
+ * 4 write 3 var
+ */
+ for(index0 = ins->next->next;
+ (index0->op == OP_INDEX) &&
+ (MISC(index0, 0) == result) &&
+ (index0->u.cval == 0) ;
+ index0 = write->next)
+ {
+ index1 = index0->next;
+ index2 = index1->next;
+ read = index2->next;
+ write = read->next;
+ if ((index0->op != OP_INDEX) ||
+ (index1->op != OP_INDEX) ||
+ (index2->op != OP_INDEX) ||
+ (read->op != OP_READ) ||
+ (write->op != OP_WRITE) ||
+ (MISC(index1, 0) != index0) ||
+ (MISC(index2, 0) != index1) ||
+ (RHS(read, 0) != index2) ||
+ (RHS(write, 0) != read)) {
+ internal_error(state, index0, "bad var read");
+ }
+ if (MISC(write, 0) == val) {
+ return index2->u.cval;
+ }
+ }
+ } while(next != first);
+ return -1;
+}
+
+static inline int enclose_triple(struct triple *ins)
+{
+ return (ins && ((ins->type->type & TYPE_MASK) != TYPE_VOID));
+}
+
+static void compute_closure_variables(struct compile_state *state,
+ struct triple *me, struct triple *fcall, struct triple_reg_set **enclose)
+{
+ struct triple_reg_set *set, *vars, **last_var;
+ struct basic_blocks bb;
+ struct reg_block *rb;
+ struct block *block;
+ struct triple *old_result, *first, *ins;
+ size_t count, idx;
+ unsigned long used_indicies;
+ int i, max_index;
+#define MAX_INDICIES (sizeof(used_indicies)*CHAR_BIT)
+#define ID_BITS(X) ((X) & (TRIPLE_FLAG_LOCAL -1))
+ struct {
+ unsigned id;
+ int index;
+ } *info;
+
+
+ /* Find the basic blocks of this function */
+ bb.func = me;
+ bb.first = RHS(me, 0);
+ old_result = 0;
+ if (!triple_is_ret(state, bb.first->prev)) {
+ bb.func = 0;
+ } else {
+ old_result = fresult(state, me);
+ }
+ analyze_basic_blocks(state, &bb);
+
+ /* Find which variables are currently alive in a given block */
+ rb = compute_variable_lifetimes(state, &bb);
+
+ /* Find the variables that are currently alive */
+ block = block_of_triple(state, fcall);
+ if (!block || (block->vertex <= 0) || (block->vertex > bb.last_vertex)) {
+ internal_error(state, fcall, "No reg block? block: %p", block);
+ }
+
+#if DEBUG_EXPLICIT_CLOSURES
+ print_live_variables(state, &bb, rb, state->dbgout);
+ fflush(state->dbgout);
+#endif
+
+ /* Count the number of triples in the function */
+ first = RHS(me, 0);
+ ins = first;
+ count = 0;
+ do {
+ count++;
+ ins = ins->next;
+ } while(ins != first);
+
+ /* Allocate some memory to temorary hold the id info */
+ info = xcmalloc(sizeof(*info) * (count +1), "info");
+
+ /* Mark the local function */
+ first = RHS(me, 0);
+ ins = first;
+ idx = 1;
+ do {
+ info[idx].id = ins->id;
+ ins->id = TRIPLE_FLAG_LOCAL | idx;
+ idx++;
+ ins = ins->next;
+ } while(ins != first);
+
+ /*
+ * Build the list of variables to enclose.
+ *
+ * A target it to put the same variable in the
+ * same slot for ever call of a given function.
+ * After coloring this removes all of the variable
+ * manipulation code.
+ *
+ * The list of variables to enclose is built ordered
+ * program order because except in corner cases this
+ * gives me the stability of assignment I need.
+ *
+ * To gurantee that stability I lookup the variables
+ * to see where they have been used before and
+ * I build my final list with the assigned indicies.
+ */
+ vars = 0;
+ if (enclose_triple(old_result)) {
+ ordered_triple_set(&vars, old_result);
+ }
+ for(set = rb[block->vertex].out; set; set = set->next) {
+ if (!enclose_triple(set->member)) {
+ continue;
+ }
+ if ((set->member == fcall) || (set->member == old_result)) {
+ continue;
+ }
+ if (!local_triple(state, me, set->member)) {
+ internal_error(state, set->member, "not local?");
+ }
+ ordered_triple_set(&vars, set->member);
+ }
+
+ /* Lookup the current indicies of the live varialbe */
+ used_indicies = 0;
+ max_index = -1;
+ for(set = vars; set ; set = set->next) {
+ struct triple *ins;
+ int index;
+ ins = set->member;
+ index = lookup_closure_index(state, me, ins);
+ info[ID_BITS(ins->id)].index = index;
+ if (index < 0) {
+ continue;
+ }
+ if (index >= MAX_INDICIES) {
+ internal_error(state, ins, "index unexpectedly large");
+ }
+ if (used_indicies & (1 << index)) {
+ internal_error(state, ins, "index previously used?");
+ }
+ /* Remember which indicies have been used */
+ used_indicies |= (1 << index);
+ if (index > max_index) {
+ max_index = index;
+ }
+ }
+
+ /* Walk through the live variables and make certain
+ * everything is assigned an index.
+ */
+ for(set = vars; set; set = set->next) {
+ struct triple *ins;
+ int index;
+ ins = set->member;
+ index = info[ID_BITS(ins->id)].index;
+ if (index >= 0) {
+ continue;
+ }
+ /* Find the lowest unused index value */
+ for(index = 0; index < MAX_INDICIES; index++) {
+ if (!(used_indicies & (1 << index))) {
+ break;
+ }
+ }
+ if (index == MAX_INDICIES) {
+ internal_error(state, ins, "no free indicies?");
+ }
+ info[ID_BITS(ins->id)].index = index;
+ /* Remember which indicies have been used */
+ used_indicies |= (1 << index);
+ if (index > max_index) {
+ max_index = index;
+ }
+ }
+
+ /* Build the return list of variables with positions matching
+ * their indicies.
+ */
+ *enclose = 0;
+ last_var = enclose;
+ for(i = 0; i <= max_index; i++) {
+ struct triple *var;
+ var = 0;
+ if (used_indicies & (1 << i)) {
+ for(set = vars; set; set = set->next) {
+ int index;
+ index = info[ID_BITS(set->member->id)].index;
+ if (index == i) {
+ var = set->member;
+ break;
+ }
+ }
+ if (!var) {
+ internal_error(state, me, "missing variable");
+ }
+ }
+ insert_triple_set(last_var, var);
+ last_var = &(*last_var)->next;
+ }
+
+#if DEBUG_EXPLICIT_CLOSURES
+ /* Print out the variables to be enclosed */
+ loc(state->dbgout, state, fcall);
+ fprintf(state->dbgout, "Alive: \n");
+ for(set = *enclose; set; set = set->next) {
+ display_triple(state->dbgout, set->member);
+ }
+ fflush(state->dbgout);
+#endif
+
+ /* Clear the marks */
+ ins = first;
+ do {
+ ins->id = info[ID_BITS(ins->id)].id;
+ ins = ins->next;
+ } while(ins != first);
+
+ /* Release the ordered list of live variables */
+ free_closure_variables(state, &vars);
+
+ /* Release the storage of the old ids */
+ xfree(info);
+
+ /* Release the variable lifetime information */
+ free_variable_lifetimes(state, &bb, rb);
+
+ /* Release the basic blocks of this function */
+ free_basic_blocks(state, &bb);
+}
+
+static void expand_function_call(
+ struct compile_state *state, struct triple *me, struct triple *fcall)
{
/* Generate an ordinary function call */
+ struct type *closure_type, **closure_next;
struct triple *func, *func_first, *func_last, *retvar;
- struct type *ptype;
- struct triple *param;
+ struct triple *first;
+ struct type *ptype, *rtype;
struct triple *jmp;
struct triple *ret_addr, *ret_loc, *ret_set;
- struct triple *result;
- int pvals, i;
+ struct triple_reg_set *enclose, *set;
+ int closure_idx, pvals, i;
+
+#if DEBUG_EXPLICIT_CLOSURES
+ FILE *fp = state->dbgout;
+ fprintf(fp, "\ndisplay_func(me) ptr: %p\n", fcall);
+ display_func(state, fp, MISC(fcall, 0));
+ display_func(state, fp, me);
+ fprintf(fp, "__________ %s _________ done\n\n", __FUNCTION__);
+#endif
- FINISHME();
/* Find the triples */
- func = MISC(ptr, 0);
+ func = MISC(fcall, 0);
func_first = RHS(func, 0);
- retvar = func_first->next;
+ retvar = fretaddr(state, func);
func_last = func_first->prev;
+ first = fcall->next;
+
+ /* Find what I need to enclose */
+ compute_closure_variables(state, me, fcall, &enclose);
+
+ /* Compute the closure type */
+ closure_type = new_type(TYPE_TUPLE, 0, 0);
+ closure_type->elements = 0;
+ closure_next = &closure_type->left;
+ for(set = enclose; set ; set = set->next) {
+ struct type *type;
+ type = &void_type;
+ if (set->member) {
+ type = set->member->type;
+ }
+ if (!*closure_next) {
+ *closure_next = type;
+ } else {
+ *closure_next = new_type(TYPE_PRODUCT, *closure_next,
+ type);
+ closure_next = &(*closure_next)->right;
+ }
+ closure_type->elements += 1;
+ }
+ if (closure_type->elements == 0) {
+ closure_type->type = TYPE_VOID;
+ }
+
+
+#if DEBUG_EXPLICIT_CLOSURES
+ fprintf(state->dbgout, "closure type: ");
+ name_of(state->dbgout, closure_type);
+ fprintf(state->dbgout, "\n");
+#endif
+
+ /* Update the called functions closure variable */
+ closure_idx = add_closure_type(state, func, closure_type);
/* Generate some needed triples */
ret_loc = label(state);
@@ -10271,63 +14342,139 @@ static struct triple *flatten_function_call(
/* Pass the parameters to the new function */
ptype = func->type->right;
- param = func_first->next->next;
- pvals = TRIPLE_RHS(ptr->sizes);
+ pvals = fcall->rhs;
for(i = 0; i < pvals; i++) {
struct type *atype;
- struct triple *arg;
+ struct triple *arg, *param;
atype = ptype;
if ((ptype->type & TYPE_MASK) == TYPE_PRODUCT) {
atype = ptype->left;
}
- while((param->type->type & TYPE_MASK) != (atype->type & TYPE_MASK)) {
- param = param->next;
+ param = farg(state, func, i);
+ if ((param->type->type & TYPE_MASK) != (atype->type & TYPE_MASK)) {
+ internal_error(state, fcall, "param type mismatch");
}
- arg = RHS(ptr, i);
+ arg = RHS(fcall, i);
flatten(state, first, write_expr(state, param, arg));
ptype = ptype->right;
- param = param->next;
}
-
+ rtype = func->type->left;
+
/* Thread the triples together */
ret_loc = flatten(state, first, ret_loc);
+
+ /* Save the active variables in the result variable */
+ for(i = 0, set = enclose; set ; set = set->next, i++) {
+ if (!set->member) {
+ continue;
+ }
+ flatten(state, ret_loc,
+ write_expr(state,
+ closure_expr(state, func, closure_idx, i),
+ read_expr(state, set->member)));
+ }
+
+ /* Initialize the return value */
+ if ((rtype->type & TYPE_MASK) != TYPE_VOID) {
+ flatten(state, ret_loc,
+ write_expr(state,
+ deref_index(state, fresult(state, func), 1),
+ new_triple(state, OP_UNKNOWNVAL, rtype, 0, 0)));
+ }
+
ret_addr = flatten(state, ret_loc, ret_addr);
ret_set = flatten(state, ret_loc, write_expr(state, retvar, ret_addr));
jmp = flatten(state, ret_loc,
call(state, retvar, ret_addr, func_first, func_last));
+ /* Restore the active variables from the result variable */
+ for(i = 0, set = enclose; set ; set = set->next, i++) {
+ struct triple_set *use, *next;
+ struct triple *new;
+ if (!set->member || (set->member == fcall)) {
+ continue;
+ }
+ /* Generate an expression for the value */
+ new = flatten(state, first,
+ read_expr(state,
+ closure_expr(state, func, closure_idx, i)));
+
+
+ /* If the original is an lvalue restore the preserved value */
+ if (is_lvalue(state, set->member)) {
+ flatten(state, first,
+ write_expr(state, set->member, new));
+ continue;
+ }
+ /* If the original is a value update the dominated uses */
+
+#if DEBUG_EXPLICIT_CLOSURES
+ fprintf(state->errout, "Updating domindated uses: %p -> %p\n",
+ set->member, new);
+#endif
+ /* If fcall dominates the use update the expression */
+ for(use = set->member->use; use; use = next) {
+ /* Replace use modifies the use chain and
+ * removes use, so I must take a copy of the
+ * next entry early.
+ */
+ next = use->next;
+ if (!tdominates(state, fcall, use->member)) {
+ continue;
+ }
+ replace_use(state, set->member, new, use->member);
+ }
+ }
+
/* Find the result */
- result = 0;
- if ((func->type->left->type & TYPE_MASK) != TYPE_VOID) {
- result = read_expr(state, MISC(func, 0));
+ if ((rtype->type & TYPE_MASK) != TYPE_VOID) {
+ struct triple * result;
+ result = flatten(state, first,
+ read_expr(state,
+ deref_index(state, fresult(state, func), 1)));
+
+ propogate_use(state, fcall, result);
}
+ /* Release the original fcall instruction */
+ release_triple(state, fcall);
+
+ /* Release the closure variable list */
+ free_closure_variables(state, &enclose);
+
if (state->compiler->debug & DEBUG_INLINE) {
- fprintf(stdout, "\n");
- loc(stdout, state, 0);
- fprintf(stdout, "\n__________ %s _________\n", __FUNCTION__);
- display_func(stdout, func);
- fprintf(stdout, "__________ %s _________ done\n\n", __FUNCTION__);
+ FILE *fp = state->dbgout;
+ fprintf(fp, "\n");
+ loc(fp, state, 0);
+ fprintf(fp, "\n__________ %s _________\n", __FUNCTION__);
+ display_func(state, fp, func);
+ display_func(state, fp, me);
+ fprintf(fp, "__________ %s _________ done\n\n", __FUNCTION__);
}
- return result;
+ return;
}
-static void inline_functions(struct compile_state *state, struct triple *first)
+static int do_inline(struct compile_state *state, struct triple *func)
{
- struct triple *ptr, *next;
- ptr = next = first;
- do {
- int do_inline;
- struct triple *func, *prev, *new;
- ptr = next;
- prev = ptr->prev;
- next = ptr->next;
- if (ptr->op != OP_FCALL) {
- continue;
+ int do_inline;
+ int policy;
+
+ policy = state->compiler->flags & COMPILER_INLINE_MASK;
+ switch(policy) {
+ case COMPILER_INLINE_ALWAYS:
+ do_inline = 1;
+ if (func->type->type & ATTRIB_NOINLINE) {
+ error(state, func, "noinline with always_inline compiler option");
}
- func = MISC(ptr, 0);
- /* See if the function should be inlined */
+ break;
+ case COMPILER_INLINE_NEVER:
+ do_inline = 0;
+ if (func->type->type & ATTRIB_ALWAYS_INLINE) {
+ error(state, func, "always_inline with noinline compiler option");
+ }
+ break;
+ case COMPILER_INLINE_DEFAULTON:
switch(func->type->type & STOR_MASK) {
case STOR_STATIC | STOR_INLINE:
case STOR_LOCAL | STOR_INLINE:
@@ -10335,41 +14482,101 @@ static void inline_functions(struct compile_state *state, struct triple *first)
do_inline = 1;
break;
default:
- do_inline = (func->u.cval == 1);
+ do_inline = 1;
break;
}
- if (state->compiler->flags & COMPILER_ALWAYS_INLINE) {
+ break;
+ case COMPILER_INLINE_DEFAULTOFF:
+ switch(func->type->type & STOR_MASK) {
+ case STOR_STATIC | STOR_INLINE:
+ case STOR_LOCAL | STOR_INLINE:
+ case STOR_EXTERN | STOR_INLINE:
do_inline = 1;
- }
- if (!(state->compiler->flags & COMPILER_INLINE)) {
+ break;
+ default:
do_inline = 0;
+ break;
+ }
+ break;
+ case COMPILER_INLINE_NOPENALTY:
+ switch(func->type->type & STOR_MASK) {
+ case STOR_STATIC | STOR_INLINE:
+ case STOR_LOCAL | STOR_INLINE:
+ case STOR_EXTERN | STOR_INLINE:
+ do_inline = 1;
+ break;
+ default:
+ do_inline = (func->u.cval == 1);
+ break;
+ }
+ break;
+ default:
+ do_inline = 0;
+ internal_error(state, 0, "Unimplemented inline policy");
+ break;
+ }
+ /* Force inlining */
+ if (func->type->type & ATTRIB_NOINLINE) {
+ do_inline = 0;
+ }
+ if (func->type->type & ATTRIB_ALWAYS_INLINE) {
+ do_inline = 1;
+ }
+ return do_inline;
+}
+
+static void inline_function(struct compile_state *state, struct triple *me, void *arg)
+{
+ struct triple *first, *ptr, *next;
+ /* If the function is not used don't bother */
+ if (me->u.cval <= 0) {
+ return;
+ }
+ if (state->compiler->debug & DEBUG_CALLS2) {
+ FILE *fp = state->dbgout;
+ fprintf(fp, "in: %s\n",
+ me->type->type_ident->name);
+ }
+
+ first = RHS(me, 0);
+ ptr = next = first;
+ do {
+ struct triple *func, *prev;
+ ptr = next;
+ prev = ptr->prev;
+ next = ptr->next;
+ if (ptr->op != OP_FCALL) {
+ continue;
}
- if (!do_inline) {
+ func = MISC(ptr, 0);
+ /* See if the function should be inlined */
+ if (!do_inline(state, func)) {
+ /* Put a label after the fcall */
+ post_triple(state, ptr, OP_LABEL, &void_type, 0, 0);
continue;
}
- if (state->compiler->debug & DEBUG_INLINE) {
- fprintf(stderr, "inlining %s\n",
+ if (state->compiler->debug & DEBUG_CALLS) {
+ FILE *fp = state->dbgout;
+ if (state->compiler->debug & DEBUG_CALLS2) {
+ loc(fp, state, ptr);
+ }
+ fprintf(fp, "inlining %s\n",
func->type->type_ident->name);
+ fflush(fp);
}
/* Update the function use counts */
func->u.cval -= 1;
- /* Unhook the call and really inline it */
- next->prev = prev;
- prev->next = next;
- ptr->next = ptr->prev = ptr;
-
- new = flatten(state, next,
- flatten_inline_call(state, next, ptr));
- if (new) {
- propogate_use(state, ptr, new);
- }
- release_triple(state, ptr);
+
+ /* Replace the fcall with the called function */
+ expand_inline_call(state, me, ptr);
+
next = prev->next;
} while (next != first);
+
ptr = next = first;
do {
- struct triple *func, *prev, *new;
+ struct triple *prev, *func;
ptr = next;
prev = ptr->prev;
next = ptr->next;
@@ -10377,36 +14584,42 @@ static void inline_functions(struct compile_state *state, struct triple *first)
continue;
}
func = MISC(ptr, 0);
- inline_functions(state, RHS(func, 0));
- /* Unhook the call and really flatten it */
- next->prev = prev;
- prev->next = next;
- ptr->next = ptr->prev = ptr;
- new = flatten(state, next,
- flatten_function_call(state, next, ptr));
- if (new) {
- propogate_use(state, ptr, new);
- }
- release_triple(state, ptr);
+ if (state->compiler->debug & DEBUG_CALLS) {
+ FILE *fp = state->dbgout;
+ if (state->compiler->debug & DEBUG_CALLS2) {
+ loc(fp, state, ptr);
+ }
+ fprintf(fp, "calling %s\n",
+ func->type->type_ident->name);
+ fflush(fp);
+ }
+ /* Replace the fcall with the instruction sequence
+ * needed to make the call.
+ */
+ expand_function_call(state, me, ptr);
next = prev->next;
} while(next != first);
}
-
+
+static void inline_functions(struct compile_state *state, struct triple *func)
+{
+ inline_function(state, func, 0);
+ reverse_walk_functions(state, inline_function, 0);
+}
+
static void insert_function(struct compile_state *state,
struct triple *func, void *arg)
{
struct triple *first, *end, *ffirst, *fend;
if (state->compiler->debug & DEBUG_INLINE) {
- fprintf(stderr, "%s func count: %d\n",
+ FILE *fp = state->errout;
+ fprintf(fp, "%s func count: %d\n",
func->type->type_ident->name, func->u.cval);
}
if (func->u.cval == 0) {
return;
}
- if (state->compiler->flags & COMPILER_ALWAYS_INLINE) {
- internal_error(state, func, "always inline failed\n");
- }
/* Find the end points of the lists */
first = arg;
@@ -10421,10 +14634,61 @@ static void insert_function(struct compile_state *state,
first->prev = fend;
}
+struct triple *input_asm(struct compile_state *state)
+{
+ struct asm_info *info;
+ struct triple *def;
+ int i, out;
+
+ info = xcmalloc(sizeof(*info), "asm_info");
+ info->str = "";
+
+ out = sizeof(arch_input_regs)/sizeof(arch_input_regs[0]);
+ memcpy(&info->tmpl.lhs, arch_input_regs, sizeof(arch_input_regs));
+
+ def = new_triple(state, OP_ASM, &void_type, out, 0);
+ def->u.ainfo = info;
+ def->id |= TRIPLE_FLAG_VOLATILE;
+
+ for(i = 0; i < out; i++) {
+ struct triple *piece;
+ piece = triple(state, OP_PIECE, &int_type, def, 0);
+ piece->u.cval = i;
+ LHS(def, i) = piece;
+ }
+
+ return def;
+}
+
+struct triple *output_asm(struct compile_state *state)
+{
+ struct asm_info *info;
+ struct triple *def;
+ int in;
+
+ info = xcmalloc(sizeof(*info), "asm_info");
+ info->str = "";
+
+ in = sizeof(arch_output_regs)/sizeof(arch_output_regs[0]);
+ memcpy(&info->tmpl.rhs, arch_output_regs, sizeof(arch_output_regs));
+
+ def = new_triple(state, OP_ASM, &void_type, 0, in);
+ def->u.ainfo = info;
+ def->id |= TRIPLE_FLAG_VOLATILE;
+
+ return def;
+}
+
static void join_functions(struct compile_state *state)
{
- struct triple *jmp, *start, *end, *call;
+ struct triple *jmp, *start, *end, *call, *in, *out, *func;
struct file_state file;
+ struct type *pnext, *param;
+ struct type *result_type, *args_type;
+ int idx;
+
+ /* Be clear the functions have not been joined yet */
+ state->functions_joined = 0;
/* Dummy file state to get debug handing right */
memset(&file, 0, sizeof(file));
@@ -10435,25 +14699,115 @@ static void join_functions(struct compile_state *state)
file.prev = state->file;
state->file = &file;
state->function = "";
-
+
+ /* The type of arguments */
+ args_type = state->main_function->type->right;
+ /* The return type without any specifiers */
+ result_type = clone_type(0, state->main_function->type->left);
+
+
+ /* Verify the external arguments */
+ if (registers_of(state, args_type) > ARCH_INPUT_REGS) {
+ error(state, state->main_function,
+ "Too many external input arguments");
+ }
+ if (registers_of(state, result_type) > ARCH_OUTPUT_REGS) {
+ error(state, state->main_function,
+ "Too many external output arguments");
+ }
+
/* Lay down the basic program structure */
- end = label(state);
- start = label(state);
- start = flatten(state, state->first, start);
- end = flatten(state, state->first, end);
- call = new_triple(state, OP_FCALL, &void_type, -1, 0);
+ end = label(state);
+ start = label(state);
+ start = flatten(state, state->first, start);
+ end = flatten(state, state->first, end);
+ in = input_asm(state);
+ out = output_asm(state);
+ call = new_triple(state, OP_FCALL, result_type, -1, registers_of(state, args_type));
MISC(call, 0) = state->main_function;
- flatten(state, state->first, call);
-
+ in = flatten(state, state->first, in);
+ call = flatten(state, state->first, call);
+ out = flatten(state, state->first, out);
+
+
+ /* Read the external input arguments */
+ pnext = args_type;
+ idx = 0;
+ while(pnext && ((pnext->type & TYPE_MASK) != TYPE_VOID)) {
+ struct triple *expr;
+ param = pnext;
+ pnext = 0;
+ if ((param->type & TYPE_MASK) == TYPE_PRODUCT) {
+ pnext = param->right;
+ param = param->left;
+ }
+ if (registers_of(state, param) != 1) {
+ error(state, state->main_function,
+ "Arg: %d %s requires multiple registers",
+ idx + 1, param->field_ident->name);
+ }
+ expr = read_expr(state, LHS(in, idx));
+ RHS(call, idx) = expr;
+ expr = flatten(state, call, expr);
+ use_triple(expr, call);
+
+ idx++;
+ }
+
+
+ /* Write the external output arguments */
+ pnext = result_type;
+ if ((pnext->type & TYPE_MASK) == TYPE_STRUCT) {
+ pnext = result_type->left;
+ }
+ for(idx = 0; idx < out->rhs; idx++) {
+ struct triple *expr;
+ param = pnext;
+ pnext = 0;
+ if (param && ((param->type & TYPE_MASK) == TYPE_PRODUCT)) {
+ pnext = param->right;
+ param = param->left;
+ }
+ if (param && ((param->type & TYPE_MASK) == TYPE_VOID)) {
+ param = 0;
+ }
+ if (param) {
+ if (registers_of(state, param) != 1) {
+ error(state, state->main_function,
+ "Result: %d %s requires multiple registers",
+ idx, param->field_ident->name);
+ }
+ expr = read_expr(state, call);
+ if ((result_type->type & TYPE_MASK) == TYPE_STRUCT) {
+ expr = deref_field(state, expr, param->field_ident);
+ }
+ } else {
+ expr = triple(state, OP_UNKNOWNVAL, &int_type, 0, 0);
+ }
+ flatten(state, out, expr);
+ RHS(out, idx) = expr;
+ use_triple(expr, out);
+ }
+
+ /* Allocate a dummy containing function */
+ func = triple(state, OP_LIST,
+ new_type(TYPE_FUNCTION, &void_type, &void_type), 0, 0);
+ func->type->type_ident = lookup(state, "", 0);
+ RHS(func, 0) = state->first;
+ func->u.cval = 1;
+
/* See which functions are called, and how often */
- mark_live_functions(state, state->first);
- inline_functions(state, state->first);
+ mark_live_functions(state);
+ inline_functions(state, func);
walk_functions(state, insert_function, end);
if (start->next != end) {
jmp = flatten(state, start, branch(state, end, 0));
}
+ /* OK now the functions have been joined. */
+ state->functions_joined = 1;
+
/* Done now cleanup */
state->file = file.prev;
state->function = 0;
@@ -10586,13 +14940,14 @@ static void unipdomf_block(struct block *block, struct block *unipdomf)
static int walk_triples(
struct compile_state *state,
- int (*cb)(struct compile_state *state, struct triple *ptr))
+ int (*cb)(struct compile_state *state, struct triple *ptr, void *arg),
+ void *arg)
{
struct triple *ptr;
int result;
ptr = state->first;
do {
- result = cb(state, ptr);
+ result = cb(state, ptr, arg);
if (ptr->next->prev != ptr) {
internal_error(state, ptr->next, "bad prev");
}
@@ -10602,8 +14957,9 @@ static int walk_triples(
}
#define PRINT_LIST 1
-static int do_print_triple(struct compile_state *state, struct triple *ins)
+static int do_print_triple(struct compile_state *state, struct triple *ins, void *arg)
{
+ FILE *fp = arg;
int op;
op = ins->op;
if (op == OP_LIST) {
@@ -10612,15 +14968,16 @@ static int do_print_triple(struct compile_state *state, struct triple *ins)
#endif
}
if ((op == OP_LABEL) && (ins->use)) {
- printf("\n%p:\n", ins);
+ fprintf(fp, "\n%p:\n", ins);
}
- display_triple(stdout, ins);
+ display_triple(fp, ins);
- if (triple_is_branch(state, ins) && ins->use && (ins->op != OP_RET)) {
+ if (triple_is_branch(state, ins) && ins->use &&
+ (ins->op != OP_RET) && (ins->op != OP_FCALL)) {
internal_error(state, ins, "branch used?");
}
if (triple_is_branch(state, ins)) {
- printf("\n");
+ fprintf(fp, "\n");
}
return 0;
}
@@ -10628,7 +14985,10 @@ static int do_print_triple(struct compile_state *state, struct triple *ins)
static void print_triples(struct compile_state *state)
{
if (state->compiler->debug & DEBUG_TRIPLES) {
- walk_triples(state, do_print_triple);
+ FILE *fp = state->dbgout;
+ fprintf(fp, "--------------- triples ---------------\n");
+ walk_triples(state, do_print_triple, fp);
+ fprintf(fp, "\n");
}
}
@@ -10647,15 +15007,16 @@ static void find_cf_blocks(struct cf_block *cf, struct block *block)
}
}
-static void print_control_flow(struct compile_state *state)
+static void print_control_flow(struct compile_state *state,
+ struct basic_blocks *bb)
{
struct cf_block *cf;
int i;
printf("\ncontrol flow\n");
- cf = xcmalloc(sizeof(*cf) * (state->last_vertex + 1), "cf_block");
- find_cf_blocks(cf, state->first_block);
+ cf = xcmalloc(sizeof(*cf) * (bb->last_vertex + 1), "cf_block");
+ find_cf_blocks(cf, bb->first_block);
- for(i = 1; i <= state->last_vertex; i++) {
+ for(i = 1; i <= bb->last_vertex; i++) {
struct block *block;
struct block_set *edge;
block = cf[i].block;
@@ -10671,26 +15032,114 @@ static void print_control_flow(struct compile_state *state)
xfree(cf);
}
+static void free_basic_block(struct compile_state *state, struct block *block)
+{
+ struct block_set *edge, *entry;
+ struct block *child;
+ if (!block) {
+ return;
+ }
+ if (block->vertex == -1) {
+ return;
+ }
+ block->vertex = -1;
+ for(edge = block->edges; edge; edge = edge->next) {
+ if (edge->member) {
+ unuse_block(edge->member, block);
+ }
+ }
+ if (block->idom) {
+ unidom_block(block->idom, block);
+ }
+ block->idom = 0;
+ if (block->ipdom) {
+ unipdom_block(block->ipdom, block);
+ }
+ block->ipdom = 0;
+ while((entry = block->use)) {
+ child = entry->member;
+ unuse_block(block, child);
+ if (child && (child->vertex != -1)) {
+ for(edge = child->edges; edge; edge = edge->next) {
+ edge->member = 0;
+ }
+ }
+ }
+ while((entry = block->idominates)) {
+ child = entry->member;
+ unidom_block(block, child);
+ if (child && (child->vertex != -1)) {
+ child->idom = 0;
+ }
+ }
+ while((entry = block->domfrontier)) {
+ child = entry->member;
+ undomf_block(block, child);
+ }
+ while((entry = block->ipdominates)) {
+ child = entry->member;
+ unipdom_block(block, child);
+ if (child && (child->vertex != -1)) {
+ child->ipdom = 0;
+ }
+ }
+ while((entry = block->ipdomfrontier)) {
+ child = entry->member;
+ unipdomf_block(block, child);
+ }
+ if (block->users != 0) {
+ internal_error(state, 0, "block still has users");
+ }
+ while((edge = block->edges)) {
+ child = edge->member;
+ remove_block_edge(block, child);
+
+ if (child && (child->vertex != -1)) {
+ free_basic_block(state, child);
+ }
+ }
+ memset(block, -1, sizeof(*block));
+ xfree(block);
+}
+
+static void free_basic_blocks(struct compile_state *state,
+ struct basic_blocks *bb)
+{
+ struct triple *first, *ins;
+ free_basic_block(state, bb->first_block);
+ bb->last_vertex = 0;
+ bb->first_block = bb->last_block = 0;
+ first = bb->first;
+ ins = first;
+ do {
+ if (triple_stores_block(state, ins)) {
+ ins->u.block = 0;
+ }
+ ins = ins->next;
+ } while(ins != first);
+
+}
-static struct block *basic_block(struct compile_state *state, struct triple *first)
+static struct block *basic_block(struct compile_state *state,
+ struct basic_blocks *bb, struct triple *first)
{
struct block *block;
struct triple *ptr;
- if (first->op != OP_LABEL) {
- internal_error(state, 0, "block does not start with a label");
+ if (!triple_is_label(state, first)) {
+ internal_error(state, first, "block does not start with a label");
}
/* See if this basic block has already been setup */
if (first->u.block != 0) {
return first->u.block;
}
/* Allocate another basic block structure */
- state->last_vertex += 1;
+ bb->last_vertex += 1;
block = xcmalloc(sizeof(*block), "block");
block->first = block->last = first;
- block->vertex = state->last_vertex;
+ block->vertex = bb->last_vertex;
ptr = first;
do {
- if ((ptr != first) && (ptr->op == OP_LABEL) && (ptr->use)) {
+ if ((ptr != first) && triple_is_label(state, ptr) && (ptr->use)) {
break;
}
block->last = ptr;
@@ -10702,13 +15151,17 @@ static struct block *basic_block(struct compile_state *state, struct triple *fir
break;
}
ptr = ptr->next;
- } while (ptr != state->first);
- if (ptr == state->first) {
+ } while (ptr != bb->first);
+ if ((ptr == bb->first) ||
+ ((ptr->next == bb->first) && (
+ triple_is_end(state, ptr) ||
+ triple_is_ret(state, ptr))))
+ {
/* The block has no outflowing edges */
}
- else if (ptr->op == OP_LABEL) {
+ else if (triple_is_label(state, ptr)) {
struct block *next;
- next = basic_block(state, ptr);
+ next = basic_block(state, bb, ptr);
add_block_edge(block, next, 0);
use_block(next, block);
}
@@ -10719,22 +15172,43 @@ static struct block *basic_block(struct compile_state *state, struct triple *fir
* I special case the first branch as that magically
* avoids some difficult cases for the register allocator.
*/
- expr = triple_targ(state, ptr, 0);
+ expr = triple_edge_targ(state, ptr, 0);
if (!expr) {
internal_error(state, ptr, "branch without targets");
}
first = *expr;
- expr = triple_targ(state, ptr, expr);
- for(; expr; expr = triple_targ(state, ptr, expr)) {
+ expr = triple_edge_targ(state, ptr, expr);
+ for(; expr; expr = triple_edge_targ(state, ptr, expr)) {
if (!*expr) continue;
- child = basic_block(state, *expr);
+ child = basic_block(state, bb, *expr);
use_block(child, block);
add_block_edge(block, child, 0);
}
if (first) {
- child = basic_block(state, first);
+ child = basic_block(state, bb, first);
use_block(child, block);
add_block_edge(block, child, 1);
+
+ /* Be certain the return block of a call is
+ * in a basic block. When it is not find
+ * start of the block, insert a label if
+ * necessary and build the basic block.
+ * Then add a fake edge from the start block
+ * to the return block of the function.
+ */
+ if (state->functions_joined && triple_is_call(state, ptr)
+ && !block_of_triple(state, MISC(ptr, 0))) {
+ struct block *tail;
+ struct triple *start;
+ start = triple_to_block_start(state, MISC(ptr, 0));
+ if (!triple_is_label(state, start)) {
+ start = pre_triple(state,
+ start, OP_LABEL, &void_type, 0, 0);
+ }
+ tail = basic_block(state, bb, start);
+ add_block_edge(child, tail, 0);
+ use_block(tail, child);
+ }
}
}
else {
@@ -10743,29 +15217,30 @@ static struct block *basic_block(struct compile_state *state, struct triple *fir
#if 0
{
struct block_set *edge;
- fprintf(stderr, "basic_block: %10p [%2d] ( %10p - %10p )",
+ FILE *fp = state->errout;
+ fprintf(fp, "basic_block: %10p [%2d] ( %10p - %10p )",
block, block->vertex,
block->first, block->last);
for(edge = block->edges; edge; edge = edge->next) {
- fprintf(stderr, " %10p [%2d]",
+ fprintf(fp, " %10p [%2d]",
edge->member ? edge->member->first : 0,
edge->member ? edge->member->vertex : -1);
}
- fprintf(stderr, "\n");
+ fprintf(fp, "\n");
}
#endif
return block;
}
-static void walk_blocks(struct compile_state *state,
+static void walk_blocks(struct compile_state *state, struct basic_blocks *bb,
void (*cb)(struct compile_state *state, struct block *block, void *arg),
void *arg)
{
struct triple *ptr, *first;
struct block *last_block;
last_block = 0;
- first = state->first;
+ first = bb->first;
ptr = first;
do {
if (triple_stores_block(state, ptr)) {
@@ -10801,10 +15276,14 @@ static void print_block(
if (block->first->op == OP_LABEL) {
fprintf(fp, "%p:\n", block->first);
}
- for(ptr = block->first; ; ptr = ptr->next) {
+ for(ptr = block->first; ; ) {
display_triple(fp, ptr);
if (ptr == block->last)
break;
+ ptr = ptr->next;
+ if (ptr == block->first) {
+ internal_error(state, 0, "missing block last?");
+ }
}
fprintf(fp, "users %d: ", block->users);
for(user = block->use; user; user = user->next) {
@@ -10819,24 +15298,25 @@ static void print_block(
static void romcc_print_blocks(struct compile_state *state, FILE *fp)
{
fprintf(fp, "--------------- blocks ---------------\n");
- walk_blocks(state, print_block, fp);
+ walk_blocks(state, &state->bb, print_block, fp);
}
static void print_blocks(struct compile_state *state, const char *func, FILE *fp)
{
if (state->compiler->debug & DEBUG_BASIC_BLOCKS) {
fprintf(fp, "After %s\n", func);
romcc_print_blocks(state, fp);
- print_control_flow(state);
+ print_control_flow(state, &state->bb);
}
}
-static void prune_nonblock_triples(struct compile_state *state)
+static void prune_nonblock_triples(struct compile_state *state,
+ struct basic_blocks *bb)
{
struct block *block;
struct triple *first, *ins, *next;
/* Delete the triples not in a basic block */
- first = state->first;
block = 0;
+ first = bb->first;
ins = first;
do {
next = ins->next;
@@ -10844,6 +15324,14 @@ static void prune_nonblock_triples(struct compile_state *state)
block = ins->u.block;
}
if (!block) {
+ struct triple_set *use;
+ for(use = ins->use; use; use = use->next) {
+ struct block *block;
+ block = block_of_triple(state, use->member);
+ if (block != 0) {
+ internal_error(state, ins, "pruning used ins?");
+ }
+ }
release_triple(state, ins);
}
if (block && block->last == ins) {
@@ -10853,145 +15341,55 @@ static void prune_nonblock_triples(struct compile_state *state)
} while(ins != first);
}
-static void setup_basic_blocks(struct compile_state *state)
+static void setup_basic_blocks(struct compile_state *state,
+ struct basic_blocks *bb)
{
- if (!triple_stores_block(state, state->first)) {
+ if (!triple_stores_block(state, bb->first)) {
internal_error(state, 0, "ins will not store block?");
}
+ /* Initialize the state */
+ bb->first_block = bb->last_block = 0;
+ bb->last_vertex = 0;
+ free_basic_blocks(state, bb);
+
/* Find the basic blocks */
- state->last_vertex = 0;
- state->first_block = basic_block(state, state->first);
- /* Delete the triples not in a basic block */
- prune_nonblock_triples(state);
+ bb->first_block = basic_block(state, bb, bb->first);
+ /* Be certain the last instruction of a function, or the
+ * entire program is in a basic block. When it is not find
+ * the start of the block, insert a label if necessary and build
+ * basic block. Then add a fake edge from the start block
+ * to the final block.
+ */
+ if (!block_of_triple(state, bb->first->prev)) {
+ struct triple *start;
+ struct block *tail;
+ start = triple_to_block_start(state, bb->first->prev);
+ if (!triple_is_label(state, start)) {
+ start = pre_triple(state,
+ start, OP_LABEL, &void_type, 0, 0);
+ }
+ tail = basic_block(state, bb, start);
+ add_block_edge(bb->first_block, tail, 0);
+ use_block(tail, bb->first_block);
+ }
+
/* Find the last basic block.
- *
- * For purposes of reverse flow computation it is
- * important that the last basic block is empty.
- * This allows the control flow graph to be modified to
- * have one unique starting block and one unique final block.
- * With the insertion of a few extra edges.
- *
- * If the final block contained instructions it could contain
- * phi functions from edges that would never contribute a
- * value. Which for now at least I consider a compile error.
*/
- state->last_block = block_of_triple(state, state->first->prev);
- if ((state->last_block->first != state->last_block->last) ||
- (state->last_block->last->op != OP_LABEL))
- {
- struct block *block, *prev_block;
- struct triple *final;
-
- prev_block = state->last_block;
-
- final = label(state);
- flatten(state, state->first, final);
- final->id |= TRIPLE_FLAG_VOLATILE;
- use_triple(final, final);
- block = basic_block(state, final);
-
- state->last_block = block;
+ bb->last_block = block_of_triple(state, bb->first->prev);
- add_block_edge(prev_block, block, 0);
- use_block(block, prev_block);
- }
+ /* Delete the triples not in a basic block */
+ prune_nonblock_triples(state, bb);
#if 0
/* If we are debugging print what I have just done */
if (state->compiler->debug & DEBUG_BASIC_BLOCKS) {
- print_blocks(state, stdout);
- print_control_flow(state);
+ print_blocks(state, state->dbgout);
+ print_control_flow(state, bb);
}
#endif
}
-static void free_basic_block(struct compile_state *state, struct block *block)
-{
- struct block_set *edge, *entry;
- struct block *child;
- if (!block) {
- return;
- }
- if (block->vertex == -1) {
- return;
- }
- block->vertex = -1;
- for(edge = block->edges; edge; edge = edge->next) {
- if (edge->member) {
- unuse_block(edge->member, block);
- }
- }
- if (block->idom) {
- unidom_block(block->idom, block);
- }
- block->idom = 0;
- if (block->ipdom) {
- unipdom_block(block->ipdom, block);
- }
- block->ipdom = 0;
- while((entry = block->use)) {
- child = entry->member;
- unuse_block(block, child);
- if (child && (child->vertex != -1)) {
- for(edge = child->edges; edge; edge = edge->next) {
- edge->member = 0;
- }
- }
- }
- while((entry = block->idominates)) {
- child = entry->member;
- unidom_block(block, child);
- if (child && (child->vertex != -1)) {
- child->idom = 0;
- }
- }
- while((entry = block->domfrontier)) {
- child = entry->member;
- undomf_block(block, child);
- }
- while((entry = block->ipdominates)) {
- child = entry->member;
- unipdom_block(block, child);
- if (child && (child->vertex != -1)) {
- child->ipdom = 0;
- }
- }
- while((entry = block->ipdomfrontier)) {
- child = entry->member;
- unipdomf_block(block, child);
- }
- if (block->users != 0) {
- internal_error(state, 0, "block still has users");
- }
- while((edge = block->edges)) {
- child = edge->member;
- remove_block_edge(block, child);
-
- if (child && (child->vertex != -1)) {
- free_basic_block(state, child);
- }
- }
- memset(block, -1, sizeof(*block));
- xfree(block);
-}
-
-static void free_basic_blocks(struct compile_state *state)
-{
- struct triple *first, *ins;
- free_basic_block(state, state->first_block);
- state->last_vertex = 0;
- state->first_block = state->last_block = 0;
- first = state->first;
- ins = first;
- do {
- if (triple_stores_block(state, ins)) {
- ins->u.block = 0;
- }
- ins = ins->next;
- } while(ins != first);
-
-}
struct sdom_block {
struct block *block;
@@ -11076,29 +15474,33 @@ static int initialize_spdblock(
return vertex;
}
-static int setup_spdblocks(struct compile_state *state, struct sdom_block *sd)
+static int setup_spdblocks(struct compile_state *state,
+ struct basic_blocks *bb, struct sdom_block *sd)
{
struct block *block;
int vertex;
/* Setup as many sdpblocks as possible without using fake edges */
- vertex = initialize_spdblock(state, sd, 0, state->last_block, 0);
+ vertex = initialize_spdblock(state, sd, 0, bb->last_block, 0);
/* Walk through the graph and find unconnected blocks. Add a
* fake edge from the unconnected blocks to the end of the
* graph.
*/
- block = state->first_block->last->next->u.block;
- for(; block && block != state->first_block; block = block->last->next->u.block) {
+ block = bb->first_block->last->next->u.block;
+ for(; block && block != bb->first_block; block = block->last->next->u.block) {
if (sd[block->vertex].block == block) {
continue;
}
#if DEBUG_SDP_BLOCKS
- fprintf(stderr, "Adding %d\n", vertex +1);
+ {
+ FILE *fp = state->errout;
+ fprintf(fp, "Adding %d\n", vertex +1);
+ }
#endif
- add_block_edge(block, state->last_block, 0);
- use_block(state->last_block, block);
+ add_block_edge(block, bb->last_block, 0);
+ use_block(bb->last_block, block);
- vertex = initialize_spdblock(state, sd, state->last_block, block, vertex);
+ vertex = initialize_spdblock(state, sd, bb->last_block, block, vertex);
}
return vertex;
}
@@ -11126,7 +15528,8 @@ static void compress_ancestors(struct sdom_block *v)
}
}
-static void compute_sdom(struct compile_state *state, struct sdom_block *sd)
+static void compute_sdom(struct compile_state *state,
+ struct basic_blocks *bb, struct sdom_block *sd)
{
int i;
/* // step 2
@@ -11146,7 +15549,7 @@ static void compute_sdom(struct compile_state *state, struct sdom_block *sd)
* dom(v) = (semi[u] < semi[v]) ? u : parent(w);
* }
*/
- for(i = state->last_vertex; i >= 2; i--) {
+ for(i = bb->last_vertex; i >= 2; i--) {
struct sdom_block *v, *parent, *next;
struct block_set *user;
struct block *block;
@@ -11175,7 +15578,8 @@ static void compute_sdom(struct compile_state *state, struct sdom_block *sd)
}
}
-static void compute_spdom(struct compile_state *state, struct sdom_block *sd)
+static void compute_spdom(struct compile_state *state,
+ struct basic_blocks *bb, struct sdom_block *sd)
{
int i;
/* // step 2
@@ -11195,7 +15599,7 @@ static void compute_spdom(struct compile_state *state, struct sdom_block *sd)
* dom(v) = (semi[u] < semi[v]) ? u : parent(w);
* }
*/
- for(i = state->last_vertex; i >= 2; i--) {
+ for(i = bb->last_vertex; i >= 2; i--) {
struct sdom_block *u, *v, *parent, *next;
struct block_set *edge;
struct block *block;
@@ -11223,10 +15627,11 @@ static void compute_spdom(struct compile_state *state, struct sdom_block *sd)
}
}
-static void compute_idom(struct compile_state *state, struct sdom_block *sd)
+static void compute_idom(struct compile_state *state,
+ struct basic_blocks *bb, struct sdom_block *sd)
{
int i;
- for(i = 2; i <= state->last_vertex; i++) {
+ for(i = 2; i <= bb->last_vertex; i++) {
struct block *block;
block = sd[i].block;
if (block->idom->vertex != sd[i].sdom->vertex) {
@@ -11237,10 +15642,11 @@ static void compute_idom(struct compile_state *state, struct sdom_block *sd)
sd[1].block->idom = 0;
}
-static void compute_ipdom(struct compile_state *state, struct sdom_block *sd)
+static void compute_ipdom(struct compile_state *state,
+ struct basic_blocks *bb, struct sdom_block *sd)
{
int i;
- for(i = 2; i <= state->last_vertex; i++) {
+ for(i = 2; i <= bb->last_vertex; i++) {
struct block *block;
block = sd[i].block;
if (block->ipdom->vertex != sd[i].sdom->vertex) {
@@ -11280,7 +15686,8 @@ static void compute_ipdom(struct compile_state *state, struct sdom_block *sd)
* Then v -> idom(w) or idom(w) -> idom(v)
*/
-static void find_immediate_dominators(struct compile_state *state)
+static void find_immediate_dominators(struct compile_state *state,
+ struct basic_blocks *bb)
{
struct sdom_block *sd;
/* w->sdom = min{v| there is a path v = v0,v1,...,vk = w such that:
@@ -11314,8 +15721,8 @@ static void find_immediate_dominators(struct compile_state *state)
* by number.
*/
/* Step 1 initialize the basic block information */
- sd = xcmalloc(sizeof(*sd) * (state->last_vertex + 1), "sdom_state");
- initialize_sdblock(sd, 0, state->first_block, 0);
+ sd = xcmalloc(sizeof(*sd) * (bb->last_vertex + 1), "sdom_state");
+ initialize_sdblock(sd, 0, bb->first_block, 0);
#if 0
sd[1].size = 0;
sd[1].label = 0;
@@ -11323,30 +15730,31 @@ static void find_immediate_dominators(struct compile_state *state)
#endif
/* Step 2 compute the semidominators */
/* Step 3 implicitly define the immediate dominator of each vertex */
- compute_sdom(state, sd);
+ compute_sdom(state, bb, sd);
/* Step 4 explicitly define the immediate dominator of each vertex */
- compute_idom(state, sd);
+ compute_idom(state, bb, sd);
xfree(sd);
}
-static void find_post_dominators(struct compile_state *state)
+static void find_post_dominators(struct compile_state *state,
+ struct basic_blocks *bb)
{
struct sdom_block *sd;
int vertex;
/* Step 1 initialize the basic block information */
- sd = xcmalloc(sizeof(*sd) * (state->last_vertex + 1), "sdom_state");
+ sd = xcmalloc(sizeof(*sd) * (bb->last_vertex + 1), "sdom_state");
- vertex = setup_spdblocks(state, sd);
- if (vertex != state->last_vertex) {
- internal_error(state, 0, "missing %d blocks\n",
- state->last_vertex - vertex);
+ vertex = setup_spdblocks(state, bb, sd);
+ if (vertex != bb->last_vertex) {
+ internal_error(state, 0, "missing %d blocks",
+ bb->last_vertex - vertex);
}
/* Step 2 compute the semidominators */
/* Step 3 implicitly define the immediate dominator of each vertex */
- compute_spdom(state, sd);
+ compute_spdom(state, bb, sd);
/* Step 4 explicitly define the immediate dominator of each vertex */
- compute_ipdom(state, sd);
+ compute_ipdom(state, bb, sd);
xfree(sd);
}
@@ -11467,12 +15875,12 @@ static void print_dominated2(
}
}
-static void print_dominators(struct compile_state *state, FILE *fp)
+static void print_dominators(struct compile_state *state, FILE *fp, struct basic_blocks *bb)
{
fprintf(fp, "\ndominates\n");
- walk_blocks(state, print_dominated, fp);
+ walk_blocks(state, bb, print_dominated, fp);
fprintf(fp, "dominates\n");
- print_dominated2(state, fp, 0, state->first_block);
+ print_dominated2(state, fp, 0, bb->first_block);
}
@@ -11497,29 +15905,29 @@ static int print_frontiers(
}
return vertex;
}
-static void print_dominance_frontiers(struct compile_state *state)
+static void print_dominance_frontiers(struct compile_state *state,
+ struct basic_blocks *bb)
{
printf("\ndominance frontiers\n");
- print_frontiers(state, state->first_block, 0);
+ print_frontiers(state, bb->first_block, 0);
}
-static void analyze_idominators(struct compile_state *state)
+static void analyze_idominators(struct compile_state *state, struct basic_blocks *bb)
{
/* Find the immediate dominators */
- find_immediate_dominators(state);
+ find_immediate_dominators(state, bb);
/* Find the dominance frontiers */
- find_block_domf(state, state->first_block);
+ find_block_domf(state, bb->first_block);
/* If debuging print the print what I have just found */
if (state->compiler->debug & DEBUG_FDOMINATORS) {
- print_dominators(state, stdout);
- print_dominance_frontiers(state);
- print_control_flow(state);
+ print_dominators(state, state->dbgout, bb);
+ print_dominance_frontiers(state, bb);
+ print_control_flow(state, bb);
}
}
-
static void print_ipdominated(
struct compile_state *state, struct block *block, void *arg)
{
@@ -11536,10 +15944,11 @@ static void print_ipdominated(
fprintf(fp, "\n");
}
-static void print_ipdominators(struct compile_state *state, FILE *fp)
+static void print_ipdominators(struct compile_state *state, FILE *fp,
+ struct basic_blocks *bb)
{
fprintf(fp, "\nipdominates\n");
- walk_blocks(state, print_ipdominated, fp);
+ walk_blocks(state, bb, print_ipdominated, fp);
}
static int print_pfrontiers(
@@ -11562,24 +15971,26 @@ static int print_pfrontiers(
}
return vertex;
}
-static void print_ipdominance_frontiers(struct compile_state *state)
+static void print_ipdominance_frontiers(struct compile_state *state,
+ struct basic_blocks *bb)
{
printf("\nipdominance frontiers\n");
- print_pfrontiers(state, state->last_block, 0);
+ print_pfrontiers(state, bb->last_block, 0);
}
-static void analyze_ipdominators(struct compile_state *state)
+static void analyze_ipdominators(struct compile_state *state,
+ struct basic_blocks *bb)
{
/* Find the post dominators */
- find_post_dominators(state);
+ find_post_dominators(state, bb);
/* Find the control dependencies (post dominance frontiers) */
- find_block_ipdomf(state, state->last_block);
+ find_block_ipdomf(state, bb->last_block);
/* If debuging print the print what I have just found */
if (state->compiler->debug & DEBUG_RDOMINATORS) {
- print_ipdominators(state, stdout);
- print_ipdominance_frontiers(state);
- print_control_flow(state);
+ print_ipdominators(state, state->dbgout, bb);
+ print_ipdominance_frontiers(state, bb);
+ print_control_flow(state, bb);
}
}
@@ -11613,11 +16024,12 @@ static int tdominates(struct compile_state *state,
return result;
}
-static void analyze_basic_blocks(struct compile_state *state)
+static void analyze_basic_blocks(
+ struct compile_state *state, struct basic_blocks *bb)
{
- setup_basic_blocks(state);
- analyze_idominators(state);
- analyze_ipdominators(state);
+ setup_basic_blocks(state, bb);
+ analyze_idominators(state, bb);
+ analyze_ipdominators(state, bb);
}
static void insert_phi_operations(struct compile_state *state)
@@ -11629,7 +16041,7 @@ static void insert_phi_operations(struct compile_state *state)
int iter;
struct triple *var, *vnext;
- size = sizeof(int) * (state->last_vertex + 1);
+ size = sizeof(int) * (state->bb.last_vertex + 1);
has_already = xcmalloc(size, "has_already");
work = xcmalloc(size, "work");
iter = 0;
@@ -11639,14 +16051,19 @@ static void insert_phi_operations(struct compile_state *state)
struct block *block;
struct triple_set *user, *unext;
vnext = var->next;
- if ((var->op != OP_ADECL) || !var->use) {
+
+ if (!triple_is_auto_var(state, var) || !var->use) {
continue;
}
+
iter += 1;
work_list = 0;
work_list_tail = &work_list;
for(user = var->use; user; user = unext) {
unext = user->next;
+ if (MISC(var, 0) == user->member) {
+ continue;
+ }
if (user->member->op == OP_READ) {
continue;
}
@@ -11689,6 +16106,12 @@ static void insert_phi_operations(struct compile_state *state)
phi->u.block = front;
MISC(phi, 0) = var;
use_triple(var, phi);
+#if 1
+ if (phi->rhs != in_edges) {
+ internal_error(state, phi, "phi->rhs: %d != in_edges: %d",
+ phi->rhs, in_edges);
+ }
+#endif
/* Insert the phi functions immediately after the label */
insert_triple(state, front->first->next, phi);
if (front->first == front->last) {
@@ -11718,44 +16141,44 @@ struct stack {
unsigned orig_id;
};
-static int count_adecls(struct compile_state *state)
+static int count_auto_vars(struct compile_state *state)
{
struct triple *first, *ins;
- int adecls = 0;
+ int auto_vars = 0;
first = state->first;
ins = first;
do {
- if (ins->op == OP_ADECL) {
- adecls += 1;
+ if (triple_is_auto_var(state, ins)) {
+ auto_vars += 1;
}
ins = ins->next;
} while(ins != first);
- return adecls;
+ return auto_vars;
}
-static void number_adecls(struct compile_state *state, struct stack *stacks)
+static void number_auto_vars(struct compile_state *state, struct stack *stacks)
{
struct triple *first, *ins;
- int adecls = 0;
+ int auto_vars = 0;
first = state->first;
ins = first;
do {
- if (ins->op == OP_ADECL) {
- adecls += 1;
- stacks[adecls].orig_id = ins->id;
- ins->id = adecls;
+ if (triple_is_auto_var(state, ins)) {
+ auto_vars += 1;
+ stacks[auto_vars].orig_id = ins->id;
+ ins->id = auto_vars;
}
ins = ins->next;
} while(ins != first);
}
-static void restore_adecls(struct compile_state *state, struct stack *stacks)
+static void restore_auto_vars(struct compile_state *state, struct stack *stacks)
{
struct triple *first, *ins;
first = state->first;
ins = first;
do {
- if (ins->op == OP_ADECL) {
+ if (triple_is_auto_var(state, ins)) {
ins->id = stacks[ins->id].orig_id;
}
ins = ins->next;
@@ -11838,7 +16261,7 @@ static void fixup_block_phi_variables(
if (val && ((val->op == OP_WRITE) || (val->op == OP_READ))) {
internal_error(state, val, "bad value in phi");
}
- if (edge >= TRIPLE_RHS(ptr->sizes)) {
+ if (edge >= ptr->rhs) {
internal_error(state, ptr, "edges > phi rhs");
}
slot = &RHS(ptr, edge);
@@ -11874,10 +16297,26 @@ static void rename_block_variables(
if (ptr->op == OP_READ) {
struct triple *var, *val;
var = RHS(ptr, 0);
+ if (!triple_is_auto_var(state, var)) {
+ internal_error(state, ptr, "read of non auto var!");
+ }
unuse_triple(var, ptr);
/* Find the current value of the variable */
val = peek_triple(stacks, var);
if (!val) {
+ /* Let the optimizer at variables that are not initially
+ * set. But give it a bogus value so things seem to
+ * work by accident. This is useful for bitfields because
+ * setting them always involves a read-modify-write.
+ */
+ if (TYPE_ARITHMETIC(ptr->type->type)) {
+ val = pre_triple(state, ptr, OP_INTCONST, ptr->type, 0, 0);
+ val->u.cval = 0xdeadbeaf;
+ } else {
+ val = pre_triple(state, ptr, OP_UNKNOWNVAL, ptr->type, 0, 0);
+ }
+ }
+ if (!val) {
error(state, ptr, "variable used without being set");
}
if ((val->op == OP_WRITE) || (val->op == OP_READ)) {
@@ -11890,24 +16329,28 @@ static void rename_block_variables(
/* LHS(A) */
if (ptr->op == OP_WRITE) {
struct triple *var, *val, *tval;
- var = RHS(ptr, 0);
- tval = val = RHS(ptr, 1);
- if ((val->op == OP_WRITE) || (val->op == OP_READ)) {
+ var = MISC(ptr, 0);
+ if (!triple_is_auto_var(state, var)) {
+ internal_error(state, ptr, "write to non auto var!");
+ }
+ tval = val = RHS(ptr, 0);
+ if ((val->op == OP_WRITE) || (val->op == OP_READ) ||
+ triple_is_auto_var(state, val)) {
internal_error(state, ptr, "bad value in write");
}
- /* Insert a copy if the types differ */
- if (!equiv_types(ptr->type, val->type)) {
+ /* Insert a cast if the types differ */
+ if (!is_subset_type(ptr->type, val->type)) {
if (val->op == OP_INTCONST) {
tval = pre_triple(state, ptr, OP_INTCONST, ptr->type, 0, 0);
tval->u.cval = val->u.cval;
}
else {
- tval = pre_triple(state, ptr, OP_COPY, ptr->type, val, 0);
+ tval = pre_triple(state, ptr, OP_CONVERT, ptr->type, val, 0);
use_triple(val, tval);
}
transform_to_arch_instruction(state, tval);
unuse_triple(val, ptr);
- RHS(ptr, 1) = tval;
+ RHS(ptr, 0) = tval;
use_triple(tval, ptr);
}
propogate_use(state, ptr, tval);
@@ -11918,6 +16361,9 @@ static void rename_block_variables(
if (ptr->op == OP_PHI) {
struct triple *var;
var = MISC(ptr, 0);
+ if (!triple_is_auto_var(state, var)) {
+ internal_error(state, ptr, "phi references non auto var!");
+ }
/* Push OP_PHI onto a stack of variable uses */
push_triple(stacks, var, ptr);
}
@@ -11943,9 +16389,9 @@ static void rename_block_variables(
}
if (ptr->op == OP_WRITE) {
struct triple *var;
- var = RHS(ptr, 0);
+ var = MISC(ptr, 0);
/* Pop OP_WRITE ptr->right from the stack of variable uses */
- pop_triple(stacks, var, RHS(ptr, 1));
+ pop_triple(stacks, var, RHS(ptr, 0));
release_triple(state, ptr);
continue;
}
@@ -11963,20 +16409,20 @@ static void rename_block_variables(
static void rename_variables(struct compile_state *state)
{
struct stack *stacks;
- int adecls;
+ int auto_vars;
/* Allocate stacks for the Variables */
- adecls = count_adecls(state);
- stacks = xcmalloc(sizeof(stacks[0])*(adecls + 1), "adecl stacks");
+ auto_vars = count_auto_vars(state);
+ stacks = xcmalloc(sizeof(stacks[0])*(auto_vars + 1), "auto var stacks");
- /* Give each adecl a stack */
- number_adecls(state, stacks);
+ /* Give each auto_var a stack */
+ number_auto_vars(state, stacks);
/* Rename the variables */
- rename_block_variables(state, stacks, state->first_block);
+ rename_block_variables(state, stacks, state->bb.first_block);
- /* Remove the stacks from the adecls */
- restore_adecls(state, stacks);
+ /* Remove the stacks from the auto_vars */
+ restore_auto_vars(state, stacks);
xfree(stacks);
}
@@ -11984,21 +16430,27 @@ static void prune_block_variables(struct compile_state *state,
struct block *block)
{
struct block_set *user;
- struct triple *next, *last, *ptr;
+ struct triple *next, *ptr;
int done;
- last = block->first;
+
done = 0;
for(ptr = block->first; !done; ptr = next) {
+ /* Be extremely careful I am deleting the list
+ * as I walk trhough it.
+ */
next = ptr->next;
if (ptr == block->last) {
done = 1;
}
- if (ptr->op == OP_ADECL) {
+ if (triple_is_auto_var(state, ptr)) {
struct triple_set *user, *next;
for(user = ptr->use; user; user = next) {
struct triple *use;
next = user->next;
use = user->member;
+ if (MISC(ptr, 0) == user->member) {
+ continue;
+ }
if (use->op != OP_PHI) {
internal_error(state, use, "decl still used");
}
@@ -12008,12 +16460,15 @@ static void prune_block_variables(struct compile_state *state,
unuse_triple(ptr, use);
MISC(use, 0) = 0;
}
- release_triple(state, ptr);
+ if ((ptr->u.cval == 0) && (MISC(ptr, 0)->lhs == 1)) {
+ /* Delete the adecl */
+ release_triple(state, MISC(ptr, 0));
+ /* And the piece */
+ release_triple(state, ptr);
+ }
continue;
}
- last = ptr;
}
- block->last = last;
for(user = block->idominates; user; user = user->next) {
prune_block_variables(state, user->member);
}
@@ -12033,7 +16488,7 @@ static void keep_phi(struct compile_state *state, struct phi_triple *live, struc
return;
}
live[phi->id].alive = 1;
- zrhs = TRIPLE_RHS(phi->sizes);
+ zrhs = phi->rhs;
slot = &RHS(phi, 0);
for(i = 0; i < zrhs; i++) {
struct triple *used;
@@ -12096,10 +16551,20 @@ static void prune_unused_phis(struct compile_state *state)
}
phi = live[i].phi;
slot = &RHS(phi, 0);
- zrhs = TRIPLE_RHS(phi->sizes);
+ zrhs = phi->rhs;
for(j = 0; j < zrhs; j++) {
if(!slot[j]) {
- error(state, phi, "variable not set on all paths to use");
+ struct triple *unknown;
+ get_occurance(phi->occurance);
+ unknown = flatten(state, state->global_pool,
+ alloc_triple(state, OP_UNKNOWNVAL,
+ phi->type, 0, 0, phi->occurance));
+ slot[j] = unknown;
+ use_triple(unknown, phi);
+ transform_to_arch_instruction(state, unknown);
+#if 0
+ warning(state, phi, "variable not set at index %d on all paths to use", j);
+#endif
}
}
}
@@ -12111,10 +16576,10 @@ static void transform_to_ssa_form(struct compile_state *state)
insert_phi_operations(state);
rename_variables(state);
- prune_block_variables(state, state->first_block);
+ prune_block_variables(state, state->bb.first_block);
prune_unused_phis(state);
- print_blocks(state, __func__, stdout);
+ print_blocks(state, __func__, state->dbgout);
}
@@ -12146,8 +16611,8 @@ static void mark_live_block(
*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)) {
+ targ = triple_edge_targ(state, block->last, 0);
+ for(; targ; targ = triple_edge_targ(state, block->last, targ)) {
if (!*targ) {
continue;
}
@@ -12156,6 +16621,10 @@ static void mark_live_block(
}
mark_live_block(state, (*targ)->u.block, next_vertex);
}
+ /* Ensure the last block of a function remains alive */
+ if (triple_is_call(state, block->last)) {
+ mark_live_block(state, MISC(block->last, 0)->u.block, next_vertex);
+ }
}
else if (block->last->next != state->first) {
struct triple *ins;
@@ -12177,9 +16646,9 @@ static void transform_from_ssa_form(struct compile_state *state)
int next_vertex;
/* Walk the control flow to see which blocks remain alive */
- walk_blocks(state, clear_vertex, 0);
+ walk_blocks(state, &state->bb, clear_vertex, 0);
next_vertex = 1;
- mark_live_block(state, state->first_block, &next_vertex);
+ mark_live_block(state, state->bb.first_block, &next_vertex);
/* Walk all of the operations to find the phi functions */
first = state->first;
@@ -12189,7 +16658,7 @@ static void transform_from_ssa_form(struct compile_state *state)
struct triple **slot;
struct triple *var;
struct triple_set *use, *use_next;
- int edge, used;
+ int edge, writers, readers;
next = phi->next;
if (phi->op != OP_PHI) {
continue;
@@ -12222,14 +16691,26 @@ static void transform_from_ssa_form(struct compile_state *state)
unuse_triple(phi, use->member);
}
/* A variable to replace the phi function */
- var = post_triple(state, phi, OP_ADECL, phi->type, 0,0);
-
+ if (registers_of(state, phi->type) != 1) {
+ internal_error(state, phi, "phi->type does not fit in a single register!");
+ }
+ var = post_triple(state, phi, OP_ADECL, phi->type, 0, 0);
+ var = var->next; /* point at the var */
+
/* Replaces use of phi with var */
propogate_use(state, phi, var);
+ /* Count the readers */
+ readers = 0;
+ for(use = var->use; use; use = use->next) {
+ if (use->member != MISC(var, 0)) {
+ readers++;
+ }
+ }
+
/* Walk all of the incoming edges/blocks and insert moves.
*/
- used = 0;
+ writers = 0;
for(edge = 0, set = block->use; set; set = set->next, edge++) {
struct block *eblock, *vblock;
struct triple *move;
@@ -12243,8 +16724,13 @@ static void transform_from_ssa_form(struct compile_state *state)
/* If we don't have a value that belongs in an OP_WRITE
* continue on.
*/
- if (!val || (val == &zero_triple) || (val == phi) ||
- (!vblock) || (vblock->vertex == 0)) {
+ if (!val || (val == &unknown_triple) || (val == phi)
+ || (vblock && (vblock->vertex == 0))) {
+ continue;
+ }
+ /* If the value should never occur error */
+ if (!vblock) {
+ internal_error(state, val, "no vblock?");
continue;
}
@@ -12265,20 +16751,48 @@ static void transform_from_ssa_form(struct compile_state *state)
}
/* Make certain the write is placed in the edge block... */
- base = eblock->first;
- if (block_of_triple(state, val) == eblock) {
- base = val;
+ /* Walk through the edge block backwards to find an
+ * appropriate location for the OP_WRITE.
+ */
+ for(base = eblock->last; base != eblock->first; base = base->prev) {
+ struct triple **expr;
+ if (base->op == OP_PIECE) {
+ base = MISC(base, 0);
+ }
+ if ((base == var) || (base == val)) {
+ goto out;
+ }
+ expr = triple_lhs(state, base, 0);
+ for(; expr; expr = triple_lhs(state, base, expr)) {
+ if ((*expr) == val) {
+ goto out;
+ }
+ }
+ expr = triple_rhs(state, base, 0);
+ for(; expr; expr = triple_rhs(state, base, expr)) {
+ if ((*expr) == var) {
+ goto out;
+ }
+ }
+ }
+ out:
+ if (triple_is_branch(state, base)) {
+ internal_error(state, base,
+ "Could not insert write to phi");
}
- move = post_triple(state, base, OP_WRITE, var->type, var, val);
+ move = post_triple(state, base, OP_WRITE, var->type, val, var);
use_triple(val, move);
use_triple(var, move);
- used = 1;
- }
+ writers++;
+ }
+ if (!writers && readers) {
+ internal_error(state, var, "no value written to in use phi?");
+ }
/* If var is not used free it */
- if (!used) {
- free_triple(state, var);
+ if (!writers) {
+ release_triple(state, MISC(var, 0));
+ release_triple(state, var);
}
-
/* Release the phi function */
release_triple(state, phi);
}
@@ -12286,7 +16800,7 @@ static void transform_from_ssa_form(struct compile_state *state)
/* Walk all of the operations to find the adecls */
for(var = first->next; var != first ; var = var->next) {
struct triple_set *use, *use_next;
- if (var->op != OP_ADECL) {
+ if (!triple_is_auto_var(state, var)) {
continue;
}
@@ -12306,12 +16820,10 @@ static void transform_from_ssa_form(struct compile_state *state)
/* Find the rhs uses and see if they need to be replaced */
used = 0;
- zrhs = TRIPLE_RHS(user->sizes);
+ zrhs = user->rhs;
slot = &RHS(user, 0);
for(i = 0; i < zrhs; i++) {
- if ((slot[i] == var) &&
- ((i != 0) || (user->op != OP_WRITE)))
- {
+ if (slot[i] == var) {
slot[i] = read;
used = 1;
}
@@ -12330,7 +16842,8 @@ static void transform_from_ssa_form(struct compile_state *state)
}
#define HI() if (state->compiler->debug & DEBUG_REBUILD_SSA_FORM) { \
- fprintf(stderr, "@ %s:%d\n", __FILE__, __LINE__); romcc_print_blocks(state, stderr); \
+ FILE *fp = state->dbgout; \
+ fprintf(fp, "@ %s:%d\n", __FILE__, __LINE__); romcc_print_blocks(state, fp); \
}
static void rebuild_ssa_form(struct compile_state *state)
@@ -12338,15 +16851,16 @@ static void rebuild_ssa_form(struct compile_state *state)
HI();
transform_from_ssa_form(state);
HI();
- free_basic_blocks(state);
- analyze_basic_blocks(state);
+ state->bb.first = state->first;
+ free_basic_blocks(state, &state->bb);
+ analyze_basic_blocks(state, &state->bb);
HI();
insert_phi_operations(state);
HI();
rename_variables(state);
HI();
- prune_block_variables(state, state->first_block);
+ prune_block_variables(state, state->bb.first_block);
HI();
prune_unused_phis(state);
HI();
@@ -12408,8 +16922,8 @@ static struct reg_info find_lhs_pre_color(
{
struct reg_info info;
int zlhs, zrhs, i;
- zrhs = TRIPLE_RHS(ins->sizes);
- zlhs = TRIPLE_LHS(ins->sizes);
+ zrhs = ins->rhs;
+ zlhs = ins->lhs;
if (!zlhs && triple_is_def(state, ins)) {
zlhs = 1;
}
@@ -12445,13 +16959,13 @@ static struct reg_info find_lhs_post_color(
struct reg_info info;
struct triple *lhs;
#if DEBUG_TRIPLE_COLOR
- fprintf(stderr, "find_lhs_post_color(%p, %d)\n",
+ fprintf(state->errout, "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)) {
+ else if (index < ins->lhs) {
lhs = LHS(ins, index);
}
else {
@@ -12467,7 +16981,7 @@ static struct reg_info find_lhs_post_color(
struct triple *user;
int zrhs, i;
user = set->member;
- zrhs = TRIPLE_RHS(user->sizes);
+ zrhs = user->rhs;
for(i = 0; i < zrhs; i++) {
if (RHS(user, i) != lhs) {
continue;
@@ -12489,7 +17003,7 @@ static struct reg_info find_lhs_post_color(
}
}
#if DEBUG_TRIPLE_COLOR
- fprintf(stderr, "find_lhs_post_color(%p, %d) -> ( %d, %x)\n",
+ fprintf(state->errout, "find_lhs_post_color(%p, %d) -> ( %d, %x)\n",
ins, index, info.reg, info.regcm);
#endif
return info;
@@ -12501,11 +17015,11 @@ static struct reg_info find_rhs_post_color(
struct reg_info info, rinfo;
int zlhs, i;
#if DEBUG_TRIPLE_COLOR
- fprintf(stderr, "find_rhs_post_color(%p, %d)\n",
+ fprintf(state->errout, "find_rhs_post_color(%p, %d)\n",
ins, index);
#endif
rinfo = arch_reg_rhs(state, ins, index);
- zlhs = TRIPLE_LHS(ins->sizes);
+ zlhs = ins->lhs;
if (!zlhs && triple_is_def(state, ins)) {
zlhs = 1;
}
@@ -12535,7 +17049,7 @@ static struct reg_info find_rhs_post_color(
}
}
#if DEBUG_TRIPLE_COLOR
- fprintf(stderr, "find_rhs_post_color(%p, %d) -> ( %d, %x)\n",
+ fprintf(state->errout, "find_rhs_post_color(%p, %d) -> ( %d, %x)\n",
ins, index, info.reg, info.regcm);
#endif
return info;
@@ -12546,7 +17060,7 @@ static struct reg_info find_lhs_color(
{
struct reg_info pre, post, info;
#if DEBUG_TRIPLE_COLOR
- fprintf(stderr, "find_lhs_color(%p, %d)\n",
+ fprintf(state->errout, "find_lhs_color(%p, %d)\n",
ins, index);
#endif
pre = find_lhs_pre_color(state, ins, index);
@@ -12562,7 +17076,7 @@ static struct reg_info find_lhs_color(
info.reg = post.reg;
}
#if DEBUG_TRIPLE_COLOR
- fprintf(stderr, "find_lhs_color(%p, %d) -> ( %d, %x) ... (%d, %x) (%d, %x)\n",
+ fprintf(state->errout, "find_lhs_color(%p, %d) -> ( %d, %x) ... (%d, %x) (%d, %x)\n",
ins, index, info.reg, info.regcm,
pre.reg, pre.regcm, post.reg, post.regcm);
#endif
@@ -12609,6 +17123,7 @@ static struct triple *typed_pre_copy(
struct triple **expr;
unsigned classes;
struct reg_info info;
+ int op;
if (ins->op == OP_PHI) {
internal_error(state, ins, "pre_copy on a phi?");
}
@@ -12616,9 +17131,19 @@ static struct triple *typed_pre_copy(
info = arch_reg_rhs(state, ins, index);
expr = &RHS(ins, index);
if ((info.regcm & classes) == 0) {
+ FILE *fp = state->errout;
+ fprintf(fp, "src_type: ");
+ name_of(fp, ins->type);
+ fprintf(fp, "\ndst_type: ");
+ name_of(fp, type);
+ fprintf(fp, "\n");
internal_error(state, ins, "pre_copy with no register classes");
}
- in = pre_triple(state, ins, OP_COPY, type, *expr, 0);
+ op = OP_COPY;
+ if (!equiv_types(type, (*expr)->type)) {
+ op = OP_CONVERT;
+ }
+ in = pre_triple(state, ins, op, type, *expr, 0);
unuse_triple(*expr, ins);
*expr = in;
use_triple(RHS(in, 0), in);
@@ -12677,7 +17202,7 @@ static void insert_copies_to_phi(struct compile_state *state)
}
get_occurance(val->occurance);
- move = build_triple(state, OP_COPY, phi->type, val, 0,
+ move = build_triple(state, OP_COPY, val->type, val, 0,
val->occurance);
move->u.block = eblock;
move->id |= TRIPLE_FLAG_PRE_SPLIT;
@@ -12701,9 +17226,18 @@ static void insert_copies_to_phi(struct compile_state *state)
*/
for(ptr = eblock->last; ptr != eblock->first; ptr = ptr->prev) {
struct triple **expr;
+ if (ptr->op == OP_PIECE) {
+ ptr = MISC(ptr, 0);
+ }
if ((ptr == phi) || (ptr == val)) {
goto out;
}
+ expr = triple_lhs(state, ptr, 0);
+ for(;expr; expr = triple_lhs(state, ptr, expr)) {
+ if ((*expr) == val) {
+ goto out;
+ }
+ }
expr = triple_rhs(state, ptr, 0);
for(;expr; expr = triple_rhs(state, ptr, expr)) {
if ((*expr) == phi) {
@@ -12716,28 +17250,19 @@ static void insert_copies_to_phi(struct compile_state *state)
internal_error(state, ptr,
"Could not insert write to phi");
}
- insert_triple(state, ptr->next, move);
- if (eblock->last == ptr) {
+ insert_triple(state, after_lhs(state, ptr), move);
+ if (eblock->last == after_lhs(state, ptr)->prev) {
eblock->last = move;
}
transform_to_arch_instruction(state, move);
}
}
- print_blocks(state, __func__, stdout);
+ print_blocks(state, __func__, state->dbgout);
}
-struct triple_reg_set {
- struct triple_reg_set *next;
- struct triple *member;
- struct triple *new;
-};
+struct triple_reg_set;
+struct reg_block;
-struct reg_block {
- struct block *block;
- struct triple_reg_set *in;
- struct triple_reg_set *out;
- int vertex;
-};
static int do_triple_set(struct triple_reg_set **head,
struct triple *member, struct triple *new_member)
@@ -12813,6 +17338,57 @@ static int initialize_regblock(struct reg_block *blocks,
return vertex;
}
+static struct triple *part_to_piece(struct compile_state *state, struct triple *ins)
+{
+/* Part to piece is a best attempt and it cannot be correct all by
+ * itself. If various values are read as different sizes in different
+ * parts of the code this function cannot work. Or rather it cannot
+ * work in conjunction with compute_variable_liftimes. As the
+ * analysis will get confused.
+ */
+ struct triple *base;
+ unsigned reg;
+ if (!is_lvalue(state, ins)) {
+ return ins;
+ }
+ base = 0;
+ reg = 0;
+ while(ins && triple_is_part(state, ins) && (ins->op != OP_PIECE)) {
+ base = MISC(ins, 0);
+ switch(ins->op) {
+ case OP_INDEX:
+ reg += index_reg_offset(state, base->type, ins->u.cval)/REG_SIZEOF_REG;
+ break;
+ case OP_DOT:
+ reg += field_reg_offset(state, base->type, ins->u.field)/REG_SIZEOF_REG;
+ break;
+ default:
+ internal_error(state, ins, "unhandled part");
+ break;
+ }
+ ins = base;
+ }
+ if (base) {
+ if (reg > base->lhs) {
+ internal_error(state, base, "part out of range?");
+ }
+ ins = LHS(base, reg);
+ }
+ return ins;
+}
+
+static int this_def(struct compile_state *state,
+ struct triple *ins, struct triple *other)
+{
+ if (ins == other) {
+ return 1;
+ }
+ if (ins->op == OP_WRITE) {
+ ins = part_to_piece(state, MISC(ins, 0));
+ }
+ return ins == other;
+}
+
static int phi_in(struct compile_state *state, struct reg_block *blocks,
struct reg_block *rb, struct block *suc)
{
@@ -12852,7 +17428,7 @@ static int phi_in(struct compile_state *state, struct reg_block *blocks,
*/
ptr2 = rb->block->first;
for(done2 = 0; !done2; ptr2 = ptr2->next) {
- if (ptr2 == expr) {
+ if (this_def(state, ptr2, expr)) {
break;
}
done2 = (ptr2 == rb->block->last);
@@ -12889,7 +17465,7 @@ static int reg_in(struct compile_state *state, struct reg_block *blocks,
last = rb->block->last;
done = 0;
for(ptr = first; !done; ptr = ptr->next) {
- if (ptr == in_set->member) {
+ if (this_def(state, ptr, in_set->member)) {
break;
}
done = (ptr == last);
@@ -12903,7 +17479,6 @@ static int reg_in(struct compile_state *state, struct reg_block *blocks,
return change;
}
-
static int use_in(struct compile_state *state, struct reg_block *rb)
{
/* Find the variables we use but don't define and add
@@ -12930,14 +17505,17 @@ static int use_in(struct compile_state *state, struct reg_block *rb)
for(;expr; expr = triple_rhs(state, ptr, expr)) {
struct triple *rhs, *test;
int tdone;
- rhs = *expr;
+ rhs = part_to_piece(state, *expr);
if (!rhs) {
continue;
}
- /* See if rhs is defined in this block */
+
+ /* See if rhs is defined in this block.
+ * A write counts as a definition.
+ */
for(tdone = 0, test = ptr; !tdone; test = test->prev) {
tdone = (test == block->first);
- if (test == rhs) {
+ if (this_def(state, test, rhs)) {
rhs = 0;
break;
}
@@ -12950,17 +17528,17 @@ static int use_in(struct compile_state *state, struct reg_block *rb)
}
static struct reg_block *compute_variable_lifetimes(
- struct compile_state *state)
+ struct compile_state *state, struct basic_blocks *bb)
{
struct reg_block *blocks;
int change;
blocks = xcmalloc(
- sizeof(*blocks)*(state->last_vertex + 1), "reg_block");
- initialize_regblock(blocks, state->last_block, 0);
+ sizeof(*blocks)*(bb->last_vertex + 1), "reg_block");
+ initialize_regblock(blocks, bb->last_block, 0);
do {
int i;
change = 0;
- for(i = 1; i <= state->last_vertex; i++) {
+ for(i = 1; i <= bb->last_vertex; i++) {
struct block_set *edge;
struct reg_block *rb;
rb = &blocks[i];
@@ -12975,12 +17553,12 @@ static struct reg_block *compute_variable_lifetimes(
return blocks;
}
-static void free_variable_lifetimes(
- struct compile_state *state, struct reg_block *blocks)
+static void free_variable_lifetimes(struct compile_state *state,
+ struct basic_blocks *bb, struct reg_block *blocks)
{
int i;
/* free in_set && out_set on each block */
- for(i = 1; i <= state->last_vertex; i++) {
+ for(i = 1; i <= bb->last_vertex; i++) {
struct triple_reg_set *entry, *next;
struct reg_block *rb;
rb = &blocks[i];
@@ -13003,11 +17581,12 @@ typedef void (*wvl_cb_t)(
struct reg_block *rb, struct triple *ins, void *arg);
static void walk_variable_lifetimes(struct compile_state *state,
- struct reg_block *blocks, wvl_cb_t cb, void *arg)
+ struct basic_blocks *bb, struct reg_block *blocks,
+ wvl_cb_t cb, void *arg)
{
int i;
- for(i = 1; i <= state->last_vertex; i++) {
+ for(i = 1; i <= state->bb.last_vertex; i++) {
struct triple_reg_set *live;
struct triple_reg_set *entry, *next;
struct triple *ptr, *prev;
@@ -13072,6 +17651,93 @@ static void walk_variable_lifetimes(struct compile_state *state,
}
}
+struct print_live_variable_info {
+ struct reg_block *rb;
+ FILE *fp;
+};
+static void print_live_variables_block(
+ struct compile_state *state, struct block *block, void *arg)
+
+{
+ struct print_live_variable_info *info = arg;
+ struct block_set *edge;
+ FILE *fp = info->fp;
+ struct reg_block *rb;
+ struct triple *ptr;
+ int phi_present;
+ int done;
+ rb = &info->rb[block->vertex];
+
+ fprintf(fp, "\nblock: %p (%d),",
+ block, block->vertex);
+ for(edge = block->edges; edge; edge = edge->next) {
+ fprintf(fp, " %p<-%p",
+ edge->member,
+ edge->member && edge->member->use?edge->member->use->member : 0);
+ }
+ fprintf(fp, "\n");
+ if (rb->in) {
+ struct triple_reg_set *in_set;
+ fprintf(fp, " in:");
+ for(in_set = rb->in; in_set; in_set = in_set->next) {
+ fprintf(fp, " %-10p", in_set->member);
+ }
+ fprintf(fp, "\n");
+ }
+ phi_present = 0;
+ for(done = 0, ptr = block->first; !done; ptr = ptr->next) {
+ done = (ptr == block->last);
+ if (ptr->op == OP_PHI) {
+ phi_present = 1;
+ break;
+ }
+ }
+ if (phi_present) {
+ int edge;
+ for(edge = 0; edge < block->users; edge++) {
+ fprintf(fp, " in(%d):", edge);
+ for(done = 0, ptr = block->first; !done; ptr = ptr->next) {
+ struct triple **slot;
+ done = (ptr == block->last);
+ if (ptr->op != OP_PHI) {
+ continue;
+ }
+ slot = &RHS(ptr, 0);
+ fprintf(fp, " %-10p", slot[edge]);
+ }
+ fprintf(fp, "\n");
+ }
+ }
+ if (block->first->op == OP_LABEL) {
+ fprintf(fp, "%p:\n", block->first);
+ }
+ for(done = 0, ptr = block->first; !done; ptr = ptr->next) {
+ done = (ptr == block->last);
+ display_triple(fp, ptr);
+ }
+ if (rb->out) {
+ struct triple_reg_set *out_set;
+ fprintf(fp, " out:");
+ for(out_set = rb->out; out_set; out_set = out_set->next) {
+ fprintf(fp, " %-10p", out_set->member);
+ }
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "\n");
+}
+
+static void print_live_variables(struct compile_state *state,
+ struct basic_blocks *bb, struct reg_block *rb, FILE *fp)
+{
+ struct print_live_variable_info info;
+ info.rb = rb;
+ info.fp = fp;
+ fprintf(fp, "\nlive variables by block\n");
+ walk_blocks(state, bb, print_live_variables_block, &info);
+
+}
+
+
static int count_triples(struct compile_state *state)
{
struct triple *first, *ins;
@@ -13093,8 +17759,38 @@ struct dead_triple {
int old_id;
int flags;
#define TRIPLE_FLAG_ALIVE 1
+#define TRIPLE_FLAG_FREE 1
};
+static void print_dead_triples(struct compile_state *state,
+ struct dead_triple *dtriple)
+{
+ struct triple *first, *ins;
+ struct dead_triple *dt;
+ FILE *fp;
+ if (!(state->compiler->debug & DEBUG_TRIPLES)) {
+ return;
+ }
+ fp = state->dbgout;
+ fprintf(fp, "--------------- dtriples ---------------\n");
+ first = state->first;
+ ins = first;
+ do {
+ dt = &dtriple[ins->id];
+ if ((ins->op == OP_LABEL) && (ins->use)) {
+ fprintf(fp, "\n%p:\n", ins);
+ }
+ fprintf(fp, "%c",
+ (dt->flags & TRIPLE_FLAG_ALIVE)?' ': '-');
+ display_triple(fp, ins);
+ if (triple_is_branch(state, ins)) {
+ fprintf(fp, "\n");
+ }
+ ins = ins->next;
+ } while(ins != first);
+ fprintf(fp, "\n");
+}
+
static void awaken(
struct compile_state *state,
@@ -13183,6 +17879,8 @@ static void eliminate_inefectual_code(struct compile_state *state)
awaken(state, dtriple, &block->first, &work_list_tail);
if (triple_is_branch(state, block->last)) {
awaken(state, dtriple, &block->last, &work_list_tail);
+ } else {
+ awaken(state, dtriple, &block->last->next, &work_list_tail);
}
/* Wake up the data depencencies of this triple */
@@ -13215,6 +17913,7 @@ static void eliminate_inefectual_code(struct compile_state *state)
awaken(state, dtriple, &last, &work_list_tail);
}
}
+ print_dead_triples(state, dtriple);
for(dt = &dtriple[1]; dt <= &dtriple[triples]; dt++) {
if ((dt->triple->op == OP_NOOP) &&
(dt->flags & TRIPLE_FLAG_ALIVE)) {
@@ -13229,7 +17928,7 @@ static void eliminate_inefectual_code(struct compile_state *state)
rebuild_ssa_form(state);
- print_blocks(state, __func__, stdout);
+ print_blocks(state, __func__, state->dbgout);
}
@@ -13257,11 +17956,11 @@ static void insert_mandatory_copies(struct compile_state *state)
goto next;
}
/* Find the architecture specific color information */
- info = arch_reg_lhs(state, ins, 0);
+ info = find_lhs_pre_color(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;
@@ -13386,7 +18085,7 @@ static void insert_mandatory_copies(struct compile_state *state)
ins = ins->next;
} while(ins != first);
- print_blocks(state, __func__, stdout);
+ print_blocks(state, __func__, state->dbgout);
}
@@ -13441,7 +18140,6 @@ struct reg_state {
};
-
struct print_interference_block_info {
struct reg_state *rstate;
FILE *fp;
@@ -13573,7 +18271,7 @@ static void print_interference_blocks(
info.fp = fp;
info.need_edges = need_edges;
fprintf(fp, "\nlive variables by block\n");
- walk_blocks(state, print_interference_block, &info);
+ walk_blocks(state, &state->bb, print_interference_block, &info);
}
@@ -13720,7 +18418,7 @@ static void add_live_edge(struct reg_state *rstate,
return;
}
#if 0
- fprintf(stderr, "new_live_edge(%p, %p)\n",
+ fprintf(state->errout, "new_live_edge(%p, %p)\n",
left, right);
#endif
new_hash = xmalloc(sizeof(*new_hash), "lre_hash");
@@ -13888,19 +18586,20 @@ static struct live_range *coalesce_ranges(
"cannot coalesce live ranges with dissimilar register classes");
}
if (state->compiler->debug & DEBUG_COALESCING) {
- fprintf(stderr, "coalescing:");
+ FILE *fp = state->errout;
+ fprintf(fp, "coalescing:");
lrd = lr1->defs;
do {
- fprintf(stderr, " %p", lrd->def);
+ fprintf(fp, " %p", lrd->def);
lrd = lrd->next;
} while(lrd != lr1->defs);
- fprintf(stderr, " |");
+ fprintf(fp, " |");
lrd = lr2->defs;
do {
- fprintf(stderr, " %p", lrd->def);
+ fprintf(fp, " %p", lrd->def);
lrd = lrd->next;
} while(lrd != lr2->defs);
- fprintf(stderr, "\n");
+ fprintf(fp, "\n");
}
/* If there is a clear dominate live range put it in lr1,
* For purposes of this test phi functions are
@@ -13917,20 +18616,20 @@ static struct live_range *coalesce_ranges(
}
#if 0
if (lr1->defs->orig_id & TRIPLE_FLAG_POST_SPLIT) {
- fprintf(stderr, "lr1 post\n");
+ fprintf(state->errout, "lr1 post\n");
}
if (lr1->defs->orig_id & TRIPLE_FLAG_PRE_SPLIT) {
- fprintf(stderr, "lr1 pre\n");
+ fprintf(state->errout, "lr1 pre\n");
}
if (lr2->defs->orig_id & TRIPLE_FLAG_POST_SPLIT) {
- fprintf(stderr, "lr2 post\n");
+ fprintf(state->errout, "lr2 post\n");
}
if (lr2->defs->orig_id & TRIPLE_FLAG_PRE_SPLIT) {
- fprintf(stderr, "lr2 pre\n");
+ fprintf(state->errout, "lr2 pre\n");
}
#endif
#if 0
- fprintf(stderr, "coalesce color1(%p): %3d color2(%p) %3d\n",
+ fprintf(state->errout, "coalesce color1(%p): %3d color2(%p) %3d\n",
lr1->defs->def,
lr1->color,
lr2->defs->def,
@@ -14083,14 +18782,14 @@ static void initialize_live_ranges(
}
/* Walk through the template of ins and coalesce live ranges */
- zlhs = TRIPLE_LHS(ins->sizes);
+ zlhs = ins->lhs;
if ((zlhs == 0) && triple_is_def(state, ins)) {
zlhs = 1;
}
- zrhs = TRIPLE_RHS(ins->sizes);
+ zrhs = ins->rhs;
if (state->compiler->debug & DEBUG_COALESCING2) {
- fprintf(stderr, "mandatory coalesce: %p %d %d\n",
+ fprintf(state->errout, "mandatory coalesce: %p %d %d\n",
ins, zlhs, zrhs);
}
@@ -14108,7 +18807,7 @@ static void initialize_live_ranges(
}
if (state->compiler->debug & DEBUG_COALESCING2) {
- fprintf(stderr, "coalesce lhs(%d): %p %d\n",
+ fprintf(state->errout, "coalesce lhs(%d): %p %d\n",
i, lhs, linfo.reg);
}
@@ -14122,7 +18821,7 @@ static void initialize_live_ranges(
rhs = &rstate->lrd[RHS(ins, j)->id];
if (state->compiler->debug & DEBUG_COALESCING2) {
- fprintf(stderr, "coalesce rhs(%d): %p %d\n",
+ fprintf(state->errout, "coalesce rhs(%d): %p %d\n",
j, rhs, rinfo.reg);
}
@@ -14268,7 +18967,7 @@ static void print_interference_ins(
id = ins->id;
ins->id = rstate->lrd[id].orig_id;
SET_REG(ins->id, lr->color);
- display_triple(stdout, ins);
+ display_triple(state->dbgout, ins);
ins->id = id;
if (lr->defs) {
@@ -14426,11 +19125,11 @@ static void fix_coalesce_conflicts(struct compile_state *state,
* we would have two definitions in the same live range simultaneously
* alive.
*/
- zlhs = TRIPLE_LHS(ins->sizes);
+ zlhs = ins->lhs;
if ((zlhs == 0) && triple_is_def(state, ins)) {
zlhs = 1;
}
- zrhs = TRIPLE_RHS(ins->sizes);
+ zrhs = ins->rhs;
for(i = 0; i < zlhs; i++) {
struct reg_info linfo;
linfo = arch_reg_lhs(state, ins, i);
@@ -14469,7 +19168,8 @@ static int correct_coalesce_conflicts(
{
int conflicts;
conflicts = 0;
- walk_variable_lifetimes(state, blocks, fix_coalesce_conflicts, &conflicts);
+ walk_variable_lifetimes(state, &state->bb, blocks,
+ fix_coalesce_conflicts, &conflicts);
return conflicts;
}
@@ -14489,7 +19189,7 @@ static void replace_block_use(struct compile_state *state,
{
int i;
#warning "WISHLIST visit just those blocks that need it *"
- for(i = 1; i <= state->last_vertex; i++) {
+ for(i = 1; i <= state->bb.last_vertex; i++) {
struct reg_block *rb;
rb = &blocks[i];
replace_set_use(state, rb->in, orig, new);
@@ -14523,7 +19223,7 @@ static struct reg_info read_lhs_color(
info.reg = ID_REG(ins->id);
info.regcm = ID_REGCM(ins->id);
}
- else if (index < TRIPLE_LHS(ins->sizes)) {
+ else if (index < ins->lhs) {
info = read_lhs_color(state, LHS(ins, index), 0);
}
else {
@@ -14548,7 +19248,7 @@ static struct triple *resolve_tangle(
int i, zrhs;
next = set->next;
user = set->member;
- zrhs = TRIPLE_RHS(user->sizes);
+ zrhs = user->rhs;
for(i = 0; i < zrhs; i++) {
if (RHS(user, i) != tangle) {
continue;
@@ -14641,7 +19341,8 @@ static int correct_tangles(
int tangles;
tangles = 0;
color_instructions(state);
- walk_variable_lifetimes(state, blocks, fix_tangles, &tangles);
+ walk_variable_lifetimes(state, &state->bb, blocks,
+ fix_tangles, &tangles);
return tangles;
}
@@ -14686,7 +19387,7 @@ struct triple *find_constrained_def(
* least dominated one first.
*/
if (state->compiler->debug & DEBUG_RANGE_CONFLICTS) {
- fprintf(stderr, "canidate: %p %-8s regcm: %x %x\n",
+ fprintf(state->errout, "canidate: %p %-8s regcm: %x %x\n",
lrd->def, tops(lrd->def->op), regcm, info.regcm);
}
if (!constrained ||
@@ -14721,8 +19422,8 @@ static int split_constrained_ranges(
}
if (state->compiler->debug & DEBUG_RANGE_CONFLICTS) {
- fprintf(stderr, "constrained: %p %-8s\n",
- constrained, tops(constrained->op));
+ fprintf(state->errout, "constrained: ");
+ display_triple(state->errout, constrained);
}
if (constrained) {
ids_from_rstate(state, rstate);
@@ -14738,7 +19439,7 @@ static int split_ranges(
{
int split;
if (state->compiler->debug & DEBUG_RANGE_CONFLICTS) {
- fprintf(stderr, "split_ranges %d %s %p\n",
+ fprintf(state->errout, "split_ranges %d %s %p\n",
rstate->passes, tops(range->defs->def->op), range->defs->def);
}
if ((range->color == REG_UNNEEDED) ||
@@ -14762,8 +19463,9 @@ static int split_ranges(
#warning "WISHLIST implement live range splitting..."
if (!split && (state->compiler->debug & DEBUG_RANGE_CONFLICTS2)) {
- print_interference_blocks(state, rstate, stderr, 0);
- print_dominators(state, stderr);
+ FILE *fp = state->errout;
+ print_interference_blocks(state, rstate, fp, 0);
+ print_dominators(state, fp, &state->bb);
}
return split;
}
@@ -14773,10 +19475,10 @@ static FILE *cgdebug_fp(struct compile_state *state)
FILE *fp;
fp = 0;
if (!fp && (state->compiler->debug & DEBUG_COLOR_GRAPH2)) {
- fp = stderr;
+ fp = state->errout;
}
if (!fp && (state->compiler->debug & DEBUG_COLOR_GRAPH)) {
- fp = stdout;
+ fp = state->dbgout;
}
return fp;
}
@@ -15100,7 +19802,9 @@ static int color_graph(struct compile_state *state, struct reg_state *rstate)
cgdebug_loc(state, range->defs->def);
cgdebug_flush(state);
colored = select_free_color(state, rstate, range);
- cgdebug_printf(state, " %s\n", arch_reg_str(range->color));
+ if (colored) {
+ cgdebug_printf(state, " %s\n", arch_reg_str(range->color));
+ }
}
return colored;
}
@@ -15144,6 +19848,7 @@ static void verify_colors(struct compile_state *state, struct reg_state *rstate)
static void color_triples(struct compile_state *state, struct reg_state *rstate)
{
+ struct live_range_def *lrd;
struct live_range *lr;
struct triple *first, *ins;
first = state->first;
@@ -15153,7 +19858,9 @@ static void color_triples(struct compile_state *state, struct reg_state *rstate)
internal_error(state, ins,
"triple without a live range");
}
- lr = rstate->lrd[ins->id].lr;
+ lrd = &rstate->lrd[ins->id];
+ lr = lrd->lr;
+ ins->id = lrd->orig_id;
SET_REG(ins->id, lr->color);
ins = ins->next;
} while (ins != first);
@@ -15220,9 +19927,10 @@ static void ids_from_rstate(struct compile_state *state,
}
/* Display the graph if desired */
if (state->compiler->debug & DEBUG_INTERFERENCE) {
- print_interference_blocks(state, rstate, stdout, 0);
- print_control_flow(state);
- fflush(stdout);
+ FILE *fp = state->dbgout;
+ print_interference_blocks(state, rstate, fp, 0);
+ print_control_flow(state, &state->bb);
+ fflush(fp);
}
first = state->first;
ins = first;
@@ -15253,7 +19961,7 @@ static void cleanup_rstate(struct compile_state *state, struct reg_state *rstate
/* Free the variable lifetime information */
if (rstate->blocks) {
- free_variable_lifetimes(state, rstate->blocks);
+ free_variable_lifetimes(state, &state->bb, rstate->blocks);
}
rstate->defs = 0;
rstate->ranges = 0;
@@ -15279,8 +19987,9 @@ static void allocate_registers(struct compile_state *state)
int coalesced;
if (state->compiler->debug & DEBUG_RANGE_CONFLICTS) {
- fprintf(stderr, "pass: %d\n", rstate.passes);
- fflush(stderr);
+ FILE *fp = state->errout;
+ fprintf(fp, "pass: %d\n", rstate.passes);
+ fflush(fp);
}
/* Restore ids */
@@ -15290,7 +19999,7 @@ static void allocate_registers(struct compile_state *state)
cleanup_rstate(state, &rstate);
/* Compute the variable lifetimes */
- rstate.blocks = compute_variable_lifetimes(state);
+ rstate.blocks = compute_variable_lifetimes(state, &state->bb);
/* Fix invalid mandatory live range coalesce conflicts */
conflicts = correct_coalesce_conflicts(state, rstate.blocks);
@@ -15306,20 +20015,20 @@ static void allocate_registers(struct compile_state *state)
} while(tangles);
- print_blocks(state, "resolve_tangles", stdout);
+ print_blocks(state, "resolve_tangles", state->dbgout);
verify_consistency(state);
/* Allocate and initialize the live ranges */
initialize_live_ranges(state, &rstate);
- /* Note current doing coalescing in a loop appears to
+ /* Note currently doing coalescing in a loop appears to
* buys me nothing. The code is left this way in case
* there is some value in it. Or if a future bugfix
- * yields some benefit.
+ * yields some benefit.
*/
do {
if (state->compiler->debug & DEBUG_COALESCING) {
- fprintf(stderr, "coalescing\n");
+ fprintf(state->errout, "coalescing\n");
}
/* Remove any previous live edge calculations */
@@ -15327,33 +20036,35 @@ static void allocate_registers(struct compile_state *state)
/* Compute the interference graph */
walk_variable_lifetimes(
- state, rstate.blocks, graph_ins, &rstate);
+ state, &state->bb, rstate.blocks,
+ graph_ins, &rstate);
/* Display the interference graph if desired */
if (state->compiler->debug & DEBUG_INTERFERENCE) {
- print_interference_blocks(state, &rstate, stdout, 1);
+ print_interference_blocks(state, &rstate, state->dbgout, 1);
printf("\nlive variables by instruction\n");
walk_variable_lifetimes(
- state, rstate.blocks,
+ state, &state->bb, rstate.blocks,
print_interference_ins, &rstate);
}
coalesced = coalesce_live_ranges(state, &rstate);
if (state->compiler->debug & DEBUG_COALESCING) {
- fprintf(stderr, "coalesced: %d\n", coalesced);
+ fprintf(state->errout, "coalesced: %d\n", coalesced);
}
} while(coalesced);
#if DEBUG_CONSISTENCY > 1
# if 0
- fprintf(stderr, "verify_graph_ins...\n");
+ fprintf(state->errout, "verify_graph_ins...\n");
# endif
/* Verify the interference graph */
walk_variable_lifetimes(
- state, rstate.blocks, verify_graph_ins, &rstate);
+ state, &state->bb, rstate.blocks,
+ verify_graph_ins, &rstate);
# if 0
- fprintf(stderr, "verify_graph_ins done\n");
+ fprintf(state->errout, "verify_graph_ins done\n");
#endif
#endif
@@ -15419,7 +20130,7 @@ static void allocate_registers(struct compile_state *state)
cleanup_rstate(state, &rstate);
/* Display the new graph */
- print_blocks(state, __func__, stdout);
+ print_blocks(state, __func__, state->dbgout);
}
/* Sparce Conditional Constant Propogation
@@ -15433,9 +20144,9 @@ struct lattice_node {
struct ssa_edge *out;
struct flow_block *fblock;
struct triple *val;
- /* lattice high val && !is_const(val)
+ /* lattice high val == def
* lattice const is_const(val)
- * lattice low val == 0
+ * lattice low other
*/
};
struct ssa_edge {
@@ -15472,11 +20183,34 @@ struct scc_state {
};
+static int is_scc_const(struct compile_state *state, struct triple *ins)
+{
+ return ins && (triple_is_ubranch(state, ins) || is_const(ins));
+}
+
+static int is_lattice_hi(struct compile_state *state, struct lattice_node *lnode)
+{
+ return !is_scc_const(state, lnode->val) && (lnode->val == lnode->def);
+}
+
+static int is_lattice_const(struct compile_state *state, struct lattice_node *lnode)
+{
+ return is_scc_const(state, lnode->val);
+}
+
+static int is_lattice_lo(struct compile_state *state, struct lattice_node *lnode)
+{
+ return (lnode->val != lnode->def) && !is_scc_const(state, lnode->val);
+}
+
+
+
+
static void scc_add_fedge(struct compile_state *state, struct scc_state *scc,
struct flow_edge *fedge)
{
if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
- fprintf(stderr, "adding fedge: %p (%4d -> %5d)\n",
+ fprintf(state->errout, "adding fedge: %p (%4d -> %5d)\n",
fedge,
fedge->src->block?fedge->src->block->last->id: 0,
fedge->dst->block?fedge->dst->block->first->id: 0);
@@ -15486,7 +20220,7 @@ static void scc_add_fedge(struct compile_state *state, struct scc_state *scc,
(fedge->work_prev != fedge)) {
if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
- fprintf(stderr, "dupped fedge: %p\n",
+ fprintf(state->errout, "dupped fedge: %p\n",
fedge);
}
return;
@@ -15527,7 +20261,7 @@ static void scc_add_sedge(struct compile_state *state, struct scc_state *scc,
struct ssa_edge *sedge)
{
if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
- fprintf(stderr, "adding sedge: %5d (%4d -> %5d)\n",
+ fprintf(state->errout, "adding sedge: %5d (%4d -> %5d)\n",
sedge - scc->ssa_edges,
sedge->src->def->id,
sedge->dst->def->id);
@@ -15537,7 +20271,7 @@ static void scc_add_sedge(struct compile_state *state, struct scc_state *scc,
(sedge->work_prev != sedge)) {
if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
- fprintf(stderr, "dupped sedge: %5d\n",
+ fprintf(state->errout, "dupped sedge: %5d\n",
sedge - scc->ssa_edges);
}
return;
@@ -15574,6 +20308,7 @@ static struct ssa_edge *scc_next_sedge(
return sedge;
}
+
static void initialize_scc_state(
struct compile_state *state, struct scc_state *scc)
{
@@ -15598,8 +20333,8 @@ static void initialize_scc_state(
ins = ins->next;
} while(ins != first);
if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
- fprintf(stderr, "ins_count: %d ssa_edge_count: %d vertex_count: %d\n",
- ins_count, ssa_edge_count, state->last_vertex);
+ fprintf(state->errout, "ins_count: %d ssa_edge_count: %d vertex_count: %d\n",
+ ins_count, ssa_edge_count, state->bb.last_vertex);
}
scc->ins_count = ins_count;
scc->lattice =
@@ -15607,7 +20342,7 @@ static void initialize_scc_state(
scc->ssa_edges =
xcmalloc(sizeof(*scc->ssa_edges)*(ssa_edge_count + 1), "ssa_edges");
scc->flow_blocks =
- xcmalloc(sizeof(*scc->flow_blocks)*(state->last_vertex + 1),
+ xcmalloc(sizeof(*scc->flow_blocks)*(state->bb.last_vertex + 1),
"flow_blocks");
/* Initialize pass one collect up the nodes */
@@ -15636,6 +20371,9 @@ static void initialize_scc_state(
lnode->out = 0;
lnode->fblock = fblock;
lnode->val = ins; /* LATTICE HIGH */
+ if (lnode->val->op == OP_UNKNOWNVAL) {
+ lnode->val = 0; /* LATTICE LOW by definition */
+ }
lnode->old_id = ins->id;
ins->id = ins_index;
}
@@ -15733,7 +20471,7 @@ static void initialize_scc_state(
fblock->edges = xcmalloc(sizeof(*fblock->edges)*1, "flow_edges");
fblock->in = 0;
fblock->out = fblock->edges;
- dst = &scc->flow_blocks[state->first_block->vertex];
+ dst = &scc->flow_blocks[state->bb.first_block->vertex];
fedge = fblock->edges;
fedge->src = fblock;
fedge->dst = dst;
@@ -15750,7 +20488,7 @@ static void initialize_scc_state(
scc_add_fedge(state, scc, fedge);
}
if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
- fprintf(stderr, "ins_index: %d ssa_edge_index: %d fblock_index: %d\n",
+ fprintf(state->errout, "ins_index: %d ssa_edge_index: %d fblock_index: %d\n",
ins_index, ssa_edge_index, fblock_index);
}
}
@@ -15760,7 +20498,7 @@ static void free_scc_state(
struct compile_state *state, struct scc_state *scc)
{
int i;
- for(i = 0; i < state->last_vertex + 1; i++) {
+ for(i = 0; i < state->bb.last_vertex + 1; i++) {
struct flow_block *fblock;
fblock = &scc->flow_blocks[i];
if (fblock->edges) {
@@ -15809,13 +20547,10 @@ static int lval_changed(struct compile_state *state,
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) &&
+ TRIPLE_SIZE(lnode->val) * sizeof(lnode->val->param[0])) == 0) &&
(memcmp(&lnode->val->u, &old->u, sizeof(old->u)) == 0)) {
changed = 0;
}
@@ -15827,10 +20562,14 @@ static int lval_changed(struct compile_state *state,
}
static void scc_debug_lnode(
- struct compile_state *state, struct lattice_node *lnode, int changed)
+ struct compile_state *state, struct scc_state *scc,
+ struct lattice_node *lnode, int changed)
{
+ if ((state->compiler->debug & DEBUG_SCC_TRANSFORM2) && lnode->val) {
+ display_triple_changes(state->errout, lnode->val, lnode->def);
+ }
if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
- FILE *fp = stderr;
+ FILE *fp = state->errout;
struct triple *val, **expr;
val = lnode->val? lnode->val : lnode->def;
fprintf(fp, "%p %s %3d %10s (",
@@ -15848,78 +20587,13 @@ static void scc_debug_lnode(
fprintf(fp, " <0x%08lx>", (unsigned long)(val->u.cval));
}
fprintf(fp, " ) -> %s %s\n",
- ((!lnode->val)? "lo": is_const(lnode->val)? "const": "hi"),
+ (is_lattice_hi(state, lnode)? "hi":
+ is_lattice_const(state, lnode)? "const" : "lo"),
changed? "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, *old;
- struct flow_edge *fedge;
- int changed;
- 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);
- index = 0;
- for(fedge = lnode->fblock->in; fedge; index++, fedge = fedge->in_next) {
- if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
- fprintf(stderr, "Examining edge: %d vertex: %d executable: %d\n",
- index,
- fedge->dst->block->vertex,
- fedge->executable
- );
- }
- if (!fedge->executable) {
- continue;
- }
- if (!slot[index]) {
- internal_error(state, lnode->def, "no phi value");
- }
- tmp = triple_to_lattice(state, scc, slot[index]);
- /* meet(X, lattice low) = lattice low */
- if (!tmp->val) {
- lnode->val = 0;
- }
- /* meet(X, lattice high) = X */
- else if (!tmp->val) {
- lnode->val = lnode->val;
- }
- /* meet(lattice high, X) = X */
- else if (!is_const(lnode->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)) {
- lnode->val = 0;
- }
- if (!lnode->val) {
- break;
- }
- }
- changed = lval_changed(state, old, lnode);
- scc_debug_lnode(state, lnode, changed);
-
- /* If the lattice value has changed update the work lists. */
- if (changed) {
- 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,
struct lattice_node *lnode)
{
@@ -15938,13 +20612,13 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
scratch->prev = scratch;
scratch->use = 0;
- count = TRIPLE_SIZE(scratch->sizes);
+ count = TRIPLE_SIZE(scratch);
for(i = 0; i < count; i++) {
dexpr = &lnode->def->param[i];
vexpr = &scratch->param[i];
*vexpr = *dexpr;
- if (((i < TRIPLE_MISC_OFF(scratch->sizes)) ||
- (i >= TRIPLE_TARG_OFF(scratch->sizes))) &&
+ if (((i < TRIPLE_MISC_OFF(scratch)) ||
+ (i >= TRIPLE_TARG_OFF(scratch))) &&
*dexpr) {
struct lattice_node *tmp;
tmp = triple_to_lattice(state, scc, *dexpr);
@@ -15971,27 +20645,17 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
internal_error(state, lnode->def, "scratch in list?");
}
/* undo any uses... */
- count = TRIPLE_SIZE(scratch->sizes);
+ count = TRIPLE_SIZE(scratch);
for(i = 0; i < count; i++) {
vexpr = &scratch->param[i];
if (*vexpr) {
unuse_triple(*vexpr, scratch);
}
}
- if (!is_const(scratch)) {
- for(i = 0; i < count; i++) {
- dexpr = &lnode->def->param[i];
- 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) {
- lnode->val = 0;
- }
- }
- }
+ if (lnode->val->op == OP_UNKNOWNVAL) {
+ lnode->val = 0; /* Lattice low by definition */
}
+ /* Find the case when I am lattice high */
if (lnode->val &&
(lnode->val->op == lnode->def->op) &&
(memcmp(lnode->val->param, lnode->def->param,
@@ -15999,6 +20663,23 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
(memcmp(&lnode->val->u, &lnode->def->u, sizeof(lnode->def->u)) == 0)) {
lnode->val = lnode->def;
}
+ /* Only allow lattice high when all of my inputs
+ * are also lattice high. Occassionally I can
+ * have constants with a lattice low input, so
+ * I do not need to check that case.
+ */
+ if (is_lattice_hi(state, lnode)) {
+ struct lattice_node *tmp;
+ int rhs;
+ rhs = lnode->val->rhs;
+ for(i = 0; i < rhs; i++) {
+ tmp = triple_to_lattice(state, scc, RHS(lnode->val, i));
+ if (!is_lattice_hi(state, tmp)) {
+ lnode->val = 0;
+ break;
+ }
+ }
+ }
/* Find the cases that are always lattice lo */
if (lnode->val &&
triple_is_def(state, lnode->val) &&
@@ -16008,9 +20689,9 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
/* See if the lattice value has changed */
changed = lval_changed(state, old, lnode);
/* See if this value should not change */
- if (lnode->val &&
+ if ((lnode->val != lnode->def) &&
(( !triple_is_def(state, lnode->def) &&
- !triple_is_cond_branch(state, lnode->def)) ||
+ !triple_is_cbranch(state, lnode->def)) ||
(lnode->def->op == OP_PIECE))) {
#warning "FIXME constant propogate through expressions with multiple left hand sides"
if (changed) {
@@ -16018,45 +20699,48 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
}
lnode->val = 0;
}
- /* Report what has just happened */
- if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
- display_triple_changes(stderr, scratch, lnode->def);
- }
/* See if we need to free the scratch value */
if (lnode->val != scratch) {
xfree(scratch);
}
+
return changed;
}
-static void scc_visit_branch(struct compile_state *state, struct scc_state *scc,
+
+static void scc_visit_cbranch(struct compile_state *state, struct scc_state *scc,
struct lattice_node *lnode)
{
struct lattice_node *cond;
struct flow_edge *left, *right;
+ int changed;
+
+ /* Update the branch value */
+ changed = compute_lnode_val(state, scc, lnode);
+ scc_debug_lnode(state, scc, lnode, changed);
+
+ /* This only applies to conditional branches */
+ if (!triple_is_cbranch(state, lnode->def)) {
+ internal_error(state, lnode->def, "not a conditional branch");
+ }
+
if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
struct flow_edge *fedge;
- fprintf(stderr, "%s: %d (",
+ FILE *fp = state->errout;
+ fprintf(fp, "%s: %d (",
tops(lnode->def->op),
lnode->def->id);
for(fedge = lnode->fblock->out; fedge; fedge = fedge->out_next) {
- fprintf(stderr, " %d", fedge->dst->block->vertex);
+ fprintf(fp, " %d", fedge->dst->block->vertex);
}
- fprintf(stderr, " )");
- if (TRIPLE_RHS(lnode->def->sizes) > 0) {
- fprintf(stderr, " <- %d",
+ fprintf(fp, " )");
+ if (lnode->def->rhs > 0) {
+ fprintf(fp, " <- %d",
RHS(lnode->def, 0)->id);
}
- fprintf(stderr, "\n");
- }
- if (!triple_is_branch(state, lnode->def)) {
- internal_error(state, lnode->def, "not branch");
- }
- /* This only applies to conditional branches */
- if (!triple_is_cond_branch(state, lnode->def)) {
- return;
+ fprintf(fp, "\n");
}
cond = triple_to_lattice(state, scc, RHS(lnode->def,0));
for(left = cond->fblock->out; left; left = left->out_next) {
@@ -16075,12 +20759,14 @@ static void scc_visit_branch(struct compile_state *state, struct scc_state *scc,
if (!right) {
internal_error(state, lnode->def, "Cannot find right branch edge");
}
- if (cond->val && !is_const(cond->val)) {
-#warning "FIXME do I need to do something here?"
- warning(state, cond->def, "condition not constant?");
+ /* I should only come here if the controlling expressions value
+ * has changed, which means it must be either a constant or lo.
+ */
+ if (is_lattice_hi(state, cond)) {
+ internal_error(state, cond->def, "condition high?");
return;
}
- if (cond->val == 0) {
+ if (is_lattice_lo(state, cond)) {
scc_add_fedge(state, scc, left);
scc_add_fedge(state, scc, right);
}
@@ -16092,21 +20778,106 @@ static void scc_visit_branch(struct compile_state *state, struct scc_state *scc,
}
+
+static void scc_add_sedge_dst(struct compile_state *state,
+ struct scc_state *scc, struct ssa_edge *sedge)
+{
+ if (triple_is_branch(state, sedge->dst->def)) {
+ scc_visit_cbranch(state, scc, sedge->dst);
+ }
+ else if (triple_is_def(state, sedge->dst->def)) {
+ scc_add_sedge(state, scc, sedge);
+ }
+}
+
+static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
+ struct lattice_node *lnode)
+{
+ struct lattice_node *tmp;
+ struct triple **slot, *old;
+ struct flow_edge *fedge;
+ int changed;
+ 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);
+ index = 0;
+ for(fedge = lnode->fblock->in; fedge; index++, fedge = fedge->in_next) {
+ if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
+ fprintf(state->errout, "Examining edge: %d vertex: %d executable: %d\n",
+ index,
+ fedge->dst->block->vertex,
+ fedge->executable
+ );
+ }
+ if (!fedge->executable) {
+ continue;
+ }
+ if (!slot[index]) {
+ internal_error(state, lnode->def, "no phi value");
+ }
+ tmp = triple_to_lattice(state, scc, slot[index]);
+ /* meet(X, lattice low) = lattice low */
+ if (is_lattice_lo(state, tmp)) {
+ lnode->val = 0;
+ }
+ /* meet(X, lattice high) = X */
+ else if (is_lattice_hi(state, tmp)) {
+ lnode->val = lnode->val;
+ }
+ /* meet(lattice high, X) = X */
+ else if (is_lattice_hi(state, lnode)) {
+ lnode->val = dup_triple(state, tmp->val);
+ /* Only change the type if necessary */
+ if (!is_subset_type(lnode->def->type, tmp->val->type)) {
+ lnode->val->type = lnode->def->type;
+ }
+ }
+ /* meet(const, const) = const or lattice low */
+ else if (!constants_equal(state, lnode->val, tmp->val)) {
+ lnode->val = 0;
+ }
+
+ /* meet(lattice low, X) = lattice low */
+ if (is_lattice_lo(state, lnode)) {
+ lnode->val = 0;
+ break;
+ }
+ }
+ changed = lval_changed(state, old, lnode);
+ scc_debug_lnode(state, scc, lnode, changed);
+
+ /* If the lattice value has changed update the work lists. */
+ if (changed) {
+ struct ssa_edge *sedge;
+ for(sedge = lnode->out; sedge; sedge = sedge->out_next) {
+ scc_add_sedge_dst(state, scc, sedge);
+ }
+ }
+}
+
+
static void scc_visit_expr(struct compile_state *state, struct scc_state *scc,
struct lattice_node *lnode)
{
int changed;
+ if (!triple_is_def(state, lnode->def)) {
+ internal_warning(state, lnode->def, "not visiting an expression?");
+ }
changed = compute_lnode_val(state, scc, lnode);
- scc_debug_lnode(state, lnode, changed);
+ scc_debug_lnode(state, scc, lnode, changed);
- if (triple_is_branch(state, lnode->def)) {
- scc_visit_branch(state, scc, lnode);
- }
- else if (changed) {
+ if (changed) {
struct ssa_edge *sedge;
for(sedge = lnode->out; sedge; sedge = sedge->out_next) {
- scc_add_sedge(state, scc, sedge);
+ scc_add_sedge_dst(state, scc, sedge);
}
}
}
@@ -16120,12 +20891,9 @@ static void scc_writeback_values(
do {
struct lattice_node *lnode;
lnode = triple_to_lattice(state, scc, ins);
-
if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
- if (lnode->val &&
- !is_const(lnode->val) &&
- !triple_is_uncond_branch(state, lnode->val) &&
- (lnode->val->op != OP_NOOP))
+ if (is_lattice_hi(state, lnode) &&
+ (lnode->val->op != OP_NOOP))
{
struct flow_edge *fedge;
int executable;
@@ -16135,7 +20903,7 @@ static void scc_writeback_values(
executable |= fedge->executable;
}
if (executable) {
- internal_warning(state, lnode->val,
+ internal_warning(state, lnode->def,
"lattice node %d %s->%s still high?",
ins->id,
tops(lnode->def->op),
@@ -16214,7 +20982,7 @@ static void scc_transform(struct compile_state *state)
}
if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
- fprintf(stderr, "vertex: %d reps: %d\n",
+ fprintf(state->errout, "vertex: %d reps: %d\n",
block->vertex, reps);
}
@@ -16226,12 +20994,13 @@ static void scc_transform(struct compile_state *state)
if (ptr->op == OP_PHI) {
scc_visit_phi(state, &scc, lnode);
}
- else if (reps == 1) {
+ else if ((reps == 1) && triple_is_def(state, ptr))
+ {
scc_visit_expr(state, &scc, lnode);
}
}
/* Add unconditional branch edges */
- if (!triple_is_cond_branch(state, fblock->block->last)) {
+ if (!triple_is_cbranch(state, fblock->block->last)) {
struct flow_edge *out;
for(out = fblock->out; out; out = out->out_next) {
scc_add_fedge(state, &scc, out);
@@ -16245,7 +21014,7 @@ static void scc_transform(struct compile_state *state)
fblock = lnode->fblock;
if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
- fprintf(stderr, "sedge: %5d (%5d -> %5d)\n",
+ fprintf(state->errout, "sedge: %5d (%5d -> %5d)\n",
sedge - scc.ssa_edges,
sedge->src->def->id,
sedge->dst->def->id);
@@ -16271,7 +21040,7 @@ static void scc_transform(struct compile_state *state)
free_scc_state(state, &scc);
rebuild_ssa_form(state);
- print_blocks(state, __func__, stdout);
+ print_blocks(state, __func__, state->dbgout);
}
@@ -16284,7 +21053,7 @@ static void transform_to_arch_instructions(struct compile_state *state)
ins = transform_to_arch_instruction(state, ins);
} while(ins != first);
- print_blocks(state, __func__, stdout);
+ print_blocks(state, __func__, state->dbgout);
}
#if DEBUG_CONSISTENCY
@@ -16322,6 +21091,36 @@ static void verify_uses(struct compile_state *state)
internal_error(state, ins, "lhs not used");
}
}
+ expr = triple_misc(state, ins, 0);
+ if (ins->op != OP_PHI) {
+ for(; expr; expr = triple_targ(state, ins, expr)) {
+ struct triple *misc;
+ misc = *expr;
+ for(set = misc?misc->use:0; set; set = set->next) {
+ if (set->member == ins) {
+ break;
+ }
+ }
+ if (!set) {
+ internal_error(state, ins, "misc not used");
+ }
+ }
+ }
+ if (!triple_is_ret(state, ins)) {
+ expr = triple_targ(state, ins, 0);
+ for(; expr; expr = triple_targ(state, ins, expr)) {
+ struct triple *targ;
+ targ = *expr;
+ for(set = targ?targ->use:0; set; set = set->next) {
+ if (set->member == ins) {
+ break;
+ }
+ }
+ if (!set) {
+ internal_error(state, ins, "targ not used");
+ }
+ }
+ }
ins = ins->next;
} while(ins != first);
@@ -16329,7 +21128,7 @@ static void verify_uses(struct compile_state *state)
static void verify_blocks_present(struct compile_state *state)
{
struct triple *first, *ins;
- if (!state->first_block) {
+ if (!state->bb.first_block) {
return;
}
first = state->first;
@@ -16339,7 +21138,7 @@ static void verify_blocks_present(struct compile_state *state)
if (triple_stores_block(state, ins)) {
if (!ins->u.block) {
internal_error(state, ins,
- "%p not in a block?\n", ins);
+ "%p not in a block?", ins);
}
}
ins = ins->next;
@@ -16366,7 +21165,7 @@ static void verify_blocks(struct compile_state *state)
struct triple *ins;
struct block *block;
int blocks;
- block = state->first_block;
+ block = state->bb.first_block;
if (!block) {
return;
}
@@ -16387,8 +21186,8 @@ static void verify_blocks(struct compile_state *state)
if (!user->member->first) {
internal_error(state, block->first, "user is empty");
}
- if ((block == state->last_block) &&
- (user->member == state->first_block)) {
+ if ((block == state->bb.last_block) &&
+ (user->member == state->bb.first_block)) {
continue;
}
for(edge = user->member->edges; edge; edge = edge->next) {
@@ -16403,15 +21202,15 @@ static void verify_blocks(struct compile_state *state)
}
if (triple_is_branch(state, block->last)) {
struct triple **expr;
- expr = triple_targ(state, block->last, 0);
- for(;expr; expr = triple_targ(state, block->last, expr)) {
+ expr = triple_edge_targ(state, block->last, 0);
+ for(;expr; expr = triple_edge_targ(state, block->last, expr)) {
if (*expr && !edge_present(state, block, *expr)) {
internal_error(state, block->last, "no edge to targ");
}
}
}
- if (!triple_is_uncond_branch(state, block->last) &&
- (block != state->last_block) &&
+ if (!triple_is_ubranch(state, block->last) &&
+ (block != state->bb.last_block) &&
!edge_present(state, block, block->last->next)) {
internal_error(state, block->last, "no edge to block->last->next");
}
@@ -16431,7 +21230,7 @@ static void verify_blocks(struct compile_state *state)
}
if (block->users != users) {
internal_error(state, block->first,
- "computed users %d != stored users %d\n",
+ "computed users %d != stored users %d",
users, block->users);
}
if (!triple_stores_block(state, block->last->next)) {
@@ -16443,10 +21242,10 @@ static void verify_blocks(struct compile_state *state)
internal_error(state, block->last->next,
"bad next block");
}
- } while(block != state->first_block);
- if (blocks != state->last_vertex) {
- internal_error(state, 0, "computed blocks != stored blocks %d\n",
- blocks, state->last_vertex);
+ } while(block != state->bb.first_block);
+ if (blocks != state->bb.last_vertex) {
+ internal_error(state, 0, "computed blocks: %d != stored blocks %d",
+ blocks, state->bb.last_vertex);
}
}
@@ -16454,7 +21253,7 @@ static void verify_domination(struct compile_state *state)
{
struct triple *first, *ins;
struct triple_set *set;
- if (!state->first_block) {
+ if (!state->bb.first_block) {
return;
}
@@ -16466,7 +21265,7 @@ static void verify_domination(struct compile_state *state)
struct triple *use_point;
int i, zrhs;
use_point = 0;
- zrhs = TRIPLE_RHS(set->member->sizes);
+ zrhs = set->member->rhs;
slot = &RHS(set->member, 0);
/* See if the use is on the right hand side */
for(i = 0; i < zrhs; i++) {
@@ -16485,15 +21284,21 @@ static void verify_domination(struct compile_state *state)
}
if (!bset) {
internal_error(state, set->member,
- "no edge for phi rhs %d\n", i);
+ "no edge for phi rhs %d", i);
}
use_point = bset->member->last;
}
}
if (use_point &&
!tdominates(state, ins, use_point)) {
- internal_error(state, use_point,
+ if (is_const(ins)) {
+ internal_warning(state, ins,
"non dominated rhs use point?");
+ }
+ else {
+ internal_error(state, ins,
+ "non dominated rhs use point?");
+ }
}
}
ins = ins->next;
@@ -16508,7 +21313,7 @@ static void verify_rhs(struct compile_state *state)
do {
struct triple **slot;
int zrhs, i;
- zrhs = TRIPLE_RHS(ins->sizes);
+ zrhs = ins->rhs;
slot = &RHS(ins, 0);
for(i = 0; i < zrhs; i++) {
if (slot[i] == 0) {
@@ -16534,7 +21339,7 @@ static void verify_piece(struct compile_state *state)
do {
struct triple *ptr;
int lhs, i;
- lhs = TRIPLE_LHS(ins->sizes);
+ lhs = ins->lhs;
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",
@@ -16563,8 +21368,103 @@ static void verify_ins_colors(struct compile_state *state)
ins = ins->next;
} while(ins != first);
}
+
+static void verify_unknown(struct compile_state *state)
+{
+ struct triple *first, *ins;
+ if ( (unknown_triple.next != &unknown_triple) ||
+ (unknown_triple.prev != &unknown_triple) ||
+#if 0
+ (unknown_triple.use != 0) ||
+#endif
+ (unknown_triple.op != OP_UNKNOWNVAL) ||
+ (unknown_triple.lhs != 0) ||
+ (unknown_triple.rhs != 0) ||
+ (unknown_triple.misc != 0) ||
+ (unknown_triple.targ != 0) ||
+ (unknown_triple.template_id != 0) ||
+ (unknown_triple.id != -1) ||
+ (unknown_triple.type != &unknown_type) ||
+ (unknown_triple.occurance != &dummy_occurance) ||
+ (unknown_triple.param[0] != 0) ||
+ (unknown_triple.param[1] != 0)) {
+ internal_error(state, &unknown_triple, "unknown_triple corrupted!");
+ }
+ if ( (dummy_occurance.count != 2) ||
+ (strcmp(dummy_occurance.filename, __FILE__) != 0) ||
+ (strcmp(dummy_occurance.function, "") != 0) ||
+ (dummy_occurance.col != 0) ||
+ (dummy_occurance.parent != 0)) {
+ internal_error(state, &unknown_triple, "dummy_occurance corrupted!");
+ }
+ if ( (unknown_type.type != TYPE_UNKNOWN)) {
+ internal_error(state, &unknown_triple, "unknown_type corrupted!");
+ }
+ first = state->first;
+ ins = first;
+ do {
+ int params, i;
+ if (ins == &unknown_triple) {
+ internal_error(state, ins, "unknown triple in list");
+ }
+ params = TRIPLE_SIZE(ins);
+ for(i = 0; i < params; i++) {
+ if (ins->param[i] == &unknown_triple) {
+ internal_error(state, ins, "unknown triple used!");
+ }
+ }
+ ins = ins->next;
+ } while(ins != first);
+}
+
+static void verify_types(struct compile_state *state)
+{
+ struct triple *first, *ins;
+ first = state->first;
+ ins = first;
+ do {
+ struct type *invalid;
+ invalid = invalid_type(state, ins->type);
+ if (invalid) {
+ FILE *fp = state->errout;
+ fprintf(fp, "type: ");
+ name_of(fp, ins->type);
+ fprintf(fp, "\n");
+ fprintf(fp, "invalid type: ");
+ name_of(fp, invalid);
+ fprintf(fp, "\n");
+ internal_error(state, ins, "invalid ins type");
+ }
+ } while(ins != first);
+}
+
+static void verify_copy(struct compile_state *state)
+{
+ struct triple *first, *ins, *next;
+ first = state->first;
+ next = ins = first;
+ do {
+ ins = next;
+ next = ins->next;
+ if (ins->op != OP_COPY) {
+ continue;
+ }
+ if (!equiv_types(ins->type, RHS(ins, 0)->type)) {
+ FILE *fp = state->errout;
+ fprintf(fp, "src type: ");
+ name_of(fp, RHS(ins, 0)->type);
+ fprintf(fp, "\n");
+ fprintf(fp, "dst type: ");
+ name_of(fp, ins->type);
+ fprintf(fp, "\n");
+ internal_error(state, ins, "type mismatch in copy");
+ }
+ } while(next != first);
+}
+
static void verify_consistency(struct compile_state *state)
{
+ verify_unknown(state);
verify_uses(state);
verify_blocks_present(state);
verify_blocks(state);
@@ -16572,6 +21472,11 @@ static void verify_consistency(struct compile_state *state)
verify_rhs(state);
verify_piece(state);
verify_ins_colors(state);
+ verify_types(state);
+ verify_copy(state);
+ if (state->compiler->debug & DEBUG_VERIFICATION) {
+ fprintf(state->dbgout, "consistency verified\n");
+ }
}
#else
static void verify_consistency(struct compile_state *state) {}
@@ -16579,16 +21484,20 @@ static void verify_consistency(struct compile_state *state) {}
static void optimize(struct compile_state *state)
{
+ /* Join all of the functions into one giant function */
+ join_functions(state);
+
/* Dump what the instruction graph intially looks like */
print_triples(state);
/* Replace structures with simpler data types */
- flatten_structures(state);
+ decompose_compound_types(state);
print_triples(state);
verify_consistency(state);
/* Analize the intermediate code */
- analyze_basic_blocks(state);
+ state->bb.first = state->first;
+ analyze_basic_blocks(state, &state->bb);
/* Transform the code to ssa form. */
/*
@@ -16637,7 +21546,7 @@ static void optimize(struct compile_state *state)
/* Remove the optimization information.
* This is more to check for memory consistency than to free memory.
*/
- free_basic_blocks(state);
+ free_basic_blocks(state, &state->bb);
}
static void print_op_asm(struct compile_state *state,
@@ -16647,8 +21556,8 @@ static void print_op_asm(struct compile_state *state,
const char *ptr;
unsigned lhs, rhs, i;
info = ins->u.ainfo;
- lhs = TRIPLE_LHS(ins->sizes);
- rhs = TRIPLE_RHS(ins->sizes);
+ lhs = ins->lhs;
+ rhs = ins->rhs;
/* Don't count the clobbers in lhs */
for(i = 0; i < lhs; i++) {
if (LHS(ins, i)->type == &void_type) {
@@ -16694,8 +21603,9 @@ static void print_op_asm(struct compile_state *state,
#define X86_4_8BIT_GPRS 1
/* x86 featrues */
-#define X86_MMX_REGS (1<<0)
-#define X86_XMM_REGS (1<<1)
+#define X86_MMX_REGS (1<<0)
+#define X86_XMM_REGS (1<<1)
+#define X86_NOOP_COPY (1<<2)
/* The x86 register classes */
#define REGC_FLAGS 0
@@ -16733,6 +21643,7 @@ static void print_op_asm(struct compile_state *state,
#define REGCM_IMM16 (1 << REGC_IMM16)
#define REGCM_IMM8 (1 << REGC_IMM8)
#define REGCM_ALL ((1 << (LAST_REGC + 1)) - 1)
+#define REGCM_IMMALL (REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8)
/* The x86 registers */
#define REG_EFLAGS 2
@@ -16852,30 +21763,51 @@ static const struct {
[REGC_IMM8] = { REGC_IMM8_FIRST, REGC_IMM8_LAST },
};
+#if ARCH_INPUT_REGS != 4
+#error ARCH_INPUT_REGS size mismatch
+#endif
+static const struct reg_info arch_input_regs[ARCH_INPUT_REGS] = {
+ { .reg = REG_EAX, .regcm = REGCM_GPR32 },
+ { .reg = REG_EBX, .regcm = REGCM_GPR32 },
+ { .reg = REG_ECX, .regcm = REGCM_GPR32 },
+ { .reg = REG_EDX, .regcm = REGCM_GPR32 },
+};
+
+#if ARCH_OUTPUT_REGS != 4
+#error ARCH_INPUT_REGS size mismatch
+#endif
+static const struct reg_info arch_output_regs[ARCH_OUTPUT_REGS] = {
+ { .reg = REG_EAX, .regcm = REGCM_GPR32 },
+ { .reg = REG_EBX, .regcm = REGCM_GPR32 },
+ { .reg = REG_ECX, .regcm = REGCM_GPR32 },
+ { .reg = REG_EDX, .regcm = REGCM_GPR32 },
+};
+
static void init_arch_state(struct arch_state *arch)
{
memset(arch, 0, sizeof(*arch));
arch->features = 0;
}
+static const struct compiler_flag arch_flags[] = {
+ { "mmx", X86_MMX_REGS },
+ { "sse", X86_XMM_REGS },
+ { "noop-copy", X86_NOOP_COPY },
+ { 0, 0 },
+};
+static const struct compiler_flag arch_cpus[] = {
+ { "i386", 0 },
+ { "p2", X86_MMX_REGS },
+ { "p3", X86_MMX_REGS | X86_XMM_REGS },
+ { "p4", X86_MMX_REGS | X86_XMM_REGS },
+ { "k7", X86_MMX_REGS },
+ { "k8", X86_MMX_REGS | X86_XMM_REGS },
+ { "c3", X86_MMX_REGS },
+ { "c3-2", X86_MMX_REGS | X86_XMM_REGS }, /* Nehemiah */
+ { 0, 0 }
+};
static int arch_encode_flag(struct arch_state *arch, const char *flag)
{
- static const struct compiler_flag flags[] = {
- { "mmx", X86_MMX_REGS },
- { "sse", X86_XMM_REGS },
- { 0, 0 },
- };
- static const struct compiler_flag cpus[] = {
- { "i386", 0 },
- { "p2", X86_MMX_REGS },
- { "p3", X86_MMX_REGS | X86_XMM_REGS },
- { "p4", X86_MMX_REGS | X86_XMM_REGS },
- { "k7", X86_MMX_REGS },
- { "k8", X86_MMX_REGS | X86_XMM_REGS },
- { "c3", X86_MMX_REGS },
- { "c3-2", X86_MMX_REGS | X86_XMM_REGS }, /* Nehemiah */
- { 0, 0 }
- };
int result;
int act;
@@ -16887,14 +21819,20 @@ static int arch_encode_flag(struct arch_state *arch, const char *flag)
}
if (act && strncmp(flag, "cpu=", 4) == 0) {
flag += 4;
- result = set_flag(cpus, &arch->features, 1, flag);
+ result = set_flag(arch_cpus, &arch->features, 1, flag);
}
else {
- result = set_flag(flags, &arch->features, act, flag);
+ result = set_flag(arch_flags, &arch->features, act, flag);
}
return result;
}
+static void arch_usage(FILE *fp)
+{
+ flag_usage(fp, arch_flags, "-m", "-mno-");
+ flag_usage(fp, arch_cpus, "-mcpu=", 0);
+}
+
static unsigned arch_regc_size(struct compile_state *state, int class)
{
if ((class < 0) || (class > LAST_REGC)) {
@@ -17230,35 +22168,35 @@ static struct reg_info arch_reg_clobber(
result.reg = REG_UNSET;
result.regcm = 0;
}
- else if (strcmp(clobber, "%eax") == 0) {
+ else if (strcmp(clobber, "eax") == 0) {
result.reg = REG_EAX;
result.regcm = REGCM_GPR32;
}
- else if (strcmp(clobber, "%ebx") == 0) {
+ else if (strcmp(clobber, "ebx") == 0) {
result.reg = REG_EBX;
result.regcm = REGCM_GPR32;
}
- else if (strcmp(clobber, "%ecx") == 0) {
+ else if (strcmp(clobber, "ecx") == 0) {
result.reg = REG_ECX;
result.regcm = REGCM_GPR32;
}
- else if (strcmp(clobber, "%edx") == 0) {
+ else if (strcmp(clobber, "edx") == 0) {
result.reg = REG_EDX;
result.regcm = REGCM_GPR32;
}
- else if (strcmp(clobber, "%esi") == 0) {
+ else if (strcmp(clobber, "esi") == 0) {
result.reg = REG_ESI;
result.regcm = REGCM_GPR32;
}
- else if (strcmp(clobber, "%edi") == 0) {
+ else if (strcmp(clobber, "edi") == 0) {
result.reg = REG_EDI;
result.regcm = REGCM_GPR32;
}
- else if (strcmp(clobber, "%ebp") == 0) {
+ else if (strcmp(clobber, "ebp") == 0) {
result.reg = REG_EBP;
result.regcm = REGCM_GPR32;
}
- else if (strcmp(clobber, "%esp") == 0) {
+ else if (strcmp(clobber, "esp") == 0) {
result.reg = REG_ESP;
result.regcm = REGCM_GPR32;
}
@@ -17271,13 +22209,14 @@ static struct reg_info arch_reg_clobber(
result.reg = REG_XMM0 + octdigval(clobber[3]);
result.regcm = REGCM_XMM;
}
- else if ((strncmp(clobber, "mmx", 3) == 0) &&
+ else if ((strncmp(clobber, "mm", 2) == 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");
+ error(state, 0, "unknown register name `%s' in asm",
+ clobber);
result.reg = REG_UNSET;
result.regcm = 0;
}
@@ -17371,6 +22310,7 @@ static unsigned arch_type_to_regcm(struct compile_state *state, struct type *typ
REGCM_MMX | REGCM_XMM |
REGCM_IMM32 | REGCM_IMM16;
break;
+ case TYPE_ENUM:
case TYPE_INT:
case TYPE_UINT:
case TYPE_LONG:
@@ -17381,7 +22321,21 @@ static unsigned arch_type_to_regcm(struct compile_state *state, struct type *typ
REGCM_MMX | REGCM_XMM |
REGCM_IMM32;
break;
+ case TYPE_JOIN:
+ case TYPE_UNION:
+ mask = arch_type_to_regcm(state, type->left);
+ break;
+ case TYPE_OVERLAP:
+ mask = arch_type_to_regcm(state, type->left) &
+ arch_type_to_regcm(state, type->right);
+ break;
+ case TYPE_BITFIELD:
+ mask = arch_type_to_regcm(state, type->left);
+ break;
default:
+ fprintf(state->errout, "type: ");
+ name_of(state->errout, type);
+ fprintf(state->errout, "\n");
internal_error(state, 0, "no register class for type");
break;
}
@@ -17439,69 +22393,70 @@ static int get_imm8(struct triple *ins, struct triple **expr)
#define TEMPLATE_NOP 0
#define TEMPLATE_INTCONST8 1
#define TEMPLATE_INTCONST32 2
-#define TEMPLATE_COPY8_REG 3
-#define TEMPLATE_COPY16_REG 4
-#define TEMPLATE_COPY32_REG 5
-#define TEMPLATE_COPY_IMM8 6
-#define TEMPLATE_COPY_IMM16 7
-#define TEMPLATE_COPY_IMM32 8
-#define TEMPLATE_PHI8 9
-#define TEMPLATE_PHI16 10
-#define TEMPLATE_PHI32 11
-#define TEMPLATE_STORE8 12
-#define TEMPLATE_STORE16 13
-#define TEMPLATE_STORE32 14
-#define TEMPLATE_LOAD8 15
-#define TEMPLATE_LOAD16 16
-#define TEMPLATE_LOAD32 17
-#define TEMPLATE_BINARY8_REG 18
-#define TEMPLATE_BINARY16_REG 19
-#define TEMPLATE_BINARY32_REG 20
-#define TEMPLATE_BINARY8_IMM 21
-#define TEMPLATE_BINARY16_IMM 22
-#define TEMPLATE_BINARY32_IMM 23
-#define TEMPLATE_SL8_CL 24
-#define TEMPLATE_SL16_CL 25
-#define TEMPLATE_SL32_CL 26
-#define TEMPLATE_SL8_IMM 27
-#define TEMPLATE_SL16_IMM 28
-#define TEMPLATE_SL32_IMM 29
-#define TEMPLATE_UNARY8 30
-#define TEMPLATE_UNARY16 31
-#define TEMPLATE_UNARY32 32
-#define TEMPLATE_CMP8_REG 33
-#define TEMPLATE_CMP16_REG 34
-#define TEMPLATE_CMP32_REG 35
-#define TEMPLATE_CMP8_IMM 36
-#define TEMPLATE_CMP16_IMM 37
-#define TEMPLATE_CMP32_IMM 38
-#define TEMPLATE_TEST8 39
-#define TEMPLATE_TEST16 40
-#define TEMPLATE_TEST32 41
-#define TEMPLATE_SET 42
-#define TEMPLATE_JMP 43
-#define TEMPLATE_RET 44
-#define TEMPLATE_INB_DX 45
-#define TEMPLATE_INB_IMM 46
-#define TEMPLATE_INW_DX 47
-#define TEMPLATE_INW_IMM 48
-#define TEMPLATE_INL_DX 49
-#define TEMPLATE_INL_IMM 50
-#define TEMPLATE_OUTB_DX 51
-#define TEMPLATE_OUTB_IMM 52
-#define TEMPLATE_OUTW_DX 53
-#define TEMPLATE_OUTW_IMM 54
-#define TEMPLATE_OUTL_DX 55
-#define TEMPLATE_OUTL_IMM 56
-#define TEMPLATE_BSF 57
-#define TEMPLATE_RDMSR 58
-#define TEMPLATE_WRMSR 59
-#define TEMPLATE_UMUL8 60
-#define TEMPLATE_UMUL16 61
-#define TEMPLATE_UMUL32 62
-#define TEMPLATE_DIV8 63
-#define TEMPLATE_DIV16 64
-#define TEMPLATE_DIV32 65
+#define TEMPLATE_UNKNOWNVAL 3
+#define TEMPLATE_COPY8_REG 5
+#define TEMPLATE_COPY16_REG 6
+#define TEMPLATE_COPY32_REG 7
+#define TEMPLATE_COPY_IMM8 8
+#define TEMPLATE_COPY_IMM16 9
+#define TEMPLATE_COPY_IMM32 10
+#define TEMPLATE_PHI8 11
+#define TEMPLATE_PHI16 12
+#define TEMPLATE_PHI32 13
+#define TEMPLATE_STORE8 14
+#define TEMPLATE_STORE16 15
+#define TEMPLATE_STORE32 16
+#define TEMPLATE_LOAD8 17
+#define TEMPLATE_LOAD16 18
+#define TEMPLATE_LOAD32 19
+#define TEMPLATE_BINARY8_REG 20
+#define TEMPLATE_BINARY16_REG 21
+#define TEMPLATE_BINARY32_REG 22
+#define TEMPLATE_BINARY8_IMM 23
+#define TEMPLATE_BINARY16_IMM 24
+#define TEMPLATE_BINARY32_IMM 25
+#define TEMPLATE_SL8_CL 26
+#define TEMPLATE_SL16_CL 27
+#define TEMPLATE_SL32_CL 28
+#define TEMPLATE_SL8_IMM 29
+#define TEMPLATE_SL16_IMM 30
+#define TEMPLATE_SL32_IMM 31
+#define TEMPLATE_UNARY8 32
+#define TEMPLATE_UNARY16 33
+#define TEMPLATE_UNARY32 34
+#define TEMPLATE_CMP8_REG 35
+#define TEMPLATE_CMP16_REG 36
+#define TEMPLATE_CMP32_REG 37
+#define TEMPLATE_CMP8_IMM 38
+#define TEMPLATE_CMP16_IMM 39
+#define TEMPLATE_CMP32_IMM 40
+#define TEMPLATE_TEST8 41
+#define TEMPLATE_TEST16 42
+#define TEMPLATE_TEST32 43
+#define TEMPLATE_SET 44
+#define TEMPLATE_JMP 45
+#define TEMPLATE_RET 46
+#define TEMPLATE_INB_DX 47
+#define TEMPLATE_INB_IMM 48
+#define TEMPLATE_INW_DX 49
+#define TEMPLATE_INW_IMM 50
+#define TEMPLATE_INL_DX 51
+#define TEMPLATE_INL_IMM 52
+#define TEMPLATE_OUTB_DX 53
+#define TEMPLATE_OUTB_IMM 54
+#define TEMPLATE_OUTW_DX 55
+#define TEMPLATE_OUTW_IMM 56
+#define TEMPLATE_OUTL_DX 57
+#define TEMPLATE_OUTL_IMM 58
+#define TEMPLATE_BSF 59
+#define TEMPLATE_RDMSR 60
+#define TEMPLATE_WRMSR 61
+#define TEMPLATE_UMUL8 62
+#define TEMPLATE_UMUL16 63
+#define TEMPLATE_UMUL32 64
+#define TEMPLATE_DIV8 65
+#define TEMPLATE_DIV16 66
+#define TEMPLATE_DIV32 67
#define LAST_TEMPLATE TEMPLATE_DIV32
#if LAST_TEMPLATE >= MAX_TEMPLATES
#error "MAX_TEMPLATES to low"
@@ -17513,13 +22468,83 @@ static int get_imm8(struct triple *ins, struct triple **expr)
static struct ins_template templates[] = {
- [TEMPLATE_NOP] = {},
+ [TEMPLATE_NOP] = {
+ .lhs = {
+ [ 0] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 1] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 2] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 3] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 4] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 5] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 6] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 7] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 8] = { REG_UNNEEDED, REGCM_IMMALL },
+ [ 9] = { REG_UNNEEDED, REGCM_IMMALL },
+ [10] = { REG_UNNEEDED, REGCM_IMMALL },
+ [11] = { REG_UNNEEDED, REGCM_IMMALL },
+ [12] = { REG_UNNEEDED, REGCM_IMMALL },
+ [13] = { REG_UNNEEDED, REGCM_IMMALL },
+ [14] = { REG_UNNEEDED, REGCM_IMMALL },
+ [15] = { REG_UNNEEDED, REGCM_IMMALL },
+ [16] = { REG_UNNEEDED, REGCM_IMMALL },
+ [17] = { REG_UNNEEDED, REGCM_IMMALL },
+ [18] = { REG_UNNEEDED, REGCM_IMMALL },
+ [19] = { REG_UNNEEDED, REGCM_IMMALL },
+ [20] = { REG_UNNEEDED, REGCM_IMMALL },
+ [21] = { REG_UNNEEDED, REGCM_IMMALL },
+ [22] = { REG_UNNEEDED, REGCM_IMMALL },
+ [23] = { REG_UNNEEDED, REGCM_IMMALL },
+ [24] = { REG_UNNEEDED, REGCM_IMMALL },
+ [25] = { REG_UNNEEDED, REGCM_IMMALL },
+ [26] = { REG_UNNEEDED, REGCM_IMMALL },
+ [27] = { REG_UNNEEDED, REGCM_IMMALL },
+ [28] = { REG_UNNEEDED, REGCM_IMMALL },
+ [29] = { REG_UNNEEDED, REGCM_IMMALL },
+ [30] = { REG_UNNEEDED, REGCM_IMMALL },
+ [31] = { REG_UNNEEDED, REGCM_IMMALL },
+ [32] = { REG_UNNEEDED, REGCM_IMMALL },
+ [33] = { REG_UNNEEDED, REGCM_IMMALL },
+ [34] = { REG_UNNEEDED, REGCM_IMMALL },
+ [35] = { REG_UNNEEDED, REGCM_IMMALL },
+ [36] = { REG_UNNEEDED, REGCM_IMMALL },
+ [37] = { REG_UNNEEDED, REGCM_IMMALL },
+ [38] = { REG_UNNEEDED, REGCM_IMMALL },
+ [39] = { REG_UNNEEDED, REGCM_IMMALL },
+ [40] = { REG_UNNEEDED, REGCM_IMMALL },
+ [41] = { REG_UNNEEDED, REGCM_IMMALL },
+ [42] = { REG_UNNEEDED, REGCM_IMMALL },
+ [43] = { REG_UNNEEDED, REGCM_IMMALL },
+ [44] = { REG_UNNEEDED, REGCM_IMMALL },
+ [45] = { REG_UNNEEDED, REGCM_IMMALL },
+ [46] = { REG_UNNEEDED, REGCM_IMMALL },
+ [47] = { REG_UNNEEDED, REGCM_IMMALL },
+ [48] = { REG_UNNEEDED, REGCM_IMMALL },
+ [49] = { REG_UNNEEDED, REGCM_IMMALL },
+ [50] = { REG_UNNEEDED, REGCM_IMMALL },
+ [51] = { REG_UNNEEDED, REGCM_IMMALL },
+ [52] = { REG_UNNEEDED, REGCM_IMMALL },
+ [53] = { REG_UNNEEDED, REGCM_IMMALL },
+ [54] = { REG_UNNEEDED, REGCM_IMMALL },
+ [55] = { REG_UNNEEDED, REGCM_IMMALL },
+ [56] = { REG_UNNEEDED, REGCM_IMMALL },
+ [57] = { REG_UNNEEDED, REGCM_IMMALL },
+ [58] = { REG_UNNEEDED, REGCM_IMMALL },
+ [59] = { REG_UNNEEDED, REGCM_IMMALL },
+ [60] = { REG_UNNEEDED, REGCM_IMMALL },
+ [61] = { REG_UNNEEDED, REGCM_IMMALL },
+ [62] = { REG_UNNEEDED, REGCM_IMMALL },
+ [63] = { REG_UNNEEDED, REGCM_IMMALL },
+ },
+ },
[TEMPLATE_INTCONST8] = {
.lhs = { [0] = { REG_UNNEEDED, REGCM_IMM8 } },
},
[TEMPLATE_INTCONST32] = {
.lhs = { [0] = { REG_UNNEEDED, REGCM_IMM32 } },
},
+ [TEMPLATE_UNKNOWNVAL] = {
+ .lhs = { [0] = { REG_UNSET, COPY32_REGCM } },
+ },
[TEMPLATE_COPY8_REG] = {
.lhs = { [0] = { REG_UNSET, COPY8_REGCM } },
.rhs = { [0] = { REG_UNSET, COPY8_REGCM } },
@@ -17546,64 +22571,16 @@ static struct ins_template templates[] = {
},
[TEMPLATE_PHI8] = {
.lhs = { [0] = { REG_VIRT0, COPY8_REGCM } },
- .rhs = {
- [ 0] = { REG_VIRT0, COPY8_REGCM },
- [ 1] = { REG_VIRT0, COPY8_REGCM },
- [ 2] = { REG_VIRT0, COPY8_REGCM },
- [ 3] = { REG_VIRT0, COPY8_REGCM },
- [ 4] = { REG_VIRT0, COPY8_REGCM },
- [ 5] = { REG_VIRT0, COPY8_REGCM },
- [ 6] = { REG_VIRT0, COPY8_REGCM },
- [ 7] = { REG_VIRT0, COPY8_REGCM },
- [ 8] = { REG_VIRT0, COPY8_REGCM },
- [ 9] = { REG_VIRT0, COPY8_REGCM },
- [10] = { REG_VIRT0, COPY8_REGCM },
- [11] = { REG_VIRT0, COPY8_REGCM },
- [12] = { REG_VIRT0, COPY8_REGCM },
- [13] = { REG_VIRT0, COPY8_REGCM },
- [14] = { REG_VIRT0, COPY8_REGCM },
- [15] = { REG_VIRT0, COPY8_REGCM },
- }, },
+ .rhs = { [0] = { REG_VIRT0, COPY8_REGCM } },
+ },
[TEMPLATE_PHI16] = {
.lhs = { [0] = { REG_VIRT0, COPY16_REGCM } },
- .rhs = {
- [ 0] = { REG_VIRT0, COPY16_REGCM },
- [ 1] = { REG_VIRT0, COPY16_REGCM },
- [ 2] = { REG_VIRT0, COPY16_REGCM },
- [ 3] = { REG_VIRT0, COPY16_REGCM },
- [ 4] = { REG_VIRT0, COPY16_REGCM },
- [ 5] = { REG_VIRT0, COPY16_REGCM },
- [ 6] = { REG_VIRT0, COPY16_REGCM },
- [ 7] = { REG_VIRT0, COPY16_REGCM },
- [ 8] = { REG_VIRT0, COPY16_REGCM },
- [ 9] = { REG_VIRT0, COPY16_REGCM },
- [10] = { REG_VIRT0, COPY16_REGCM },
- [11] = { REG_VIRT0, COPY16_REGCM },
- [12] = { REG_VIRT0, COPY16_REGCM },
- [13] = { REG_VIRT0, COPY16_REGCM },
- [14] = { REG_VIRT0, COPY16_REGCM },
- [15] = { REG_VIRT0, COPY16_REGCM },
- }, },
+ .rhs = { [0] = { REG_VIRT0, COPY16_REGCM } },
+ },
[TEMPLATE_PHI32] = {
.lhs = { [0] = { REG_VIRT0, COPY32_REGCM } },
- .rhs = {
- [ 0] = { REG_VIRT0, COPY32_REGCM },
- [ 1] = { REG_VIRT0, COPY32_REGCM },
- [ 2] = { REG_VIRT0, COPY32_REGCM },
- [ 3] = { REG_VIRT0, COPY32_REGCM },
- [ 4] = { REG_VIRT0, COPY32_REGCM },
- [ 5] = { REG_VIRT0, COPY32_REGCM },
- [ 6] = { REG_VIRT0, COPY32_REGCM },
- [ 7] = { REG_VIRT0, COPY32_REGCM },
- [ 8] = { REG_VIRT0, COPY32_REGCM },
- [ 9] = { REG_VIRT0, COPY32_REGCM },
- [10] = { REG_VIRT0, COPY32_REGCM },
- [11] = { REG_VIRT0, COPY32_REGCM },
- [12] = { REG_VIRT0, COPY32_REGCM },
- [13] = { REG_VIRT0, COPY32_REGCM },
- [14] = { REG_VIRT0, COPY32_REGCM },
- [15] = { REG_VIRT0, COPY32_REGCM },
- }, },
+ .rhs = { [0] = { REG_VIRT0, COPY32_REGCM } },
+ },
[TEMPLATE_STORE8] = {
.rhs = {
[0] = { REG_UNSET, REGCM_GPR32 },
@@ -17965,7 +22942,7 @@ static void fixup_branches(struct compile_state *state,
struct triple *left, *right;
left = right = 0;
left = RHS(cmp, 0);
- if (TRIPLE_RHS(cmp->sizes) > 1) {
+ if (cmp->rhs > 1) {
right = RHS(cmp, 1);
}
branch = entry->member;
@@ -17979,7 +22956,7 @@ static void bool_cmp(struct compile_state *state,
struct triple *ins, int cmp_op, int jmp_op, int set_op)
{
struct triple_set *entry, *next;
- struct triple *set;
+ struct triple *set, *convert;
/* Put a barrier up before the cmp which preceeds the
* copy instruction. If a set actually occurs this gives
@@ -17998,40 +22975,25 @@ static void bool_cmp(struct compile_state *state,
/* Generate the instruction sequence that will transform the
* result of the comparison into a logical value.
*/
- set = post_triple(state, ins, set_op, &char_type, ins, 0);
+ set = post_triple(state, ins, set_op, &uchar_type, ins, 0);
use_triple(ins, set);
set->template_id = TEMPLATE_SET;
+ convert = set;
+ if (!equiv_types(ins->type, set->type)) {
+ convert = post_triple(state, set, OP_CONVERT, ins->type, set, 0);
+ use_triple(set, convert);
+ convert->template_id = TEMPLATE_COPY32_REG;
+ }
+
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);
- }
+ replace_rhs_use(state, ins, convert, entry->member);
}
- return next;
+ fixup_branches(state, ins, convert, jmp_op);
}
struct reg_info arch_reg_lhs(struct compile_state *state, struct triple *ins, int index)
@@ -18043,12 +23005,12 @@ struct reg_info arch_reg_lhs(struct compile_state *state, struct triple *ins, in
index = ins->u.cval;
ins = MISC(ins, 0);
}
- zlhs = TRIPLE_LHS(ins->sizes);
+ zlhs = ins->lhs;
if (triple_is_def(state, ins)) {
zlhs = 1;
}
if (index >= zlhs) {
- internal_error(state, ins, "index %d out of range for %s\n",
+ internal_error(state, ins, "index %d out of range for %s",
index, tops(ins->op));
}
switch(ins->op) {
@@ -18078,7 +23040,7 @@ struct reg_info arch_reg_rhs(struct compile_state *state, struct triple *ins, in
{
struct reg_info result;
struct ins_template *template;
- if ((index > TRIPLE_RHS(ins->sizes)) ||
+ if ((index > ins->rhs) ||
(ins->op == OP_PIECE)) {
internal_error(state, ins, "index %d out of range for %s\n",
index, tops(ins->op));
@@ -18087,6 +23049,9 @@ struct reg_info arch_reg_rhs(struct compile_state *state, struct triple *ins, in
case OP_ASM:
template = &ins->u.ainfo->tmpl;
break;
+ case OP_PHI:
+ index = 0;
+ /* Fall through */
default:
if (ins->template_id > LAST_TEMPLATE) {
internal_error(state, ins, "bad template number %d",
@@ -18108,34 +23073,18 @@ static struct triple *mod_div(struct compile_state *state,
{
struct triple *div, *piece0, *piece1;
- /* Generate a piece to hold the remainder */
- piece1 = post_triple(state, ins, OP_PIECE, ins->type, 0, 0);
- piece1->u.cval = 1;
-
- /* Generate a piece to hold the quotient */
- piece0 = post_triple(state, ins, OP_PIECE, ins->type, 0, 0);
- piece0->u.cval = 0;
-
/* Generate the appropriate division instruction */
div = post_triple(state, ins, div_op, ins->type, 0, 0);
RHS(div, 0) = RHS(ins, 0);
RHS(div, 1) = RHS(ins, 1);
- LHS(div, 0) = piece0;
- LHS(div, 1) = piece1;
+ piece0 = LHS(div, 0);
+ piece1 = LHS(div, 1);
div->template_id = TEMPLATE_DIV32;
use_triple(RHS(div, 0), div);
use_triple(RHS(div, 1), div);
use_triple(LHS(div, 0), div);
use_triple(LHS(div, 1), div);
- /* Hook on piece0 */
- MISC(piece0, 0) = div;
- use_triple(div, piece0);
-
- /* Hook on piece1 */
- MISC(piece1, 0) = div;
- use_triple(div, piece1);
-
/* Replate uses of ins with the appropriate piece of the div */
propogate_use(state, ins, LHS(div, index));
release_triple(state, ins);
@@ -18144,6 +23093,133 @@ static struct triple *mod_div(struct compile_state *state,
return piece1->next;
}
+static int noop_adecl(struct triple *adecl)
+{
+ struct triple_set *use;
+ /* It's a noop if it doesn't specify stoorage */
+ if (adecl->lhs == 0) {
+ return 1;
+ }
+ /* Is the adecl used? If not it's a noop */
+ for(use = adecl->use; use ; use = use->next) {
+ if ((use->member->op != OP_PIECE) ||
+ (MISC(use->member, 0) != adecl)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static struct triple *x86_deposit(struct compile_state *state, struct triple *ins)
+{
+ struct triple *mask, *nmask, *shift;
+ struct triple *val, *val_mask, *val_shift;
+ struct triple *targ, *targ_mask;
+ struct triple *new;
+ ulong_t the_mask, the_nmask;
+
+ targ = RHS(ins, 0);
+ val = RHS(ins, 1);
+
+ /* Get constant for the mask value */
+ the_mask = 1;
+ the_mask <<= ins->u.bitfield.size;
+ the_mask -= 1;
+ the_mask <<= ins->u.bitfield.offset;
+ mask = pre_triple(state, ins, OP_INTCONST, &uint_type, 0, 0);
+ mask->u.cval = the_mask;
+
+ /* Get the inverted mask value */
+ the_nmask = ~the_mask;
+ nmask = pre_triple(state, ins, OP_INTCONST, &uint_type, 0, 0);
+ nmask->u.cval = the_nmask;
+
+ /* Get constant for the shift value */
+ shift = pre_triple(state, ins, OP_INTCONST, &uint_type, 0, 0);
+ shift->u.cval = ins->u.bitfield.offset;
+
+ /* Shift and mask the source value */
+ val_shift = val;
+ if (shift->u.cval != 0) {
+ val_shift = pre_triple(state, ins, OP_SL, val->type, val, shift);
+ use_triple(val, val_shift);
+ use_triple(shift, val_shift);
+ }
+ val_mask = val_shift;
+ if (is_signed(val->type)) {
+ val_mask = pre_triple(state, ins, OP_AND, val->type, val_shift, mask);
+ use_triple(val_shift, val_mask);
+ use_triple(mask, val_mask);
+ }
+
+ /* Mask the target value */
+ targ_mask = pre_triple(state, ins, OP_AND, targ->type, targ, nmask);
+ use_triple(targ, targ_mask);
+ use_triple(nmask, targ_mask);
+
+ /* Now combined them together */
+ new = pre_triple(state, ins, OP_OR, targ->type, targ_mask, val_mask);
+ use_triple(targ_mask, new);
+ use_triple(val_mask, new);
+
+ /* Move all of the users over to the new expression */
+ propogate_use(state, ins, new);
+
+ /* Delete the original triple */
+ release_triple(state, ins);
+
+ /* Restart the transformation at mask */
+ return mask;
+}
+
+static struct triple *x86_extract(struct compile_state *state, struct triple *ins)
+{
+ struct triple *mask, *shift;
+ struct triple *val, *val_mask, *val_shift;
+ ulong_t the_mask;
+
+ val = RHS(ins, 0);
+
+ /* Get constant for the mask value */
+ the_mask = 1;
+ the_mask <<= ins->u.bitfield.size;
+ the_mask -= 1;
+ mask = pre_triple(state, ins, OP_INTCONST, &int_type, 0, 0);
+ mask->u.cval = the_mask;
+
+ /* Get constant for the right shift value */
+ shift = pre_triple(state, ins, OP_INTCONST, &int_type, 0, 0);
+ shift->u.cval = ins->u.bitfield.offset;
+
+ /* Shift arithmetic right, to correct the sign */
+ val_shift = val;
+ if (shift->u.cval != 0) {
+ int op;
+ if (ins->op == OP_SEXTRACT) {
+ op = OP_SSR;
+ } else {
+ op = OP_USR;
+ }
+ val_shift = pre_triple(state, ins, op, val->type, val, shift);
+ use_triple(val, val_shift);
+ use_triple(shift, val_shift);
+ }
+
+ /* Finally mask the value */
+ val_mask = pre_triple(state, ins, OP_AND, ins->type, val_shift, mask);
+ use_triple(val_shift, val_mask);
+ use_triple(mask, val_mask);
+
+ /* Move all of the users over to the new expression */
+ propogate_use(state, ins, val_mask);
+
+ /* Release the original instruction */
+ release_triple(state, ins);
+
+ return mask;
+
+}
+
static struct triple *transform_to_arch_instruction(
struct compile_state *state, struct triple *ins)
{
@@ -18153,7 +23229,7 @@ static struct triple *transform_to_arch_instruction(
* Copies are inserted to preserve the register flexibility
* of 3 address instructions.
*/
- struct triple *next;
+ struct triple *next, *value;
size_t size;
next = ins->next;
switch(ins->op) {
@@ -18166,6 +23242,9 @@ static struct triple *transform_to_arch_instruction(
case OP_ADDRCONST:
ins->template_id = TEMPLATE_INTCONST32;
break;
+ case OP_UNKNOWNVAL:
+ ins->template_id = TEMPLATE_UNKNOWNVAL;
+ break;
case OP_NOOP:
case OP_SDECL:
case OP_BLOBCONST:
@@ -18173,26 +23252,28 @@ static struct triple *transform_to_arch_instruction(
ins->template_id = TEMPLATE_NOP;
break;
case OP_COPY:
+ case OP_CONVERT:
size = size_of(state, ins->type);
- if (is_imm8(RHS(ins, 0)) && (size <= 1)) {
+ value = RHS(ins, 0);
+ if (is_imm8(value) && (size <= SIZEOF_I8)) {
ins->template_id = TEMPLATE_COPY_IMM8;
}
- else if (is_imm16(RHS(ins, 0)) && (size <= 2)) {
+ else if (is_imm16(value) && (size <= SIZEOF_I16)) {
ins->template_id = TEMPLATE_COPY_IMM16;
}
- else if (is_imm32(RHS(ins, 0)) && (size <= 4)) {
+ else if (is_imm32(value) && (size <= SIZEOF_I32)) {
ins->template_id = TEMPLATE_COPY_IMM32;
}
- else if (is_const(RHS(ins, 0))) {
+ else if (is_const(value)) {
internal_error(state, ins, "bad constant passed to copy");
}
- else if (size <= 1) {
+ else if (size <= SIZEOF_I8) {
ins->template_id = TEMPLATE_COPY8_REG;
}
- else if (size <= 2) {
+ else if (size <= SIZEOF_I16) {
ins->template_id = TEMPLATE_COPY16_REG;
}
- else if (size <= 4) {
+ else if (size <= SIZEOF_I32) {
ins->template_id = TEMPLATE_COPY32_REG;
}
else {
@@ -18201,19 +23282,29 @@ static struct triple *transform_to_arch_instruction(
break;
case OP_PHI:
size = size_of(state, ins->type);
- if (size <= 1) {
+ if (size <= SIZEOF_I8) {
ins->template_id = TEMPLATE_PHI8;
}
- else if (size <= 2) {
+ else if (size <= SIZEOF_I16) {
ins->template_id = TEMPLATE_PHI16;
}
- else if (size <= 4) {
+ else if (size <= SIZEOF_I32) {
ins->template_id = TEMPLATE_PHI32;
}
else {
internal_error(state, ins, "bad type passed to phi");
}
break;
+ case OP_ADECL:
+ /* Adecls should always be treated as dead code and
+ * removed. If we are not optimizing they may linger.
+ */
+ if (!noop_adecl(ins)) {
+ internal_error(state, ins, "adecl remains?");
+ }
+ ins->template_id = TEMPLATE_NOP;
+ next = after_lhs(state, ins);
+ break;
case OP_STORE:
switch(ins->type->type & TYPE_MASK) {
case TYPE_CHAR: case TYPE_UCHAR:
@@ -18262,7 +23353,6 @@ static struct triple *transform_to_arch_instruction(
ins->template_id = TEMPLATE_DIV32;
next = after_lhs(state, ins);
break;
- /* FIXME UMUL does not work yet.. */
case OP_UMUL:
ins->template_id = TEMPLATE_UMUL32;
break;
@@ -18284,8 +23374,8 @@ static struct triple *transform_to_arch_instruction(
ins->template_id = TEMPLATE_SL32_CL;
if (get_imm8(ins, &RHS(ins, 1))) {
ins->template_id = TEMPLATE_SL32_IMM;
- } else if (size_of(state, RHS(ins, 1)->type) > 1) {
- typed_pre_copy(state, &char_type, ins, 1);
+ } else if (size_of(state, RHS(ins, 1)->type) > SIZEOF_CHAR) {
+ typed_pre_copy(state, &uchar_type, ins, 1);
}
break;
case OP_INVERT:
@@ -18411,10 +23501,17 @@ static struct triple *transform_to_arch_instruction(
case OP_SET_SMOREEQ: case OP_SET_UMOREEQ:
ins->template_id = TEMPLATE_SET;
break;
+ case OP_DEPOSIT:
+ next = x86_deposit(state, ins);
+ break;
+ case OP_SEXTRACT:
+ case OP_UEXTRACT:
+ next = x86_extract(state, ins);
+ break;
/* Unhandled instructions */
case OP_PIECE:
default:
- internal_error(state, ins, "unhandled ins: %d %s\n",
+ internal_error(state, ins, "unhandled ins: %d %s",
ins->op, tops(ins->op));
break;
}
@@ -18423,7 +23520,7 @@ static struct triple *transform_to_arch_instruction(
static long next_label(struct compile_state *state)
{
- static long label_counter = 0;
+ static long label_counter = 1000;
return ++label_counter;
}
static void generate_local_labels(struct compile_state *state)
@@ -18462,31 +23559,31 @@ static int check_reg(struct compile_state *state,
return reg;
}
-static const char *arch_reg_str(int reg)
-{
+
#if REG_XMM7 != 44
#error "Registers have renumberd fix arch_reg_str"
#endif
- static const char *regs[] = {
- "%unset",
- "%unneeded",
- "%eflags",
- "%al", "%bl", "%cl", "%dl", "%ah", "%bh", "%ch", "%dh",
- "%ax", "%bx", "%cx", "%dx", "%si", "%di", "%bp", "%sp",
- "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp", "%esp",
- "%edx:%eax",
- "%dx:%ax",
- "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7",
- "%xmm0", "%xmm1", "%xmm2", "%xmm3",
- "%xmm4", "%xmm5", "%xmm6", "%xmm7",
- };
+static const char *arch_regs[] = {
+ "%unset",
+ "%unneeded",
+ "%eflags",
+ "%al", "%bl", "%cl", "%dl", "%ah", "%bh", "%ch", "%dh",
+ "%ax", "%bx", "%cx", "%dx", "%si", "%di", "%bp", "%sp",
+ "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp", "%esp",
+ "%edx:%eax",
+ "%dx:%ax",
+ "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7",
+ "%xmm0", "%xmm1", "%xmm2", "%xmm3",
+ "%xmm4", "%xmm5", "%xmm6", "%xmm7",
+};
+static const char *arch_reg_str(int reg)
+{
if (!((reg >= REG_EFLAGS) && (reg <= REG_XMM7))) {
reg = 0;
}
- return regs[reg];
+ return arch_regs[reg];
}
-
static const char *reg(struct compile_state *state, struct triple *triple,
int classes)
{
@@ -18495,13 +23592,56 @@ static const char *reg(struct compile_state *state, struct triple *triple,
return arch_reg_str(reg);
}
+static int arch_reg_size(int reg)
+{
+ int size;
+ size = 0;
+ if (reg == REG_EFLAGS) {
+ size = 32;
+ }
+ else if ((reg >= REG_AL) && (reg <= REG_DH)) {
+ size = 8;
+ }
+ else if ((reg >= REG_AX) && (reg <= REG_SP)) {
+ size = 16;
+ }
+ else if ((reg >= REG_EAX) && (reg <= REG_ESP)) {
+ size = 32;
+ }
+ else if (reg == REG_EDXEAX) {
+ size = 64;
+ }
+ else if (reg == REG_DXAX) {
+ size = 32;
+ }
+ else if ((reg >= REG_MMX0) && (reg <= REG_MMX7)) {
+ size = 64;
+ }
+ else if ((reg >= REG_XMM0) && (reg <= REG_XMM7)) {
+ size = 128;
+ }
+ return size;
+}
+
+static int reg_size(struct compile_state *state, struct triple *ins)
+{
+ int reg;
+ reg = ID_REG(ins->id);
+ if (reg == REG_UNSET) {
+ internal_error(state, ins, "register not set");
+ }
+ return arch_reg_size(reg);
+}
+
+
+
const char *type_suffix(struct compile_state *state, struct type *type)
{
const char *suffix;
switch(size_of(state, type)) {
- case 1: suffix = "b"; break;
- case 2: suffix = "w"; break;
- case 4: suffix = "l"; break;
+ case SIZEOF_I8: suffix = "b"; break;
+ case SIZEOF_I16: suffix = "w"; break;
+ case SIZEOF_I32: suffix = "l"; break;
default:
internal_error(state, 0, "unknown suffix");
suffix = 0;
@@ -18563,8 +23703,13 @@ static void print_const(struct compile_state *state,
(unsigned long)(ins->u.cval));
break;
default:
- internal_error(state, ins, "Unknown constant type");
+ fprintf(state->errout, "type: ");
+ name_of(state->errout, ins->type);
+ fprintf(state->errout, "\n");
+ internal_error(state, ins, "Unknown constant type. Val: %lu",
+ (unsigned long)(ins->u.cval));
}
+
break;
case OP_ADDRCONST:
if ((MISC(ins, 0)->op != OP_SDECL) &&
@@ -18583,7 +23728,7 @@ static void print_const(struct compile_state *state,
{
unsigned char *blob;
size_t size, i;
- size = size_of(state, ins->type);
+ size = size_of_in_bytes(state, ins->type);
blob = ins->u.blob;
for(i = 0; i < size; i++) {
fprintf(fp, ".byte 0x%02x\n",
@@ -18601,18 +23746,40 @@ static void print_const(struct compile_state *state,
#define DATA_SECTION ".rom.data"
static long get_const_pool_ref(
- struct compile_state *state, struct triple *ins, FILE *fp)
+ struct compile_state *state, struct triple *ins, size_t size, FILE *fp)
{
+ size_t fill_bytes;
long ref;
ref = next_label(state);
fprintf(fp, ".section \"" DATA_SECTION "\"\n");
- fprintf(fp, ".balign %d\n", align_of(state, ins->type));
+ fprintf(fp, ".balign %d\n", align_of_in_bytes(state, ins->type));
fprintf(fp, "L%s%lu:\n", state->compiler->label_prefix, ref);
print_const(state, ins, fp);
+ fill_bytes = bits_to_bytes(size - size_of(state, ins->type));
+ if (fill_bytes) {
+ fprintf(fp, ".fill %d, 1, 0\n", fill_bytes);
+ }
fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
return ref;
}
+static long get_mask_pool_ref(
+ struct compile_state *state, struct triple *ins, unsigned long mask, FILE *fp)
+{
+ long ref;
+ if (mask == 0xff) {
+ ref = 1;
+ }
+ else if (mask == 0xffff) {
+ ref = 2;
+ }
+ else {
+ ref = 0;
+ internal_error(state, ins, "unhandled mask value");
+ }
+ return ref;
+}
+
static void print_binary_op(struct compile_state *state,
const char *op, struct triple *ins, FILE *fp)
{
@@ -18756,10 +23923,15 @@ static void print_op_move(struct compile_state *state,
* of registers we can move between.
* Because OP_COPY will be introduced in arbitrary locations
* OP_COPY must not affect flags.
+ * OP_CONVERT can change the flags and it is the only operation
+ * where it is expected the types in the registers can change.
*/
int omit_copy = 1; /* Is it o.k. to omit a noop copy? */
struct triple *dst, *src;
- if (ins->op == OP_COPY) {
+ if (state->arch->features & X86_NOOP_COPY) {
+ omit_copy = 0;
+ }
+ if ((ins->op == OP_COPY) || (ins->op == OP_CONVERT)) {
src = RHS(ins, 0);
dst = ins;
}
@@ -18767,6 +23939,19 @@ static void print_op_move(struct compile_state *state,
internal_error(state, ins, "unknown move operation");
src = dst = 0;
}
+ if (reg_size(state, dst) < size_of(state, dst->type)) {
+ internal_error(state, ins, "Invalid destination register");
+ }
+ if (!equiv_types(src->type, dst->type) && (dst->op == OP_COPY)) {
+ fprintf(state->errout, "src type: ");
+ name_of(state->errout, src->type);
+ fprintf(state->errout, "\n");
+ fprintf(state->errout, "dst type: ");
+ name_of(state->errout, dst->type);
+ fprintf(state->errout, "\n");
+ internal_error(state, ins, "Type mismatch for OP_COPY");
+ }
+
if (!is_const(src)) {
int src_reg, dst_reg;
int src_regcm, dst_regcm;
@@ -18978,12 +24163,17 @@ static void print_op_move(struct compile_state *state,
}
#endif /* X86_4_8BIT_GPRS */
else {
+ if ((src_regcm & ~REGCM_FLAGS) == 0) {
+ internal_error(state, ins, "attempt to copy from %%eflags!");
+ }
internal_error(state, ins, "unknown copy type");
}
}
else {
+ size_t dst_size;
int dst_reg;
int dst_regcm;
+ dst_size = size_of(state, dst->type);
dst_reg = ID_REG(dst->id);
dst_regcm = arch_reg_regcm(state, dst_reg);
if (dst_regcm & (REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO)) {
@@ -18993,8 +24183,8 @@ static void print_op_move(struct compile_state *state,
reg(state, dst, REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO));
}
else if (dst_regcm & REGCM_DIVIDEND64) {
- if (size_of(state, dst->type) > 4) {
- internal_error(state, ins, "64bit constant...");
+ if (dst_size > SIZEOF_I32) {
+ internal_error(state, ins, "%dbit constant...", dst_size);
}
fprintf(fp, "\tmov $0, %%edx\n");
fprintf(fp, "\tmov ");
@@ -19002,8 +24192,8 @@ static void print_op_move(struct compile_state *state,
fprintf(fp, ", %%eax\n");
}
else if (dst_regcm & REGCM_DIVIDEND32) {
- if (size_of(state, dst->type) > 2) {
- internal_error(state, ins, "32bit constant...");
+ if (dst_size > SIZEOF_I16) {
+ internal_error(state, ins, "%dbit constant...", dst_size);
}
fprintf(fp, "\tmov $0, %%dx\n");
fprintf(fp, "\tmov ");
@@ -19012,7 +24202,10 @@ static void print_op_move(struct compile_state *state,
}
else if (dst_regcm & (REGCM_XMM | REGCM_MMX)) {
long ref;
- ref = get_const_pool_ref(state, src, fp);
+ if (dst_size > SIZEOF_I32) {
+ internal_error(state, ins, "%d bit constant...", dst_size);
+ }
+ ref = get_const_pool_ref(state, src, SIZEOF_I32, fp);
fprintf(fp, "\tmovd L%s%lu, %s\n",
state->compiler->label_prefix, ref,
reg(state, dst, (REGCM_XMM | REGCM_MMX)));
@@ -19021,6 +24214,101 @@ static void print_op_move(struct compile_state *state,
internal_error(state, ins, "unknown copy immediate type");
}
}
+ /* Leave now if this is not a type conversion */
+ if (ins->op != OP_CONVERT) {
+ return;
+ }
+ /* Now make certain I have not logically overflowed the destination */
+ if ((size_of(state, src->type) > size_of(state, dst->type)) &&
+ (size_of(state, dst->type) < reg_size(state, dst)))
+ {
+ unsigned long mask;
+ int dst_reg;
+ int dst_regcm;
+ if (size_of(state, dst->type) >= 32) {
+ fprintf(state->errout, "dst type: ");
+ name_of(state->errout, dst->type);
+ fprintf(state->errout, "\n");
+ internal_error(state, dst, "unhandled dst type size");
+ }
+ mask = 1;
+ mask <<= size_of(state, dst->type);
+ mask -= 1;
+
+ dst_reg = ID_REG(dst->id);
+ dst_regcm = arch_reg_regcm(state, dst_reg);
+
+ if (dst_regcm & (REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO)) {
+ fprintf(fp, "\tand $0x%lx, %s\n",
+ mask, reg(state, dst, REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO));
+ }
+ else if (dst_regcm & REGCM_MMX) {
+ long ref;
+ ref = get_mask_pool_ref(state, dst, mask, fp);
+ fprintf(fp, "\tpand L%s%lu, %s\n",
+ state->compiler->label_prefix, ref,
+ reg(state, dst, REGCM_MMX));
+ }
+ else if (dst_regcm & REGCM_XMM) {
+ long ref;
+ ref = get_mask_pool_ref(state, dst, mask, fp);
+ fprintf(fp, "\tpand L%s%lu, %s\n",
+ state->compiler->label_prefix, ref,
+ reg(state, dst, REGCM_XMM));
+ }
+ else {
+ fprintf(state->errout, "dst type: ");
+ name_of(state->errout, dst->type);
+ fprintf(state->errout, "\n");
+ fprintf(state->errout, "dst: %s\n", reg(state, dst, REGCM_ALL));
+ internal_error(state, dst, "failed to trunc value: mask %lx", mask);
+ }
+ }
+ /* Make certain I am properly sign extended */
+ if ((size_of(state, src->type) < size_of(state, dst->type)) &&
+ (is_signed(src->type)))
+ {
+ int bits, reg_bits, shift_bits;
+ int dst_reg;
+ int dst_regcm;
+
+ bits = size_of(state, src->type);
+ reg_bits = reg_size(state, dst);
+ if (reg_bits > 32) {
+ reg_bits = 32;
+ }
+ shift_bits = reg_bits - size_of(state, src->type);
+ dst_reg = ID_REG(dst->id);
+ dst_regcm = arch_reg_regcm(state, dst_reg);
+
+ if (shift_bits < 0) {
+ internal_error(state, dst, "negative shift?");
+ }
+
+ if (dst_regcm & (REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO)) {
+ fprintf(fp, "\tshl $%d, %s\n",
+ shift_bits,
+ reg(state, dst, REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO));
+ fprintf(fp, "\tsar $%d, %s\n",
+ shift_bits,
+ reg(state, dst, REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO));
+ }
+ else if (dst_regcm & (REGCM_MMX | REGCM_XMM)) {
+ fprintf(fp, "\tpslld $%d, %s\n",
+ shift_bits,
+ reg(state, dst, REGCM_MMX | REGCM_XMM));
+ fprintf(fp, "\tpsrad $%d, %s\n",
+ shift_bits,
+ reg(state, dst, REGCM_MMX | REGCM_XMM));
+ }
+ else {
+ fprintf(state->errout, "dst type: ");
+ name_of(state->errout, dst->type);
+ fprintf(state->errout, "\n");
+ fprintf(state->errout, "dst: %s\n", reg(state, dst, REGCM_ALL));
+ internal_error(state, dst, "failed to signed extend value");
+ }
+ }
}
static void print_op_load(struct compile_state *state,
@@ -19147,14 +24435,14 @@ static void print_op_branch(struct compile_state *state,
{
const char *bop = "j";
if ((branch->op == OP_JMP) || (branch->op == OP_CALL)) {
- if (TRIPLE_RHS(branch->sizes) != 0) {
+ if (branch->rhs != 0) {
internal_error(state, branch, "jmp with condition?");
}
bop = "jmp";
}
else {
struct triple *ptr;
- if (TRIPLE_RHS(branch->sizes) != 1) {
+ if (branch->rhs != 1) {
internal_error(state, branch, "jmpcc without condition?");
}
check_reg(state, RHS(branch, 0), REGCM_FLAGS);
@@ -19186,6 +24474,11 @@ static void print_op_branch(struct compile_state *state,
}
}
+#if 1
+ if (branch->op == OP_CALL) {
+ fprintf(fp, "\t/* call */\n");
+ }
+#endif
fprintf(fp, "\t%s L%s%lu\n",
bop,
state->compiler->label_prefix,
@@ -19203,7 +24496,7 @@ static void print_op_set(struct compile_state *state,
struct triple *set, FILE *fp)
{
const char *sop = "set";
- if (TRIPLE_RHS(set->sizes) != 1) {
+ if (set->rhs != 1) {
internal_error(state, set, "setcc without condition?");
}
check_reg(state, RHS(set, 0), REGCM_FLAGS);
@@ -19261,7 +24554,7 @@ static void print_sdecl(struct compile_state *state,
struct triple *ins, FILE *fp)
{
fprintf(fp, ".section \"" DATA_SECTION "\"\n");
- fprintf(fp, ".balign %d\n", align_of(state, ins->type));
+ fprintf(fp, ".balign %d\n", align_of_in_bytes(state, ins->type));
fprintf(fp, "L%s%lu:\n",
state->compiler->label_prefix, (unsigned long)(ins->u.cval));
print_const(state, MISC(ins, 0), fp);
@@ -19290,6 +24583,7 @@ static void print_instruction(struct compile_state *state,
case OP_POS: break;
case OP_NEG: print_unary_op(state, "neg", ins, fp); break;
case OP_INVERT: print_unary_op(state, "not", ins, fp); break;
+ case OP_NOOP:
case OP_INTCONST:
case OP_ADDRCONST:
case OP_BLOBCONST:
@@ -19297,10 +24591,15 @@ static void print_instruction(struct compile_state *state,
case OP_PHI:
/* Don't generate anything for variable declarations. */
break;
+ case OP_UNKNOWNVAL:
+ fprintf(fp, " /* unknown %s */\n",
+ reg(state, ins, REGCM_ALL));
+ break;
case OP_SDECL:
print_sdecl(state, ins, fp);
break;
case OP_COPY:
+ case OP_CONVERT:
print_op_move(state, ins, fp);
break;
case OP_LOAD:
@@ -19369,6 +24668,12 @@ static void print_instruction(struct compile_state *state,
fprintf(fp, "L%s%lu:\n",
state->compiler->label_prefix, (unsigned long)(ins->u.cval));
break;
+ case OP_ADECL:
+ /* Ignore adecls with no registers error otherwise */
+ if (!noop_adecl(ins)) {
+ internal_error(state, ins, "adecl remains?");
+ }
+ break;
/* Ignore OP_PIECE */
case OP_PIECE:
break;
@@ -19396,6 +24701,13 @@ static void print_instructions(struct compile_state *state)
print_location = 1;
last_occurance = 0;
fp = state->output;
+ /* Masks for common sizes */
+ fprintf(fp, ".section \"" DATA_SECTION "\"\n");
+ fprintf(fp, ".balign 16\n");
+ fprintf(fp, "L%s1:\n", state->compiler->label_prefix);
+ fprintf(fp, ".int 0xff, 0, 0, 0\n");
+ fprintf(fp, "L%s2:\n", state->compiler->label_prefix);
+ fprintf(fp, ".int 0xffff, 0, 0, 0\n");
fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
first = state->first;
ins = first;
@@ -19450,23 +24762,59 @@ static void generate_code(struct compile_state *state)
}
-static void print_tokens(struct compile_state *state)
+static void print_preprocessed_tokens(struct compile_state *state)
{
struct token *tk;
+ int tok;
+ FILE *fp;
+ int line;
+ const char *filename;
+ fp = state->output;
tk = &state->token[0];
- do {
-#if 1
- token(state, 0);
-#else
- next_token(state, 0);
-#endif
- loc(stdout, state, 0);
- printf("%s <- `%s'\n",
- tokens[tk->tok],
+ filename = 0;
+ line = 0;
+ for(;;) {
+ const char *token_str;
+ tok = peek(state);
+ if (tok == TOK_EOF) {
+ break;
+ }
+ eat(state, tok);
+ token_str =
tk->ident ? tk->ident->name :
- tk->str_len ? tk->val.str : "");
+ tk->str_len ? tk->val.str :
+ tokens[tk->tok];
+
+ if ((state->file->line != line) ||
+ (state->file->basename != filename)) {
+ int i, col;
+ if ((state->file->basename == filename) &&
+ (line < state->file->line)) {
+ while(line < state->file->line) {
+ fprintf(fp, "\n");
+ line++;
+ }
+ }
+ else {
+ fprintf(fp, "\n#line %d \"%s\"\n",
+ state->file->line, state->file->basename);
+ }
+ line = state->file->line;
+ filename = state->file->basename;
+ col = get_col(state->file) - strlen(token_str);
+ for(i = 0; i < col; i++) {
+ fprintf(fp, " ");
+ }
+ }
- } while(tk->tok != TOK_EOF);
+ fprintf(fp, "%s ", token_str);
+
+ if (state->compiler->debug & DEBUG_TOKENS) {
+ loc(state->dbgout, state, 0);
+ fprintf(state->dbgout, "%s <- `%s'\n",
+ tokens[tok], token_str);
+ }
+ }
}
static void compile(const char *filename,
@@ -19483,26 +24831,48 @@ static void compile(const char *filename,
memset(&state.token[i], 0, sizeof(state.token[i]));
state.token[i].tok = -1;
}
+ /* Remember the output descriptors */
+ state.errout = stderr;
+ state.dbgout = stdout;
/* Remember the output filename */
state.output = fopen(state.compiler->ofilename, "w");
if (!state.output) {
error(&state, 0, "Cannot open output file %s\n",
state.compiler->ofilename);
}
+ /* Make certain a good cleanup happens */
+ exit_state = &state;
+ atexit(exit_cleanup);
+
/* Prep the preprocessor */
state.if_depth = 0;
- state.if_value = 0;
+ memset(state.if_bytes, 0, sizeof(state.if_bytes));
/* register the C keywords */
register_keywords(&state);
/* register the keywords the macro preprocessor knows */
register_macro_keywords(&state);
+ /* generate some builtin macros */
+ register_builtin_macros(&state);
/* Memorize where some special keywords are. */
- state.i_switch = lookup(&state, "switch", 6);
- state.i_case = lookup(&state, "case", 4);
- state.i_continue = lookup(&state, "continue", 8);
- state.i_break = lookup(&state, "break", 5);
- state.i_default = lookup(&state, "default", 7);
- state.i_return = lookup(&state, "return", 6);
+ state.i_switch = lookup(&state, "switch", 6);
+ state.i_case = lookup(&state, "case", 4);
+ state.i_continue = lookup(&state, "continue", 8);
+ state.i_break = lookup(&state, "break", 5);
+ state.i_default = lookup(&state, "default", 7);
+ state.i_return = lookup(&state, "return", 6);
+ /* Memorize where predefined macros are. */
+ state.i_defined = lookup(&state, "defined", 7);
+ state.i___VA_ARGS__ = lookup(&state, "__VA_ARGS__", 11);
+ state.i___FILE__ = lookup(&state, "__FILE__", 8);
+ state.i___LINE__ = lookup(&state, "__LINE__", 8);
+ /* Memorize where predefined identifiers are. */
+ state.i___func__ = lookup(&state, "__func__", 8);
+ /* Memorize where some attribute keywords are. */
+ state.i_noinline = lookup(&state, "noinline", 8);
+ state.i_always_inline = lookup(&state, "always_inline", 13);
+
+ /* Process the command line macros */
+ process_cmdline_macros(&state);
/* Allocate beginning bounding labels for the function list */
state.first = label(&state);
@@ -19518,22 +24888,22 @@ static void compile(const char *filename,
state.global_pool->id |= TRIPLE_FLAG_VOLATILE;
flatten(&state, state.first, state.global_pool);
-
/* Enter the globl definition scope */
start_scope(&state);
register_builtins(&state);
compile_file(&state, filename, 1);
-#if 0
- print_tokens(&state);
-#endif
+
+ /* Stop if all we want is preprocessor output */
+ if (state.compiler->flags & COMPILER_CPP_ONLY) {
+ print_preprocessed_tokens(&state);
+ return;
+ }
+
decls(&state);
/* Exit the global definition scope */
end_scope(&state);
- /* Join all of the functions into one giant function */
- join_functions(&state);
-
/* Now that basic compilation has happened
* optimize the intermediate code
*/
@@ -19541,21 +24911,37 @@ static void compile(const char *filename,
generate_code(&state);
if (state.compiler->debug) {
- fprintf(stderr, "done\n");
+ fprintf(state.errout, "done\n");
}
+ exit_state = 0;
}
-static void version(void)
+static void version(FILE *fp)
{
- printf("romcc " VERSION " released " RELEASE_DATE "\n");
+ fprintf(fp, "romcc " VERSION " released " RELEASE_DATE "\n");
}
static void usage(void)
{
- version();
- printf(
- "Usage: romcc <source>.c\n"
- "Compile a C source file without using ram\n"
+ FILE *fp = stdout;
+ version(fp);
+ fprintf(fp,
+ "\nUsage: romcc [options] <source>.c\n"
+ "Compile a C source file generating a binary that does not implicilty use RAM\n"
+ "Options: \n"
+ "-o <output file name>\n"
+ "-f<option> Specify a generic compiler option\n"
+ "-m<option> Specify a arch dependent option\n"
+ "-- Specify this is the last option\n"
+ "\nGeneric compiler options:\n"
+ );
+ compiler_usage(fp);
+ fprintf(fp,
+ "\nArchitecture compiler options:\n"
+ );
+ arch_usage(fp);
+ fprintf(fp,
+ "\n"
);
}
@@ -19575,6 +24961,11 @@ int main(int argc, char **argv)
struct compiler_state compiler;
struct arch_state arch;
int all_opts;
+
+
+ /* I don't want any surprises */
+ setlocale(LC_ALL, "C");
+
init_compiler_state(&compiler);
init_arch_state(&arch);
filename = 0;
@@ -19592,7 +24983,19 @@ int main(int argc, char **argv)
result = 0;
all_opts = 1;
}
- else if (strncmp(argv[1],"-O", 2) == 0) {
+ else if (strncmp(argv[1], "-E", 2) == 0) {
+ result = compiler_encode_flag(&compiler, argv[1]);
+ }
+ else if (strncmp(argv[1], "-O", 2) == 0) {
+ result = compiler_encode_flag(&compiler, argv[1]);
+ }
+ else if (strncmp(argv[1], "-I", 2) == 0) {
+ result = compiler_encode_flag(&compiler, argv[1]);
+ }
+ else if (strncmp(argv[1], "-D", 2) == 0) {
+ result = compiler_encode_flag(&compiler, argv[1]);
+ }
+ else if (strncmp(argv[1], "-U", 2) == 0) {
result = compiler_encode_flag(&compiler, argv[1]);
}
else if (strncmp(argv[1], "--label-prefix=", 15) == 0) {
diff --git a/util/romcc/tests.sh b/util/romcc/tests.sh
new file mode 100644
index 0000000000..0dba165a75
--- /dev/null
+++ b/util/romcc/tests.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+# Allow core dumps
+ulimit -c hard
+set -x
+N=''
+root=simple_test
+#root=simple_test
+#root=linux_test
+#root=raminit_test
+if [ -n "$2" -a -n "$1" ] ; then
+ root=$1
+ N=$2
+elif [ -n "$1" ] ; then
+ root=$1
+else
+ echo "too few arguments"
+ exit 1
+fi
+ROMCC=./romcc
+stem="$root$N"
+base=tests/$stem
+op="-Itests/include"
+op="$op -feliminate-inefectual-code -fsimplify -fscc-transform "
+#op="$op -O2"
+op="$op -finline-policy=defaulton"
+#op="$op -finline-policy=nopenalty"
+#op="$op -finline-policy=never"
+op="$op -fdebug -fdebug-triples -fdebug-interference -fdebug-verification"
+#op="$op -fdebug-inline"
+#op="$op -fdebug-calls"
+#op="$op -mnoop-copy"
+#op="$op -fsimplify -fno-simplify-op -fno-simplify-phi -fno-simplify-label -fno-simplify-branch -fno-simplify-copy -fno-simplify-arith -fno-simplify-shift -fno-simplify-bitwise -fno-simplify-logical"
+#op="$op -fdebug-rebuild-ssa-form"
+op="$op -fmax-allocation-passes=8"
+op="$op -fdebug-live-range-conflicts"
+op="$op -fdebug-scc-transform"
+op="$op -fdebug-scc-transform2"
+#-fdebug-coalescing
+#-fdebug-coalesing2
+#-fno-simplify-call "
+#-fno-always-inline"
+#
+#op="-O2 -mmmx -msse --debug=4294967295"
+#op="-fdebug -fdebug-triples -fdebug-inline -O2 -mmmx -msse -fno-always-inline "
+#op="-fdebug -fdebug-inline -O2 -mmmx "
+#op="-fdebug -fdebug-live-range-conflicts -fdebug-live-range-conflicts2 -fno-debug-interference -fdebug-color-graph -fdebug-coalescing -fmax-allocation-passes=10 -O2 -mmmx -msse"
+#op="-fdebug -O2 -mmmx -msse"
+#op="-fdebug -fdebug-inline -fno-eliminate-inefectual-code -fno-always-inline -mmmx"
+#op="-fdebug -fdebug-inline -fno-always-inline -mmmx"
+export ALLOC_CHECK_=2
+rm -f core $base.S $base.debug $base.debug2 $base.elf $base.out &&
+make romcc &&
+$ROMCC $op -o $base.S $base.c 2>&1 > $base.debug | tee $base.debug2
+if [ '(' -f $base.c ')' -a '(' '!' -f core ')' -a '(' -f $base.S ')' ]; then
+ if [ "$stem" = "linux_test$N" ] ; then
+ as $base.S -o $base.o &&
+ ld -T tests/ldscript.ld $base.o -o $base.elf &&
+ ./$base.elf > $base.out &&
+ diff -u results/$stem.out $base.out
+ else
+ /bin/true
+ fi
+else
+ /bin/false
+fi
+
+
diff --git a/util/romcc/tests/fail_test10.c b/util/romcc/tests/fail_test10.c
new file mode 100644
index 0000000000..1993e0e59c
--- /dev/null
+++ b/util/romcc/tests/fail_test10.c
@@ -0,0 +1,19 @@
+
+
+struct result {
+ int a, b, c, d;
+};
+
+struct big_arg {
+ int a, b;
+};
+static struct result main(int a, int b, struct big_arg d)
+{
+ struct result result;
+ result.a = 1;
+ result.b = 1;
+ result.c = b + 1;
+ result.d = a + 1;
+
+}
+
diff --git a/util/romcc/tests/fail_test11.c b/util/romcc/tests/fail_test11.c
new file mode 100644
index 0000000000..3252060cc8
--- /dev/null
+++ b/util/romcc/tests/fail_test11.c
@@ -0,0 +1,21 @@
+
+
+struct big_arg {
+ int x, y;
+};
+struct result {
+ struct big_arg a;
+ int c, d;
+};
+
+static struct result main(int a, int b, int c, int d)
+{
+ struct result result;
+ result.a.x = d + 1;
+ result.a.y = c + 1;
+ result.c = b + 1;
+ result.d = a + 1;
+
+ return result;
+}
+
diff --git a/util/romcc/tests/fail_test9.c b/util/romcc/tests/fail_test9.c
new file mode 100644
index 0000000000..a24ce9ea3e
--- /dev/null
+++ b/util/romcc/tests/fail_test9.c
@@ -0,0 +1,9 @@
+typedef __builtin_msr_t msr_t;
+
+static msr_t rdmsr(unsigned long index)
+{
+ return __builtin_rdmsr(index);
+}
+
+#warning "romcc should die gracefully here"
+
diff --git a/util/romcc/tests/hello_world1.c b/util/romcc/tests/hello_world1.c
new file mode 100644
index 0000000000..6dd80d89b8
--- /dev/null
+++ b/util/romcc/tests/hello_world1.c
@@ -0,0 +1,128 @@
+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) {
+ ;
+ }
+}
diff --git a/util/romcc/tests/include/linux_console.h b/util/romcc/tests/include/linux_console.h
new file mode 100644
index 0000000000..861c701e5d
--- /dev/null
+++ b/util/romcc/tests/include/linux_console.h
@@ -0,0 +1,136 @@
+#ifndef LINUX_CONSOLE_H
+#define LINUX_CONSOLE_H
+
+#include "linux_syscall.h"
+
+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 inline 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 int 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_emerg_char(unsigned char byte) { console_tx_char(byte); }
+static void print_emerg_hex8(unsigned char value) { console_tx_hex8(value); }
+static void print_emerg_hex16(unsigned short value){ console_tx_hex16(value); }
+static void print_emerg_hex32(unsigned int value) { console_tx_hex32(value); }
+static void print_emerg(const char *str) { console_tx_string(str); }
+
+static void print_warn_char(unsigned char byte) { console_tx_char(byte); }
+static void print_warn_hex8(unsigned char value) { console_tx_hex8(value); }
+static void print_warn_hex16(unsigned short value){ console_tx_hex16(value); }
+static void print_warn_hex32(unsigned int value) { console_tx_hex32(value); }
+static void print_warn(const char *str) { console_tx_string(str); }
+
+static void print_info_char(unsigned char byte) { console_tx_char(byte); }
+static void print_info_hex8(unsigned char value) { console_tx_hex8(value); }
+static void print_info_hex16(unsigned short value){ console_tx_hex16(value); }
+static void print_info_hex32(unsigned int value) { console_tx_hex32(value); }
+static void print_info(const char *str) { console_tx_string(str); }
+
+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 print_spew_char(unsigned char byte) { console_tx_char(byte); }
+static void print_spew_hex8(unsigned char value) { console_tx_hex8(value); }
+static void print_spew_hex16(unsigned short value){ console_tx_hex16(value); }
+static void print_spew_hex32(unsigned int value) { console_tx_hex32(value); }
+static void print_spew(const char *str) { console_tx_string(str); }
+
+static void die(const char *str)
+{
+ print_emerg(str);
+ do {
+ asm volatile (" ");
+ } while(1);
+}
+#endif /* LINUX_CONSOLE_H */
diff --git a/util/romcc/tests/include/linux_syscall.h b/util/romcc/tests/include/linux_syscall.h
new file mode 100644
index 0000000000..487095f712
--- /dev/null
+++ b/util/romcc/tests/include/linux_syscall.h
@@ -0,0 +1,7 @@
+#ifndef LINUX_SYSCALL_H
+#define LINUX_SYSCALL_H
+
+/* When I support other platforms use #ifdefs here */
+#include "linuxi386_syscall.h"
+
+#endif /* LINUX_SYSCALL_H */
diff --git a/util/romcc/tests/include/linuxi386_syscall.h b/util/romcc/tests/include/linuxi386_syscall.h
new file mode 100644
index 0000000000..d202661c67
--- /dev/null
+++ b/util/romcc/tests/include/linuxi386_syscall.h
@@ -0,0 +1,299 @@
+struct syscall_result {
+ long val;
+ int errno;
+};
+
+static inline 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
+
+/* Standard file descriptors */
+#define STDIN_FILENO 0 /* Standard input */
+#define STDOUT_FILENO 1 /* Standard output */
+#define STDERR_FILENO 2 /* Standard error output */
+
+typedef long ssize_t;
+typedef unsigned long size_t;
+
+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);
+}
diff --git a/util/romcc/tests/ldscript.ld b/util/romcc/tests/ldscript.ld
index 97b307fc66..249ebd5c19 100644
--- a/util/romcc/tests/ldscript.ld
+++ b/util/romcc/tests/ldscript.ld
@@ -4,6 +4,7 @@ ENTRY(_start)
SECTIONS
{
. = 0x1000;
+ __cpu_reset = 0xdeadbeef;
.text . : {
. = ALIGN(16);
_start = . ;
diff --git a/util/romcc/tests/linux_test10.c b/util/romcc/tests/linux_test10.c
new file mode 100644
index 0000000000..ef8c930187
--- /dev/null
+++ b/util/romcc/tests/linux_test10.c
@@ -0,0 +1,57 @@
+#include "linux_syscall.h"
+#include "linux_console.h"
+
+struct stuff {
+ signed int a : 5;
+ signed int b : 6;
+ signed int c : 2;
+ unsigned int d : 3;
+};
+
+static void test(void)
+{
+ struct stuff var;
+#if 0
+ int a, b, c, d;
+
+ a = 1;
+ b = 2;
+ c = 3;
+ d = 7;
+
+ var.a = a;
+ var.b = b;
+ var.c = c;
+ var.d = d;
+
+ a = var.a;
+ b = var.b;
+ c = var.c;
+ d = var.d;
+
+ print_debug(" a: ");
+ print_debug_hex32(a);
+ print_debug(" b: ");
+ print_debug_hex32(b);
+ print_debug(" c: ");
+ print_debug_hex32(c);
+ print_debug(" d: ");
+ print_debug_hex32(d);
+#else
+ var.a = 1;
+ var.b = 2;
+ var.c = 3;
+ var.d = 7;
+
+ print_debug(" a: ");
+ print_debug_hex32(var.a);
+ print_debug(" b: ");
+ print_debug_hex32(var.b);
+ print_debug(" c: ");
+ print_debug_hex32(var.c);
+ print_debug(" d: ");
+ print_debug_hex32(var.d);
+#endif
+ print_debug("\n");
+ _exit(0);
+}
diff --git a/util/romcc/tests/linux_test11.c b/util/romcc/tests/linux_test11.c
new file mode 100644
index 0000000000..9c1183fd87
--- /dev/null
+++ b/util/romcc/tests/linux_test11.c
@@ -0,0 +1,11 @@
+#include "linux_syscall.h"
+#include "linux_console.h"
+
+static void test(void)
+{
+ signed char x;
+ x = -1;
+ print_debug_hex32(x);
+ print_debug("\n");
+ _exit(0);
+}
diff --git a/util/romcc/tests/linux_test12.c b/util/romcc/tests/linux_test12.c
new file mode 100644
index 0000000000..5503aa05f0
--- /dev/null
+++ b/util/romcc/tests/linux_test12.c
@@ -0,0 +1,70 @@
+#include "linux_syscall.h"
+#include "linux_console.h"
+
+#define MACRO(hello, hello2) 1
+
+#ifndef A
+#define A 135
+#endif
+#define B A
+#define C B
+#define D C
+#define E D
+#define F E
+#define G F
+#define H G
+#define I H
+
+#define FOO() "hah?\n"
+#define BAR(X) ( X " There\n" )
+#define BAZ(X) #X
+#define SUM(X, Y) ((X) + (Y))
+#define REALLY_SUM(...) SUM(__VA_ARGS__)
+
+
+#define hash_hash # /* comment */ ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+
+#define ECHO(X) X
+#define print_debug(X) ECHO(print_debug(X))
+
+static void test(void)
+{
+ print_debug(FOO());
+ print_debug(BAR("Hi!!"));
+ print_debug(BAZ(This should be shown as a string... "enclosed in quotes") "\n");
+ print_debug("This is a quote\" see\n");
+ print_debug(BAR(BAZ(I)));
+
+ print_debug_hex32(REALLY_SUM(1,2));
+ print_debug("\n");
+
+ print_debug(join(x, y) "\n");
+
+ print_debug("romcc: ");
+ print_debug_hex8(__ROMCC__);
+ print_debug(".");
+ print_debug_hex8(__ROMCC_MINOR__);
+ print_debug("\n");
+
+ print_debug(__FILE__);
+ print_debug(":");
+ print_debug(__func__);
+ print_debug(":");
+ print_debug_hex32(__LINE__);
+ print_debug("\n");
+
+ print_debug("Compiled at: ");
+ print_debug(__DATE__);
+ print_debug(" ");
+ print_debug(__TIME__);
+ print_debug("\n");
+
+ print_debug("Compile time: ");
+ print_debug(__TIME__);
+ print_debug("\n");
+
+ _exit(0);
+}
diff --git a/util/romcc/tests/linux_test13.c b/util/romcc/tests/linux_test13.c
new file mode 100644
index 0000000000..83ef239854
--- /dev/null
+++ b/util/romcc/tests/linux_test13.c
@@ -0,0 +1,47 @@
+#include "linux_syscall.h"
+#include "linux_console.h"
+
+struct mem_controller {
+ unsigned short channel0[4];
+};
+
+static unsigned int spd_detect_dimms(const struct mem_controller *ctrl)
+{
+ unsigned dimm_mask;
+ int i;
+
+ print_debug("1\n");
+ dimm_mask = 0;
+ for(i = 0; i < 4; i++) {
+ int byte;
+ unsigned device;
+
+ print_debug("2\n");
+ device = ctrl->channel0[i];
+ if (device) {
+ print_debug("3\n");
+ byte = ctrl->channel0[i] + 2;
+ if (byte == 7) {
+ dimm_mask |= (1 << i);
+ }
+ }
+ print_debug("4\n");
+ }
+ print_debug("5\n");
+ return dimm_mask;
+}
+
+
+static void main(void)
+{
+ static const struct mem_controller cpu[] = {
+ {
+ .channel0 = { (0xa<<3)|0, (0xa<<3)|2, 0, 0 },
+ },
+ };
+ long dimm_mask;
+ print_debug("A\n");
+ dimm_mask = spd_detect_dimms(cpu);
+ print_debug("B\n");
+ _exit(0);
+}
diff --git a/util/romcc/tests/linux_test5.c b/util/romcc/tests/linux_test5.c
index 55613c21b0..13093fb0fc 100644
--- a/util/romcc/tests/linux_test5.c
+++ b/util/romcc/tests/linux_test5.c
@@ -1,7 +1,7 @@
#include "linux_syscall.h"
#include "linux_console.h"
-int log2(int value)
+inline int log2(int value)
{
/* __builtin_bsr is a exactly equivalent to the x86 machine
* instruction with the exception that it returns -1
diff --git a/util/romcc/tests/linux_test9.c b/util/romcc/tests/linux_test9.c
new file mode 100644
index 0000000000..2a900a55fc
--- /dev/null
+++ b/util/romcc/tests/linux_test9.c
@@ -0,0 +1,13 @@
+#include "linux_syscall.h"
+#include "linux_console.h"
+
+static void test(void)
+{
+ unsigned char i;
+ for(i = 127; i != 5; i++) {
+ print_debug("i: ");
+ print_debug_hex32((unsigned )i);
+ print_debug("\n");
+ }
+ _exit(0);
+}
diff --git a/util/romcc/tests/raminit_test1.c b/util/romcc/tests/raminit_test1.c
new file mode 100644
index 0000000000..9b6cf5d31c
--- /dev/null
+++ b/util/romcc/tests/raminit_test1.c
@@ -0,0 +1,1292 @@
+#define HAVE_STRING_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)
+{
+ __builtin_outb(value, port);
+}
+
+void outw(unsigned short value, unsigned short port)
+{
+ __builtin_outw(value, port);
+}
+
+void outl(unsigned int value, unsigned short port)
+{
+ __builtin_outl(value, port);
+}
+
+unsigned char inb(unsigned short port)
+{
+ return __builtin_inb(port);
+}
+
+unsigned char inw(unsigned short port)
+{
+ return __builtin_inw(port);
+}
+
+unsigned char inl(unsigned short port)
+{
+ return __builtin_inl(port);
+}
+
+static unsigned int config_cmd(unsigned char bus, unsigned devfn, unsigned where)
+{
+ return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3);
+}
+
+static unsigned char pcibios_read_config_byte(
+ unsigned char bus, unsigned devfn, unsigned where)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ return inb(0xCFC + (where & 3));
+}
+
+static unsigned short pcibios_read_config_word(
+ unsigned char bus, unsigned devfn, unsigned where)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ return inw(0xCFC + (where & 2));
+}
+
+static unsigned int pcibios_read_config_dword(
+ unsigned char bus, unsigned devfn, unsigned where)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ return inl(0xCFC);
+}
+
+
+static void pcibios_write_config_byte(
+ unsigned char bus, unsigned devfn, unsigned where, unsigned char value)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ outb(value, 0xCFC + (where & 3));
+}
+
+static void pcibios_write_config_word(
+ unsigned char bus, unsigned devfn, unsigned where, unsigned short value)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ outw(value, 0xCFC + (where & 2));
+}
+
+static void pcibios_write_config_dword(
+ unsigned char bus, unsigned devfn, unsigned where, unsigned int value)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ outl(value, 0xCFC);
+}
+
+/* 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
+
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+
+/* 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))
+ ;
+}
+
+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_nibble(unsigned nibble)
+{
+ unsigned char digit;
+ digit = nibble + '0';
+ if (digit > '9') {
+ digit += 39;
+ }
+ __console_tx_char(digit);
+}
+void __console_tx_hex8(unsigned char byte)
+{
+ __console_tx_nibble(byte >> 4);
+ __console_tx_nibble(byte & 0x0f);
+}
+
+void __console_tx_hex32(unsigned char value)
+{
+ __console_tx_nibble((value >> 28) & 0x0f);
+ __console_tx_nibble((value >> 24) & 0x0f);
+ __console_tx_nibble((value >> 20) & 0x0f);
+ __console_tx_nibble((value >> 16) & 0x0f);
+ __console_tx_nibble((value >> 12) & 0x0f);
+ __console_tx_nibble((value >> 8) & 0x0f);
+ __console_tx_nibble((value >> 4) & 0x0f);
+ __console_tx_nibble(value & 0x0f);
+}
+
+#if HAVE_STRING_SUPPORT
+void __console_tx_string(char *str)
+{
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ __console_tx_char(ch);
+ }
+}
+#else
+void __console_tx_string(char *str)
+{
+}
+#endif
+
+
+void print_emerg_char(unsigned char byte) { __console_tx_char(byte); }
+void print_emerg_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_emerg_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_emerg(char *str) { __console_tx_string(str); }
+
+void print_alert_char(unsigned char byte) { __console_tx_char(byte); }
+void print_alert_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_alert_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_alert(char *str) { __console_tx_string(str); }
+
+void print_crit_char(unsigned char byte) { __console_tx_char(byte); }
+void print_crit_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_crit_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_crit(char *str) { __console_tx_string(str); }
+
+void print_err_char(unsigned char byte) { __console_tx_char(byte); }
+void print_err_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_err_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_err(char *str) { __console_tx_string(str); }
+
+void print_warning_char(unsigned char byte) { __console_tx_char(byte); }
+void print_warning_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_warning_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_warning(char *str) { __console_tx_string(str); }
+
+void print_notice_char(unsigned char byte) { __console_tx_char(byte); }
+void print_notice_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_notice_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_notice(char *str) { __console_tx_string(str); }
+
+void print_info_char(unsigned char byte) { __console_tx_char(byte); }
+void print_info_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_info_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_info(char *str) { __console_tx_string(str); }
+
+void print_debug_char(unsigned char byte) { __console_tx_char(byte); }
+void print_debug_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_debug_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_debug(char *str) { __console_tx_string(str); }
+
+void print_spew_char(unsigned char byte) { __console_tx_char(byte); }
+void print_spew_hex8(unsigned char value) { __console_tx_hex8(value); }
+void print_spew_hex32(unsigned int value) { __console_tx_hex32(value); }
+void print_spew(char *str) { __console_tx_string(str); }
+
+#define PIIX4_DEVFN 0x90
+#define SMBUS_MEM_DEVICE_START 0x50
+#define SMBUS_MEM_DEVICE_END 0x53
+#define SMBUS_MEM_DEVICE_INC 1
+
+
+#define PM_BUS 0
+#define PM_DEVFN (PIIX4_DEVFN+3)
+
+#define SMBUS_IO_BASE 0x1000
+#define SMBHSTSTAT 0
+#define SMBHSTCTL 2
+#define SMBHSTCMD 3
+#define SMBHSTADD 4
+#define SMBHSTDAT0 5
+#define SMBHSTDAT1 6
+#define SMBBLKDAT 7
+
+void smbus_enable(void)
+{
+ /* iobase addr */
+ pcibios_write_config_dword(PM_BUS, PM_DEVFN, 0x90, SMBUS_IO_BASE | 1);
+ /* smbus enable */
+ pcibios_write_config_byte(PM_BUS, PM_DEVFN, 0xd2, (0x4 << 1) | 1);
+ /* iospace enable */
+ pcibios_write_config_word(PM_BUS, PM_DEVFN, 0x4, 1);
+}
+
+void smbus_setup(void)
+{
+ outb(0, SMBUS_IO_BASE + SMBHSTSTAT);
+}
+
+static void smbus_wait_until_ready(void)
+{
+ while((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) {
+ /* nop */
+ }
+}
+
+static void smbus_wait_until_done(void)
+{
+ unsigned char byte;
+ do {
+ byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ }while((byte &1) == 1);
+ while( (byte & ~1) == 0) {
+ byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ }
+}
+
+int smbus_read_byte(unsigned device, unsigned address)
+{
+ unsigned char host_status_register;
+ unsigned char byte;
+ int result;
+
+ smbus_wait_until_ready();
+
+ /* setup transaction */
+ /* disable interrupts */
+ outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
+ /* set the device I'm talking too */
+ outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADD);
+ /* set the command/address... */
+ outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
+ /* set up for a byte data read */
+ outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
+
+ /* clear any lingering errors, so the transaction will run */
+ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
+
+ /* clear the data byte...*/
+ outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
+
+ /* start the command */
+ outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
+
+ /* poll for transaction completion */
+ smbus_wait_until_done();
+
+ host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+
+ /* read results of transaction */
+ byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
+
+ result = byte;
+ if (host_status_register != 0x02) {
+ result = -1;
+ }
+ return result;
+}
+
+#define I440GX_BUS 0
+#define I440GX_DEVFN ((0x00 << 3) + 0)
+
+#define USE_ECC 0
+
+#define CAS_LATENCY 3
+
+ /* CAS latency 2 */
+#if (CAS_LATENCY == 2)
+#define CAS_NB 0x17
+ /*
+ * 7 == 0111
+ * 1 == 0001
+ */
+#define CAS_MODE 0x2a
+ /*
+ * a == 1010
+ * 2 == 0010
+ */
+#endif
+
+ /* CAS latency 3 */
+#if (CAS_LATENCY == 3)
+#define CAS_NB 0x13
+ /*
+ * 3 == 0011
+ * 1 == 0001
+ */
+#define CAS_MODE 0x3a
+ /*
+ * a == 1010
+ * 3 == 0011
+ */
+#endif
+
+#ifndef CAS_NB
+#error "Nothing defined"
+#endif
+
+/* Default values for config registers */
+
+static void set_nbxcfg(void)
+{
+ /* NBXCFG 0x50 - 0x53 */
+ /* f == 1111
+ * 0 == 0000
+ * 0 == 0000
+ * 0 == 0000
+ * 0 == 0000
+ * 1 == 0001
+ * 8 == 1000
+ * c == 1100
+ * SDRAM Row without ECC:
+ * row 0 == 1 No ECC
+ * row 1 == 1 No ECC
+ * row 2 == 1 No ECC
+ * row 3 == 1 No ECC
+ * row 4 == 1 No ECC
+ * row 5 == 1 No ECC
+ * row 6 == 1 No ECC
+ * row 7 == 1 No ECC
+ * Host Bus Fast Data Ready Enable == 0 Disabled
+ * IDSEL_REDIRECT == 0 (430TX compatibility disable?)
+ * WSC# Hanshake Disable == 0 enable (Use External IOAPIC)
+ * Host/DRAM Frequence == 00 100Mhz
+ * AGP to PCI Access Enable == 0 Disable
+ * PCI Agent to Aperture Access Disable == 0 Enable (Ignored)
+ * Aperture Access Global Enable == 0 Disable
+ * DRAM Data Integrity Mode == 11 (Error Checking/Correction)
+ * ECC Diagnostic Mode Enable == 0 Not Enabled
+ * MDA present == 0 Not Present
+ * USWC Write Post During During I/O Bridge Access Enable == 1 Enabled
+ * In Order Queue Depth (IQD) (RO) == ??
+ */
+ pcibios_write_config_dword(I440GX_BUS, I440GX_DEVFN, 0x50, 0xff00000c);
+}
+
+static void set_dramc(void)
+{
+ /* 0 == 0000
+ * 8 == 1000
+ * Not registered SDRAM
+ * refresh disabled
+ */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57, 0x8);
+}
+
+static void set_pam(void)
+{
+ /* PAM - Programmable Attribute Map Registers */
+ /* Ideally we want to enable all of these as DRAM and teach
+ * linux it is o.k. to use them...
+ */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x59, 0x00);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5a, 0x00);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5b, 0x00);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5d, 0x00);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5e, 0x00);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5f, 0x00);
+}
+
+static void set_drb(void)
+{
+ /* DRB - DRAM Row Boundary Registers */
+ /* Conservative setting 8MB of ram on first DIMM... */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x60, 0x01);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x61, 0x01);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x62, 0x01);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x63, 0x01);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x64, 0x01);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x65, 0x01);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x66, 0x01);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x67, 0x01);
+}
+
+static void set_fdhc(void)
+{
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x68, 0x00);
+}
+static void set_mbsc(void)
+{
+ /* MBSC - Memory Buffer Strength Control */
+ /* 00c00003e820
+ * [47:44] 0 == 0000
+ * [43:40] 0 == 0000
+ * [39:36] c == 1100
+ * [35:32] 0 == 0000
+ * [31:28] 0 == 0000
+ * [27:24] 0 == 0000
+ * [23:20] 0 == 0000
+ * [19:16] 3 == 0011
+ * [15:12] e == 1110
+ * [11: 8] 8 == 1000
+ * [ 7: 4] 2 == 0010
+ * [ 3: 0] 0 == 0000
+ * MAA[14:0]#, WEA#, SRASA#, SCASA# Buffer Strengths == 3x
+ * MAB[14,13,10,12:11,9:0]#, WEB#, SRASB#, SCASB# Buffer Strengths == 3x
+ * MD[63:0]# Buffer Strength Control 2 == 3x
+ * MD[63:0]# Buffer Strength Control 1 == 3x
+ * MECC[7:0] Buffer Strength Control 2 == 3x
+ * MECC[7:0] Buffer Strength Control 1 == 3x
+ * CSB7# Buffer Strength == 3x
+ * CSA7# Buffer Strength == 3x
+ * CSB6# Buffer Strength == 3x
+ * CSA6# Buffer Strength == 3x
+ * CSA5#/CSB5# Buffer Strength == 2x
+ * CSA4#/CSB4# Buffer Strength == 2x
+ * CSA3#/CSB3# Buffer Strength == 2x
+ * CSA2#/CSB2# Buffer Strength == 2x
+ * CSA1#/CSB1# Buffer Strength == 2x
+ * CSA0#/CSB0# Buffer Strength == 2x
+ * DQMA5 Buffer Strength == 2x
+ * DQMA1 Buffer Strength == 3x
+ * DQMB5 Buffer Strength == 2x
+ * DQMB1 Buffer Strength == 2x
+ * DQMA[7:6,4:2,0] Buffer Strength == 3x
+ * GCKE Buffer Strength == 1x
+ * FENA Buffer Strength == 3x
+ */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x69, 0xB3);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6a, 0xee);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6b, 0xff);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6c, 0xff);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6d, 0xff);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6e, 0x03);
+}
+
+static void set_smram(void)
+{
+ /* 0x72 SMRAM */
+ /* 1 == 0001
+ * a == 1010
+ * SMM Compatible base segment == 010 (Hardcoded value)
+ */
+}
+
+static void set_esramc(void)
+{
+ /* 0x73 ESMRAMC */
+}
+
+static void set_rps(void)
+{
+ /* RPS - Row Page Size Register */
+ /* 0x0055
+ * [15:12] 0 == 0000
+ * [11: 8] 0 == 0000
+ * [ 7: 4] 5 == 0101
+ * [ 3: 0] 5 == 0101
+ * DRB[0] == 4KB
+ * DRB[1] == 4KB
+ * DRB[2] == 4KB
+ * DRB[3] == 4KB
+ * DRB[4] == 2KB
+ * DRB[5] == 2KB
+ * DRB[6] == 2KB
+ * DRB[7] == 2KB
+ */
+ pcibios_write_config_word(I440GX_BUS, I440GX_DEVFN, 0x74, 0x5555);
+}
+
+static void set_sdramc(void)
+{
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76, CAS_NB);
+}
+
+static void set_pgpol(void)
+{
+ /* PGPOL - Paging Policy Register */
+ /* 0xff07
+ * [15:12] f == 1111
+ * [11: 8] f == 1111
+ * [ 7: 4] 0 == 0000
+ * [ 3: 0] 7 == 0111
+ * row0 == 4banks
+ * row1 == 4banks
+ * row2 == 4banks
+ * row3 == 4banks
+ * row4 == 4banks
+ * row5 == 4banks
+ * row6 == 4banks
+ * row7 == 4banks
+ * Dram Idle Timer (DIT) == 32 clocks
+ */
+ pcibios_write_config_word(I440GX_BUS, I440GX_DEVFN, 0x78, 0xff07);
+}
+
+static void set_mbfs(void)
+{
+ /* MBFS - Memory Buffer Frequencey Select Register */
+ /* 0xffff7f
+ * [23:20] f == 1111
+ * [19:16] f == 1111
+ * [15:12] f == 1111
+ * [11: 8] f == 1111
+ * [ 7: 4] 7 == 0111
+ * [ 3: 0] f == 1111
+ * MAA[14:0], WEA#, SRASA#, SCASA# == 100Mhz Buffers Enabled
+ * MAB[14,13,10,12:11,9:0], WEB#, SRASB#, SCASB# == 100Mhz Buffers Enabled
+ * MD[63:0] Control 2 == 100 Mhz Buffer Enable
+ * MD[63:0] Control 1 == 100 Mhz B
+ * MECC[7:0] Control 2 == 100 Mhz B
+ *
+ */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xca, 0xff);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xcb, 0xff);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xcc, 0x7f);
+}
+
+static void set_dwtc(void)
+{
+ /* DWTC - DRAM Write Thermal Throttle Control */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe0, 0xb4);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe1, 0xbe);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe2, 0xff);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe3, 0xd7);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe4, 0x97);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe5, 0x3e);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe6, 0x00);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe7, 0x80);
+}
+
+static void set_drtc(void)
+{
+ /* DRTC - DRAM Read Thermal Throttle Control */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe8, 0x2c);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe9, 0xd3);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xea, 0xf7);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xeb, 0xcf);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xec, 0x9d);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xed, 0x3e);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xee, 0x00);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xef, 0x00);
+}
+
+static void set_pmcr(void)
+{
+ /* PMCR -- BIOS sets 0x90 into it.
+ * 0x10 is REQUIRED.
+ * we have never used it. So why did this ever work?
+ */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x7a, 0x90);
+
+}
+void sdram_set_registers(void)
+{
+ set_nbxcfg();
+ set_dramc();
+ set_pam();
+ set_drb();
+ set_fdhc();
+ set_mbsc();
+ set_smram();
+ set_esramc();
+ set_rps();
+ set_sdramc();
+ set_pgpol();
+ set_mbfs();
+ set_dwtc();
+ set_drtc();
+ set_pmcr();
+}
+
+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);
+}
+
+
+static void spd_set_drb(void)
+{
+ /*
+ * Effects: Uses serial presence detect to set the
+ * DRB registers which holds the ending memory address assigned
+ * to each DIMM.
+ */
+ unsigned end_of_memory;
+ unsigned device;
+ unsigned drb_reg;
+
+ end_of_memory = 0; /* in multiples of 8MiB */
+ device = SMBUS_MEM_DEVICE_START;
+ drb_reg = 0x60;
+ while (device <= SMBUS_MEM_DEVICE_END) {
+ unsigned side1_bits, side2_bits;
+ int byte, byte2;
+
+ side1_bits = side2_bits = -1;
+
+ /* rows */
+ byte = smbus_read_byte(device, 3);
+ if (byte >= 0) {
+ side1_bits += byte & 0xf;
+
+ /* columns */
+ byte = smbus_read_byte(device, 4);
+ side1_bits += byte & 0xf;
+
+ /* banks */
+ byte = smbus_read_byte(device, 17);
+ side1_bits += log2(byte);
+
+ /* Get the moduel data width and convert it to a power of two */
+ /* low byte */
+ byte = smbus_read_byte(device, 6);
+
+ /* high byte */
+ byte2 = smbus_read_byte(device, 7);
+#if HAVE_CAST_SUPPORT
+ side1_bits += log2((((unsigned long)byte2 << 8)| byte));
+#else
+ side1_bits += log2((byte2 << 8) | byte);
+#endif
+
+ /* now I have the ram size in bits as a power of two (less 1) */
+ /* Make it mulitples of 8MB */
+ side1_bits -= 25;
+
+ /* side two */
+
+ /* number of physical banks */
+ byte = smbus_read_byte(device, 5);
+ if (byte > 1) {
+ /* for now only handle the symmetrical case */
+ side2_bits = side1_bits;
+ }
+ }
+
+ /* Compute the end address for the DRB register */
+ /* Only process dimms < 2GB (2^8 * 8MB) */
+ if (side1_bits < 8) {
+ end_of_memory += (1 << side1_bits);
+ }
+#if HAVE_STRING_SUPPORT
+ print_debug("end_of_memory: "); print_debug_hex32(end_of_memory); print_debug("\n");
+#endif
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, drb_reg, end_of_memory);
+
+ if (side2_bits < 8 ) {
+ end_of_memory += (1 << side2_bits);
+ }
+#if HAVE_STRING_SUPPORT
+ print_debug("end_of_memory: "); print_debug_hex32(end_of_memory); print_debug("\n");
+#endif
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, drb_reg +1, end_of_memory);
+
+ drb_reg += 2;
+ device += SMBUS_MEM_DEVICE_INC;
+ }
+}
+
+void sdram_no_memory(void)
+{
+#if HAVE_STRING_SUPPORT
+ print_err("No memory!!\n");
+#endif
+ while(1) ;
+}
+
+static void spd_set_dramc(void)
+{
+ /*
+ * Effects: Uses serial presence detect to set the
+ * DRAMC register, which records if ram is registerd or not,
+ * and controls the refresh rate.
+ * The refresh rate is not set here, as memory refresh
+ * cannot be enbaled until after memory is initialized.
+ * see spd_enable_refresh.
+ */
+ /* auto detect if ram is registered or not. */
+ /* The DRAMC register also contorls the refresh rate but we can't
+ * set that here because we must leave refresh disabled.
+ * see: spd_enable_refresh
+ */
+ /* Find the first dimm and assume the rest are the same */
+ /* FIXME Check for illegal/unsupported ram configurations and abort */
+ unsigned device;
+ int byte;
+ unsigned dramc;
+ byte = -1;
+ device = SMBUS_MEM_DEVICE_START;
+
+ while ((byte < 0) && (device <= SMBUS_MEM_DEVICE_END)) {
+ byte = smbus_read_byte(device, 21);
+ device += SMBUS_MEM_DEVICE_INC;
+ }
+ if (byte < 0) {
+ /* We couldn't find anything we must have no memory */
+ sdram_no_memory();
+ }
+ dramc = 0x8;
+ if ((byte & 0x12) != 0) {
+ /* this is a registered part.
+ * observation: for register parts, BIOS zeros (!)
+ * registers CA-CC. This has an undocumented meaning.
+ */
+ /* But it does make sense the oppisite of registered
+ * sdram is buffered and 0xca - 0xcc control the buffers.
+ * Clearing them aparently disables them.
+ */
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xca, 0);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xcb, 0);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xcc, 0);
+ dramc = 0x10;
+ }
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57, dramc);
+}
+
+static void spd_enable_refresh(void)
+{
+ /*
+ * Effects: Uses serial presence detect to set the
+ * refresh rate in the DRAMC register.
+ * see spd_set_dramc for the other values.
+ * FIXME: Check for illegal/unsupported ram configurations and abort
+ */
+#if HAVE_STATIC_ARRAY_SUPPORT
+ static const unsigned char refresh_rates[] = {
+ 0x01, /* Normal 15.625 us -> 15.6 us */
+ 0x05, /* Reduced(.25X) 3.9 us -> 7.8 us */
+ 0x05, /* Reduced(.5X) 7.8 us -> 7.8 us */
+ 0x02, /* Extended(2x) 31.3 us -> 31.2 us */
+ 0x03, /* Extended(4x) 62.5 us -> 62.4 us */
+ 0x04, /* Extended(8x) 125 us -> 124.8 us */
+ };
+#endif
+ /* Find the first dimm and assume the rest are the same */
+ int status;
+ int byte;
+ unsigned device;
+ unsigned refresh_rate;
+ byte = -1;
+ status = -1;
+ device = SMBUS_MEM_DEVICE_START;
+ while ((byte < 0) && (device <= SMBUS_MEM_DEVICE_END)) {
+ byte = smbus_read_byte(device, 12);
+ device += SMBUS_MEM_DEVICE_INC;
+ }
+ if (byte < 0) {
+ /* We couldn't find anything we must have no memory */
+ sdram_no_memory();
+ }
+ byte &= 0x7f;
+ /* Default refresh rate be conservative */
+ refresh_rate = 5;
+ /* see if the ram refresh is a supported one */
+ if (byte < 6) {
+#if HAVE_STATIC_ARRAY_SUPPORT
+ refresh_rate = refresh_rates[byte];
+#endif
+ }
+ byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57);
+ byte &= 0xf8;
+ byte |= refresh_rate;
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57, byte);
+}
+
+static void spd_set_sdramc(void)
+{
+ return;
+}
+
+static void spd_set_rps(void)
+{
+ /*
+ * Effects: Uses serial presence detect to set the row size
+ * on a given DIMM
+ * FIXME: Check for illegal/unsupported ram configurations and abort
+ */
+ /* The RPS register holds the size of a ``page'' of DRAM on each DIMM */
+ unsigned page_sizes;
+ unsigned index;
+ unsigned device;
+ unsigned char dramc;
+ /* default all page sizes to 2KB */
+ page_sizes = 0;
+ index = 0;
+ device = SMBUS_MEM_DEVICE_START;
+ for(; device <= SMBUS_MEM_DEVICE_END; index += 4, device += SMBUS_MEM_DEVICE_INC) {
+ unsigned int status;
+ unsigned int byte;
+ int page_size;
+
+ byte = smbus_read_byte(device, 3);
+ if (byte < 0) continue;
+
+ /* I now have the row page size as a power of 2 */
+ page_size = byte & 0xf;
+ /* make it in multiples of 2Kb */
+ page_size -= 11;
+
+ if (page_size <= 0) continue;
+
+ /* FIXME: do something with page sizes greather than 8KB!! */
+ page_sizes |= (page_size << index);
+
+ /* side two */
+ byte = smbus_read_byte(device, 5);
+ if (byte <= 1) continue;
+
+ /* For now only handle the symmetrical case */
+ page_sizes |= (page_size << (index +2));
+ }
+ /* next block is for Ron's attempt to get registered to work. */
+ /* we have just verified that we have to have this code. It appears that
+ * the registered SDRAMs do indeed set the RPS wrong. sheesh.
+ */
+ /* at this point, page_sizes holds the RPS for all ram.
+ * we have verified that for registered DRAM the values are
+ * 1/2 the size they should be. So we test for registered
+ * and then double the sizes if needed.
+ */
+
+ dramc = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57);
+ if (dramc & 0x10) {
+ /* registered */
+
+ /* BIOS makes weird page size for registered! */
+ /* what we have found is you need to set the EVEN banks to
+ * twice the size. Fortunately there is a very easy way to
+ * do this. First, read the WORD value of register 0x74.
+ */
+ page_sizes += 0x1111;
+ }
+
+ pcibios_write_config_word(I440GX_BUS, I440GX_DEVFN, 0x74, page_sizes);
+}
+
+static void spd_set_pgpol(void)
+{
+ /*
+ * Effects: Uses serial presence detect to set the number of banks
+ * on a given DIMM
+ * FIXME: Check for illegal/unsupported ram configurations and abort
+ */
+ /* The PGPOL register stores the number of logical banks per DIMM,
+ * and number of clocks the DRAM controller waits in the idle
+ * state.
+ */
+ unsigned device;
+ unsigned bank_sizes;
+ unsigned bank;
+ unsigned reg;
+ /* default all bank counts 2 */
+ bank_sizes = 0;
+ bank = 0;
+ device = SMBUS_MEM_DEVICE_START;
+ for(; device <= SMBUS_MEM_DEVICE_END;
+ bank += 2, device += SMBUS_MEM_DEVICE_INC) {
+ int byte;
+
+ /* logical banks */
+ byte = smbus_read_byte(device, 17);
+ if (byte < 0) continue;
+ if (byte < 4) continue;
+ bank_sizes |= (1 << bank);
+
+ /* side 2 */
+ /* Number of physical banks */
+ byte = smbus_read_byte(device, 5);
+ if (byte <= 1) continue;
+ /* for now only handle the symmetrical case */
+ bank_sizes |= (1 << (bank +1));
+ }
+ reg = bank_sizes << 8;
+ reg |= 0x7; /* 32 clocks idle time */
+ pcibios_write_config_word(I440GX_BUS, I440GX_DEVFN, 0x78, reg);
+}
+
+static void spd_set_nbxcfg(void)
+{
+ /*
+ * Effects: Uses serial presence detect to set the
+ * ECC support flags in the NBXCFG register
+ * FIXME: Check for illegal/unsupported ram configurations and abort
+ */
+ unsigned reg;
+ unsigned index;
+ unsigned device;
+
+ /* Say all dimms have no ECC support */
+ reg = 0xff;
+ index = 0;
+
+ device = SMBUS_MEM_DEVICE_START;
+ for(; device <= SMBUS_MEM_DEVICE_END; index += 2, device += SMBUS_MEM_DEVICE_INC) {
+ int byte;
+
+ byte = smbus_read_byte(device, 11);
+ if (byte < 0) continue;
+#if !USE_ECC
+ byte = 0; /* Disable ECC */
+#endif
+ /* 0 == None, 1 == Parity, 2 == ECC */
+ if (byte != 2) continue;
+ reg ^= (1 << index);
+
+ /* side two */
+ /* number of physical banks */
+ byte = smbus_read_byte(device, 5);
+ if (byte <= 1) continue;
+ /* There is only the symmetrical case */
+ reg ^= (1 << (index +1));
+ }
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x53, reg);
+ /* Now see if reg is 0xff. If it is we are done. If not,
+ * we need to set 0x18 into regster 0x50.l
+ * we will do this in two steps, first or in 0x80 to 0x50.b,
+ * then or in 0x1 to 0x51.b
+ */
+#if HAVE_STRING_SUPPORT
+ print_debug("spd_set_nbxcfg reg="); print_debug_hex8(reg); print_debug("\n");
+#endif
+ if (reg != 0xff) {
+ unsigned char byte;
+ byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x50);
+ byte |= 0x80;
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x50, byte);
+ byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x51);
+ byte |= 1;
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x51, byte);
+ /* try this.
+ * We should be setting bit 2 in register 76 and we're not
+ * technically we should see if CL=2 for the ram,
+ * but registered is so screwed up that it's kind of a lost
+ * cause.
+ */
+ byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76);
+ byte |= 4;
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76, byte);
+#if HAVE_STRING_SUPPORT
+ print_debug("spd_set_nbxcfg 0x76.b="); print_debug_hex8(byte); print_debug("\n");
+#endif
+ }
+}
+
+void sdram_set_spd_registers(void)
+{
+ spd_set_drb();
+ spd_set_dramc();
+ spd_set_rps();
+ spd_set_sdramc();
+ spd_set_pgpol();
+ spd_set_nbxcfg();
+}
+
+void sdram_first_normal_reference(void)
+{
+ return;
+}
+
+void sdram_special_finishup(void)
+{
+ return;
+}
+
+static void set_ram_command(unsigned command)
+{
+ unsigned char byte;
+ command &= 0x7;
+ byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76);
+ byte &= 0x1f;
+ byte |= (command << 5);
+ pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76, byte);
+#if HAVE_STRING_SUPPORT
+ print_debug("set_ram_command 0x76.b="); print_debug_hex8(byte); print_debug("\n");
+#endif
+}
+
+#define RAM_COMMAND_NONE 0x0
+#define RAM_COMMAND_NOOP 0x1
+#define RAM_COMMAND_PRECHARGE 0x2
+#define RAM_COMMAND_MRS 0x3
+#define RAM_COMMAND_CBR 0x4
+
+void sdram_set_command_none(void)
+{
+ set_ram_command(RAM_COMMAND_NONE);
+}
+void sdram_set_command_noop(void)
+{
+ set_ram_command(RAM_COMMAND_NOOP);
+}
+void sdram_set_command_precharge(void)
+{
+ set_ram_command(RAM_COMMAND_PRECHARGE);
+}
+
+static unsigned long dimm_base(int n)
+{
+ unsigned char byte;
+ unsigned long result;
+ if (n == 0) {
+ return 0;
+ }
+
+ byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x60 + (n - 1));
+ result = byte;
+ result <<= 23;
+ return result;
+}
+
+static void dimms_read(unsigned long offset)
+{
+ int i;
+ for(i = 0; i < 8; i++) {
+ unsigned long dummy;
+ unsigned long addr;
+ unsigned long next_base;
+
+ next_base = dimm_base(i +1);
+ addr = dimm_base(i);
+ if (addr == next_base) {
+ continue;
+ }
+ addr += offset;
+#if HAVE_STRING_SUPPORT
+ print_debug("Reading ");
+ print_debug_hex32(addr);
+ 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 ");
+ print_debug_hex32(addr ^ 0xddf8);
+ 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 ");
+ print_debug_hex32(addr);
+ print_debug_hex32(addr ^ 0xddf8);
+ print_debug("\n");
+#endif
+ }
+}
+
+void sdram_set_command_cbr(void)
+{
+ set_ram_command(RAM_COMMAND_CBR);
+}
+
+void sdram_assert_command(void)
+{
+ dimms_read(0x400);
+}
+
+void sdram_set_mode_register(void)
+{
+ unsigned char byte;
+ unsigned cas_mode;
+ set_ram_command(RAM_COMMAND_MRS);
+ byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76);
+ cas_mode = byte & 0x4;
+ cas_mode ^= 4;
+ cas_mode <<= 2;
+ cas_mode |= 0x2a;
+ cas_mode <<= 3;
+ dimms_read(cas_mode);
+}
+
+void sdram_enable_refresh(void)
+{
+ spd_enable_refresh();
+}
+
+
+unsigned long sdram_get_ecc_size_bytes(void)
+{
+ unsigned char byte;
+ unsigned long size;
+ /* FIXME handle the no ram case. */
+ /* Read the RAM SIZE */
+ byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x67);
+ /* Convert it to bytes */
+ size = byte;
+ size <<= 23;
+#if !USE_ECC
+ size = 0;
+#endif
+ return size;
+}
+
+/* Dummy udelay code acting as a place holder... */
+void udelay(int count)
+{
+ int i;
+ i = 5;
+}
+
+void sdram_enable(void)
+{
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram Enable 1\n");
+#endif
+
+ /* noop command */
+ sdram_set_command_noop();
+ udelay(200);
+ sdram_assert_command();
+
+ /* Precharge all */
+ sdram_set_command_precharge();
+ sdram_assert_command();
+
+ /* wait until the all banks idle state... */
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram Enable 2\n");
+#endif
+
+ /* Now we need 8 AUTO REFRESH / CBR cycles to be performed */
+
+ sdram_set_command_cbr();
+ sdram_assert_command();
+ sdram_assert_command();
+ sdram_assert_command();
+ sdram_assert_command();
+ sdram_assert_command();
+ sdram_assert_command();
+ sdram_assert_command();
+ sdram_assert_command();
+
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram Enable 3\n");
+#endif
+
+ /* mode register set */
+ sdram_set_mode_register();
+ /* MAx[14:0] lines,
+ * MAx[2:0 ] 010 == burst mode of 4
+ * MAx[3:3 ] 1 == interleave wrap type
+ * MAx[4:4 ] == CAS# latency bit
+ * MAx[6:5 ] == 01
+ * MAx[12:7] == 0
+ */
+
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram Enable 4\n");
+#endif
+
+ /* normal operation */
+ sdram_set_command_none();
+
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram Enable 5\n");
+#endif
+}
+
+/* Setup SDRAM */
+void sdram_initialize(void)
+{
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram1\n");
+#endif
+ /* Set the registers we can set once to reasonable values */
+ sdram_set_registers();
+
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram2\n");
+#endif
+ /* Now setup those things we can auto detect */
+ sdram_set_spd_registers();
+
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram3\n");
+#endif
+ /* Now that everything is setup enable the SDRAM.
+ * Some chipsets do the work for use while on others
+ * we need to it by hand.
+ */
+ sdram_enable();
+
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram4\n");
+#endif
+ sdram_first_normal_reference();
+
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram5\n");
+#endif
+ sdram_enable_refresh();
+ sdram_special_finishup();
+
+#if HAVE_STRING_SUPPORT
+ print_debug("Ram6\n");
+#endif
+}
diff --git a/util/romcc/tests/raminit_test7.c b/util/romcc/tests/raminit_test7.c
new file mode 100644
index 0000000000..be62d30573
--- /dev/null
+++ b/util/romcc/tests/raminit_test7.c
@@ -0,0 +1,2805 @@
+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;
+
+static inline unsigned long apic_read(unsigned long reg)
+{
+ return *((volatile unsigned long *)(0xfee00000 +reg));
+}
+static inline void apic_write(unsigned long reg, unsigned long v)
+{
+ *((volatile unsigned long *)(0xfee00000 +reg)) = v;
+}
+static inline void apic_wait_icr_idle(void)
+{
+ do { } while ( apic_read( 0x300 ) & 0x01000 );
+}
+
+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 inline void outsb(uint16_t port, const void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; outsb "
+ : "=S" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+static inline void outsw(uint16_t port, const void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; outsw "
+ : "=S" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+static inline void outsl(uint16_t port, const void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; outsl "
+ : "=S" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+static inline void insb(uint16_t port, void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; insb "
+ : "=D" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+static inline void insw(uint16_t port, void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; insw "
+ : "=D" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+static inline void insl(uint16_t port, void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; insl "
+ : "=D" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+static inline void pnp_write_config(unsigned char port, unsigned char value, unsigned char reg)
+{
+ outb(reg, port);
+ outb(value, port +1);
+}
+static inline unsigned char pnp_read_config(unsigned char port, unsigned char reg)
+{
+ outb(reg, port);
+ return inb(port +1);
+}
+static inline void pnp_set_logical_device(unsigned char port, int device)
+{
+ pnp_write_config(port, device, 0x07);
+}
+static inline void pnp_set_enable(unsigned char port, int enable)
+{
+ pnp_write_config(port, enable?0x1:0x0, 0x30);
+}
+static inline int pnp_read_enable(unsigned char port)
+{
+ return !!pnp_read_config(port, 0x30);
+}
+static inline void pnp_set_iobase0(unsigned char port, unsigned iobase)
+{
+ pnp_write_config(port, (iobase >> 8) & 0xff, 0x60);
+ pnp_write_config(port, iobase & 0xff, 0x61);
+}
+static inline void pnp_set_iobase1(unsigned char port, unsigned iobase)
+{
+ pnp_write_config(port, (iobase >> 8) & 0xff, 0x62);
+ pnp_write_config(port, iobase & 0xff, 0x63);
+}
+static inline void pnp_set_irq0(unsigned char port, unsigned irq)
+{
+ pnp_write_config(port, irq, 0x70);
+}
+static inline void pnp_set_irq1(unsigned char port, unsigned irq)
+{
+ pnp_write_config(port, irq, 0x72);
+}
+static inline void pnp_set_drq(unsigned char port, unsigned drq)
+{
+ pnp_write_config(port, drq & 0xff, 0x74);
+}
+static void hlt(void)
+{
+ __builtin_hlt();
+}
+typedef __builtin_div_t div_t;
+typedef __builtin_ldiv_t ldiv_t;
+typedef __builtin_udiv_t udiv_t;
+typedef __builtin_uldiv_t uldiv_t;
+static div_t div(int numer, int denom)
+{
+ return __builtin_div(numer, denom);
+}
+static ldiv_t ldiv(long numer, long denom)
+{
+ return __builtin_ldiv(numer, denom);
+}
+static udiv_t udiv(unsigned numer, unsigned denom)
+{
+ return __builtin_udiv(numer, denom);
+}
+static uldiv_t uldiv(unsigned long numer, unsigned long denom)
+{
+ return __builtin_uldiv(numer, denom);
+}
+int log2(int value)
+{
+
+ return __builtin_bsr(value);
+}
+typedef unsigned device_t;
+static unsigned char pci_read_config8(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = dev | where;
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inb(0xCFC + (addr & 3));
+}
+static unsigned short pci_read_config16(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = dev | where;
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inw(0xCFC + (addr & 2));
+}
+static unsigned int pci_read_config32(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = dev | where;
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inl(0xCFC);
+}
+static void pci_write_config8(device_t dev, unsigned where, unsigned char value)
+{
+ unsigned addr;
+ addr = dev | where;
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outb(value, 0xCFC + (addr & 3));
+}
+static void pci_write_config16(device_t dev, unsigned where, unsigned short value)
+{
+ unsigned addr;
+ addr = dev | where;
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outw(value, 0xCFC + (addr & 2));
+}
+static void pci_write_config32(device_t dev, unsigned where, unsigned int value)
+{
+ unsigned addr;
+ addr = dev | where;
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outl(value, 0xCFC);
+}
+static device_t pci_locate_device(unsigned pci_id, device_t dev)
+{
+ for(; dev <= ( ((( 255 ) & 0xFF) << 16) | ((( 31 ) & 0x1f) << 11) | ((( 7 ) & 0x7) << 8)) ; dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) {
+ unsigned int id;
+ id = pci_read_config32(dev, 0);
+ if (id == pci_id) {
+ return dev;
+ }
+ }
+ return (0xffffffffU) ;
+}
+
+
+
+
+
+static int uart_can_tx_byte(void)
+{
+ return inb(1016 + 0x05 ) & 0x20;
+}
+static void uart_wait_to_tx_byte(void)
+{
+ while(!uart_can_tx_byte())
+ ;
+}
+static void uart_wait_until_sent(void)
+{
+ while(!(inb(1016 + 0x05 ) & 0x40))
+ ;
+}
+static void uart_tx_byte(unsigned char data)
+{
+ uart_wait_to_tx_byte();
+ outb(data, 1016 + 0x00 );
+
+ uart_wait_until_sent();
+}
+static void uart_init(void)
+{
+
+ outb(0x0, 1016 + 0x01 );
+
+ outb(0x01, 1016 + 0x02 );
+
+ outb(0x80 | 3 , 1016 + 0x03 );
+ outb((115200/ 115200 ) & 0xFF, 1016 + 0x00 );
+ outb(((115200/ 115200 ) >> 8) & 0xFF, 1016 + 0x01 );
+ outb(3 , 1016 + 0x03 );
+}
+
+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 do_console_tx_string(const char *str) __attribute__((noinline))
+{
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ __console_tx_byte(ch);
+ }
+}
+static void __console_tx_string(int loglevel, const char *str)
+{
+ if (8 > loglevel) {
+ do_console_tx_string(str);
+ }
+}
+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); }
+static void console_init(void)
+{
+ static const char console_test[] =
+ "\r\n\r\nLinuxBIOS-"
+ "1.1.4"
+ ".0Fallback"
+ " "
+ "Thu Oct 9 20:29:48 MDT 2003"
+ " starting...\r\n";
+ print_info(console_test);
+}
+static void die(const char *str)
+{
+ print_emerg(str);
+ do {
+ hlt();
+ } while(1);
+}
+static void write_phys(unsigned long addr, unsigned long value)
+{
+ asm volatile(
+ "movnti %1, (%0)"
+ :
+ : "r" (addr), "r" (value)
+ :
+ );
+}
+static unsigned long read_phys(unsigned long addr)
+{
+ volatile unsigned long *ptr;
+ ptr = (void *)addr;
+ return *ptr;
+}
+static 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)) {
+ print_debug_hex32(addr);
+ print_debug("\r");
+ }
+ write_phys(addr, addr);
+ };
+
+ print_debug_hex32(addr);
+ print_debug("\r\nDRAM filled\r\n");
+}
+static 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)) {
+ 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 ram_check(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.\r\n");
+}
+static int enumerate_ht_chain(unsigned link)
+{
+
+ unsigned next_unitid, last_unitid;
+ int reset_needed = 0;
+ 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 ) & 0x7) << 8)) , 0x00 );
+
+ 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 ) & 0x7) << 8)) , 0x0e );
+ pos = 0;
+ hdr_type &= 0x7f;
+ if ((hdr_type == 0 ) ||
+ (hdr_type == 1 )) {
+ pos = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x34 );
+ }
+ while(pos != 0) {
+ uint8_t cap;
+ cap = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 0 );
+ if (cap == 0x08 ) {
+ uint16_t flags;
+ flags = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 2 );
+ 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 ) & 0x7) << 8)) , pos + 2 , flags);
+ next_unitid += count;
+ break;
+ }
+ }
+ pos = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 1 );
+ }
+ } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
+ return reset_needed;
+}
+static void enable_smbus(void)
+{
+ device_t dev;
+ dev = pci_locate_device((((( 0x746b ) & 0xFFFF) << 16) | (( 0x1022 ) & 0xFFFF)) , 0);
+ if (dev == (0xffffffffU) ) {
+ die("SMBUS controller not found\r\n");
+ }
+ uint8_t enable;
+ print_debug("SMBus controller enabled\r\n");
+ pci_write_config32(dev, 0x58, 0x0f00 | 1);
+ enable = pci_read_config8(dev, 0x41);
+ pci_write_config8(dev, 0x41, enable | (1 << 7));
+
+ outw(inw(0x0f00 + 0xe0 ), 0x0f00 + 0xe0 );
+}
+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(0x0f00 + 0xe0 );
+ if ((val & 0x800) == 0) {
+ break;
+ }
+ if(loops == ((100*1000*10) / 2)) {
+ outw(inw(0x0f00 + 0xe0 ),
+ 0x0f00 + 0xe0 );
+ }
+ } while(--loops);
+ return loops?0:-2;
+}
+static int smbus_wait_until_done(void)
+{
+ unsigned long loops;
+ loops = (100*1000*10) ;
+ do {
+ unsigned short val;
+ smbus_delay();
+
+ val = inw(0x0f00 + 0xe0 );
+ if (((val & 0x8) == 0) | ((val & 0x437) != 0)) {
+ break;
+ }
+ } while(--loops);
+ return loops?0:-3;
+}
+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 -2;
+ }
+
+
+
+ outw(inw(0x0f00 + 0xe2 ) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), 0x0f00 + 0xe2 );
+
+ outw(((device & 0x7f) << 1) | 1, 0x0f00 + 0xe4 );
+
+ outb(address & 0xFF, 0x0f00 + 0xe8 );
+
+ outw((inw(0x0f00 + 0xe2 ) & ~7) | (0x2), 0x0f00 + 0xe2 );
+
+
+ outw(inw(0x0f00 + 0xe0 ), 0x0f00 + 0xe0 );
+
+ outw(0, 0x0f00 + 0xe6 );
+
+ outw((inw(0x0f00 + 0xe2 ) | (1 << 3)), 0x0f00 + 0xe2 );
+
+ if (smbus_wait_until_done() < 0) {
+ return -3;
+ }
+ global_status_register = inw(0x0f00 + 0xe0 );
+
+ byte = inw(0x0f00 + 0xe6 ) & 0xff;
+ if (global_status_register != (1 << 4)) {
+ return -1;
+ }
+ return byte;
+}
+static void smbus_write_byte(unsigned device, unsigned address, unsigned char val)
+{
+ return;
+}
+struct mem_controller {
+ unsigned node_id;
+ device_t f0, f1, f2, f3;
+ uint8_t channel0[4];
+ uint8_t channel1[4];
+};
+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);
+}
+struct tsc_struct {
+ unsigned lo;
+ unsigned hi;
+};
+typedef struct tsc_struct tsc_t;
+static tsc_t rdtsc(void)
+{
+ tsc_t res;
+ asm ("rdtsc"
+ : "=a" (res.lo), "=d"(res.hi)
+ :
+ :
+ );
+ return res;
+}
+void init_timer(void)
+{
+
+ apic_write(0x320 , (1 << 17)|(1<< 16)|(0 << 12)|(0 << 0));
+
+ apic_write(0x3E0 , 0xB );
+
+ apic_write(0x380 , 0xffffffff);
+}
+void udelay(unsigned usecs)
+{
+ uint32_t start, value, ticks;
+
+ ticks = usecs * 200;
+ start = apic_read(0x390 );
+ do {
+ value = apic_read(0x390 );
+ } while((start - value) < ticks);
+
+}
+void mdelay(unsigned msecs)
+{
+ unsigned i;
+ for(i = 0; i < msecs; i++) {
+ udelay(1000);
+ }
+}
+void delay(unsigned secs)
+{
+ unsigned i;
+ for(i = 0; i < secs; i++) {
+ mdelay(1000);
+ }
+}
+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));
+ return bsp;
+}
+static int cpu_init_detected(void)
+{
+ unsigned long htic;
+ htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c );
+ return !!(htic & (1<<6) );
+}
+static int bios_reset_detected(void)
+{
+ unsigned long htic;
+ htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c );
+ return (htic & (1<<4) ) && !(htic & (1<<5) );
+}
+static int cold_reset_detected(void)
+{
+ unsigned long htic;
+ htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c );
+ return !(htic & (1<<4) );
+}
+static void distinguish_cpu_resets(unsigned node_id)
+{
+ uint32_t htic;
+ device_t device;
+ device = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 + node_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ;
+ htic = pci_read_config32(device, 0x6c );
+ htic |= (1<<4) | (1<<5) | (1<<6) ;
+ pci_write_config32(device, 0x6c , htic);
+}
+static void set_bios_reset(void)
+{
+ unsigned long htic;
+ htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c );
+ htic &= ~(1<<5) ;
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c , htic);
+}
+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;
+ for(dev = ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ;
+ dev <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 0x7 ) & 0x7) << 8)) ;
+ dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) {
+ uint32_t id;
+ id = pci_read_config32(dev, 0x00 );
+ if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
+ continue;
+ }
+ 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_pci_devices(void)
+{
+ device_t dev;
+ for(dev = ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ;
+ dev <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 0x7 ) & 0x7) << 8)) ;
+ dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) {
+ uint32_t id;
+ id = pci_read_config32(dev, 0x00 );
+ if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
+ continue;
+ }
+ dump_pci_device(dev);
+ }
+}
+static void dump_spd_registers(const struct mem_controller *ctrl)
+{
+ int i;
+ print_debug("\r\n");
+ for(i = 0; i < 4; i++) {
+ unsigned device;
+ device = ctrl->channel0[i];
+ if (device) {
+ int j;
+ print_debug("dimm: ");
+ print_debug_hex8(i);
+ print_debug(".0: ");
+ print_debug_hex8(device);
+ for(j = 0; j < 256; j++) {
+ int status;
+ unsigned char byte;
+ if ((j & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(j);
+ print_debug(": ");
+ }
+ status = smbus_read_byte(device, j);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ break;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug_char(' ');
+ }
+ print_debug("\r\n");
+ }
+ device = ctrl->channel1[i];
+ if (device) {
+ int j;
+ print_debug("dimm: ");
+ print_debug_hex8(i);
+ print_debug(".1: ");
+ print_debug_hex8(device);
+ for(j = 0; j < 256; j++) {
+ int status;
+ unsigned char byte;
+ if ((j & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(j);
+ print_debug(": ");
+ }
+ status = smbus_read_byte(device, j);
+ 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 unsigned int cpuid(unsigned int op)
+{
+ unsigned int ret;
+ unsigned dummy2,dummy3,dummy4;
+ asm volatile (
+ "cpuid"
+ : "=a" (ret), "=b" (dummy2), "=c" (dummy3), "=d" (dummy4)
+ : "a" (op)
+ );
+ return ret;
+}
+static int is_cpu_rev_a0(void)
+{
+ return (cpuid(1) & 0xffff) == 0x0f10;
+}
+static int is_cpu_pre_c0(void)
+{
+ return (cpuid(1) & 0xffef) < 0x0f48;
+}
+static void memreset_setup(void)
+{
+ if (is_cpu_pre_c0()) {
+
+ outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0x0f00 + 0xc0 + 28);
+
+ outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0x0f00 + 0xc0 + 29);
+ }
+ else {
+
+ outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0x0f00 + 0xc0 + 29);
+ }
+}
+static void memreset(int controllers, const struct mem_controller *ctrl)
+{
+ if (is_cpu_pre_c0()) {
+ udelay(800);
+
+ outb((0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0x0f00 + 0xc0 + 28);
+ udelay(90);
+ }
+}
+static unsigned int generate_row(uint8_t node, uint8_t row, uint8_t maxnodes)
+{
+
+ uint32_t ret=0x00010101;
+ static const unsigned int rows_2p[2][2] = {
+ { 0x00050101, 0x00010404 },
+ { 0x00010404, 0x00050101 }
+ };
+ if(maxnodes>2) {
+ print_debug("this mainboard is only designed for 2 cpus\r\n");
+ maxnodes=2;
+ }
+ if (!(node>=maxnodes || row>=maxnodes)) {
+ ret=rows_2p[node][row];
+ }
+ return ret;
+}
+static inline int spd_read_byte(unsigned device, unsigned address)
+{
+ return smbus_read_byte(device, address);
+}
+
+static void coherent_ht_mainboard(unsigned cpus)
+{
+}
+
+void cpu_ldtstop(unsigned cpus)
+{
+ uint32_t tmp;
+ device_t dev;
+ unsigned cnt;
+ for(cnt=0; cnt<cpus; cnt++) {
+
+ pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0x81,0x23);
+
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0xd4,0x00000701);
+
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0xd8,0x00000000);
+
+ tmp=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,0x90);
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,0x90, tmp | (1<<24) );
+ }
+}
+
+
+
+
+
+static void setup_resource_map(const unsigned int *register_values, int max)
+{
+ int i;
+ print_debug("setting up resource map....\r\n");
+ for(i = 0; i < max; i += 3) {
+ device_t dev;
+ unsigned where;
+ unsigned long reg;
+ dev = register_values[i] & ~0xff;
+ where = register_values[i] & 0xff;
+ reg = pci_read_config32(dev, where);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2];
+ pci_write_config32(dev, where, reg);
+ }
+ print_debug("done.\r\n");
+}
+static void setup_default_resource_map(void)
+{
+ static const unsigned int register_values[] = {
+
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x0000f8f8, 0x00000000,
+ ( ((( 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,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x84 ) & 0xFF)) , 0x00000048, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x8C ) & 0xFF)) , 0x00000048, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0x00000048, 0x00000000,
+ ( ((( 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, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xBC ) & 0xFF)) , 0x00000048, 0x00ffff00,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x80 ) & 0xFF)) , 0x000000f0, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x88 ) & 0xFF)) , 0x000000f0, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0x000000f0, 0x00000000,
+ ( ((( 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, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB8 ) & 0xFF)) , 0x000000f0, 0x00fc0003,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC4 ) & 0xFF)) , 0xFE000FC8, 0x01fff000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xCC ) & 0xFF)) , 0xFE000FC8, 0x00000000,
+ ( ((( 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,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC0 ) & 0xFF)) , 0xFE000FCC, 0x00000003,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC8 ) & 0xFF)) , 0xFE000FCC, 0x00000000,
+ ( ((( 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,
+
+ ( ((( 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 max;
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ setup_resource_map(register_values, max);
+}
+static void sdram_set_registers(const struct mem_controller *ctrl)
+{
+ static const unsigned int register_values[] = {
+
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x0000f8f8, 0x00000000,
+ ( ((( 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,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x001f01fe, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x001f01fe, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x001f01fe, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x001f01fe, 0x00000000,
+ ( ((( 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,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0xC01f01ff, 0x00000000,
+ ( ((( 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,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x80 ) & 0xFF)) , 0xffff8888, 0x00000000,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x88 ) & 0xFF)) , 0xe8088008, 0x02522001 ,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x8c ) & 0xFF)) , 0xff8fe08e, (0 << 20)|(0 << 8)|(0 << 4)|(0 << 0),
+
+ ( ((( 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)|(0 << 18)|(1 << 17)|(0 << 16)|
+ (2 << 14)|(0 << 13)|(0 << 12)|
+ (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)|
+ (0 << 3) |(0 << 1) |(0 << 0),
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0xc180f0f0,
+ (0 << 29)|(0 << 28)|(0 << 27)|(0 << 26)|(0 << 25)|
+ (0 << 20)|(0 << 19)|(3 << 16)|(0 << 8)|(0 << 0),
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0xfc00ffff, 0x00000000,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0xffe0e0e0, 0x00000000,
+
+ ( ((( 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,
+
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0xffff8000, 0x00000f70,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0xffffff80, 0x00000002,
+ ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0x0000000f, 0x00068300,
+ };
+ int i;
+ int max;
+ print_debug("setting up CPU");
+ print_debug_hex8(ctrl->node_id);
+ print_debug(" northbridge registers\r\n");
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ for(i = 0; i < max; i += 3) {
+ device_t dev;
+ unsigned where;
+ unsigned long reg;
+ dev = (register_values[i] & ~0xff) - ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) + ctrl->f0;
+ where = register_values[i] & 0xff;
+ reg = pci_read_config32(dev, where);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2];
+ pci_write_config32(dev, where, reg);
+ }
+ print_debug("done.\r\n");
+}
+static int is_dual_channel(const struct mem_controller *ctrl)
+{
+ uint32_t dcl;
+ dcl = pci_read_config32(ctrl->f2, 0x90 );
+ return dcl & (1<<16) ;
+}
+static int is_opteron(const struct mem_controller *ctrl)
+{
+
+ uint32_t nbcap;
+ nbcap = pci_read_config32(ctrl->f3, 0xE8 );
+ return !!(nbcap & 0x0001 );
+}
+static int is_registered(const struct mem_controller *ctrl)
+{
+
+ uint32_t dcl;
+ dcl = pci_read_config32(ctrl->f2, 0x90 );
+ return !(dcl & (1<<18) );
+}
+struct dimm_size {
+ unsigned long side1;
+ unsigned long side2;
+};
+static struct dimm_size spd_get_dimm_size(unsigned device)
+{
+
+ struct dimm_size sz;
+ int value, low;
+ sz.side1 = 0;
+ sz.side2 = 0;
+
+ value = spd_read_byte(device, 3);
+ if (value < 0) goto out;
+ sz.side1 += value & 0xf;
+ value = spd_read_byte(device, 4);
+ if (value < 0) goto out;
+ sz.side1 += value & 0xf;
+ value = spd_read_byte(device, 17);
+ if (value < 0) goto out;
+ sz.side1 += log2(value & 0xff);
+
+ value = spd_read_byte(device, 7);
+ if (value < 0) goto out;
+ value &= 0xff;
+ value <<= 8;
+
+ low = spd_read_byte(device, 6);
+ if (low < 0) goto out;
+ value = value | (low & 0xff);
+ sz.side1 += log2(value);
+
+ value = spd_read_byte(device, 5);
+ if (value <= 1) goto out;
+
+ sz.side2 = sz.side1;
+ value = spd_read_byte(device, 3);
+ if (value < 0) goto out;
+ if ((value & 0xf0) == 0) goto out;
+ sz.side2 -= (value & 0x0f);
+ sz.side2 += ((value >> 4) & 0x0f);
+ value = spd_read_byte(device, 4);
+ if (value < 0) goto out;
+ sz.side2 -= (value & 0x0f);
+ sz.side2 += ((value >> 4) & 0x0f);
+ out:
+ return sz;
+}
+static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz, unsigned index)
+{
+ uint32_t base0, base1, map;
+ uint32_t dch;
+ if (sz.side1 != sz.side2) {
+ sz.side2 = 0;
+ }
+ map = pci_read_config32(ctrl->f2, 0x80 );
+ map &= ~(0xf << (index + 4));
+
+
+ base0 = base1 = 0;
+
+ if (sz.side1 >= (25 +3)) {
+ map |= (sz.side1 - (25 + 3)) << (index *4);
+ base0 = (1 << ((sz.side1 - (25 + 3)) + 21)) | 1;
+ }
+
+ if (sz.side2 >= (25 + 3)) {
+ base1 = (1 << ((sz.side2 - (25 + 3)) + 21)) | 1;
+ }
+
+ if (is_dual_channel(ctrl)) {
+ base0 = (base0 << 1) | (base0 & 1);
+ base1 = (base1 << 1) | (base1 & 1);
+ }
+
+ base0 &= ~0x001ffffe;
+ base1 &= ~0x001ffffe;
+
+ pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+0)<<2), base0);
+ pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+1)<<2), base1);
+ pci_write_config32(ctrl->f2, 0x80 , map);
+
+
+ if (base0) {
+ dch = pci_read_config32(ctrl->f2, 0x94 );
+ dch |= (1 << 26) << index;
+ pci_write_config32(ctrl->f2, 0x94 , dch);
+ }
+}
+static void spd_set_ram_size(const struct mem_controller *ctrl)
+{
+ int i;
+
+ for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ struct dimm_size sz;
+ sz = spd_get_dimm_size(ctrl->channel0[i]);
+ set_dimm_size(ctrl, sz, i);
+ }
+}
+static void route_dram_accesses(const struct mem_controller *ctrl,
+ unsigned long base_k, unsigned long limit_k)
+{
+
+ unsigned node_id;
+ unsigned limit;
+ unsigned base;
+ unsigned index;
+ unsigned limit_reg, base_reg;
+ device_t device;
+ node_id = ctrl->node_id;
+ index = (node_id << 3);
+ limit = (limit_k << 2);
+ limit &= 0xffff0000;
+ limit -= 0x00010000;
+ limit |= ( 0 << 8) | (node_id << 0);
+ base = (base_k << 2);
+ base &= 0xffff0000;
+ base |= (0 << 8) | (1<<1) | (1<<0);
+ limit_reg = 0x44 + index;
+ base_reg = 0x40 + index;
+ for(device = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ; device <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ; device += ( ((( 0 ) & 0xFF) << 16) | ((( 1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ) {
+ pci_write_config32(device, limit_reg, limit);
+ pci_write_config32(device, base_reg, base);
+ }
+}
+static void set_top_mem(unsigned tom_k)
+{
+
+ if (!tom_k) {
+ set_bios_reset();
+ print_debug("No memory - reset");
+
+ pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0x04 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , 0x41, 0xf1);
+
+ outb(0x0e, 0x0cf9);
+ }
+
+ print_debug("RAM: 0x");
+ print_debug_hex32(tom_k);
+ print_debug(" KB\r\n");
+
+ msr_t msr;
+ msr.lo = (tom_k & 0x003fffff) << 10;
+ msr.hi = (tom_k & 0xffc00000) >> 22;
+ wrmsr(0xC001001D , msr);
+
+ if (tom_k >= 0x003f0000) {
+ tom_k = 0x3f0000;
+ }
+ msr.lo = (tom_k & 0x003fffff) << 10;
+ msr.hi = (tom_k & 0xffc00000) >> 22;
+ wrmsr(0xC001001A , msr);
+}
+static unsigned long interleave_chip_selects(const struct mem_controller *ctrl)
+{
+
+ static const uint32_t csbase_low[] = {
+ (1 << (13 - 4)),
+ (1 << (14 - 4)),
+ (1 << (14 - 4)),
+ (1 << (15 - 4)),
+ (1 << (15 - 4)),
+ (1 << (16 - 4)),
+ (1 << (16 - 4)),
+ };
+ uint32_t csbase_inc;
+ int chip_selects, index;
+ int bits;
+ int dual_channel;
+ unsigned common_size;
+ uint32_t csbase, csmask;
+
+ chip_selects = 0;
+ common_size = 0;
+ for(index = 0; index < 8; index++) {
+ unsigned size;
+ uint32_t value;
+
+ value = pci_read_config32(ctrl->f2, 0x40 + (index << 2));
+
+
+ if (!(value & 1)) {
+ continue;
+ }
+ chip_selects++;
+ size = value >> 21;
+ if (common_size == 0) {
+ common_size = size;
+ }
+
+ if (common_size != size) {
+ return 0;
+ }
+ }
+
+ bits = log2(chip_selects);
+ if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) {
+ return 0;
+
+ }
+
+ if ((bits == 3) && (common_size == (1 << (32 - 3)))) {
+ print_debug("8 4GB chip selects cannot be interleaved\r\n");
+ return 0;
+ }
+
+ if (is_dual_channel(ctrl)) {
+ csbase_inc = csbase_low[log2(common_size) - 1] << 1;
+ } else {
+ csbase_inc = csbase_low[log2(common_size)];
+ }
+
+ csbase = 0 | 1;
+ csmask = (((common_size << bits) - 1) << 21);
+ csmask |= 0xfe00 & ~((csbase_inc << bits) - csbase_inc);
+ for(index = 0; index < 8; index++) {
+ uint32_t value;
+ value = pci_read_config32(ctrl->f2, 0x40 + (index << 2));
+
+ if (!(value & 1)) {
+ continue;
+ }
+ pci_write_config32(ctrl->f2, 0x40 + (index << 2), csbase);
+ pci_write_config32(ctrl->f2, 0x60 + (index << 2), csmask);
+ csbase += csbase_inc;
+ }
+
+ print_debug("Interleaved\r\n");
+
+ return common_size << (15 + bits);
+}
+static unsigned long order_chip_selects(const struct mem_controller *ctrl)
+{
+ unsigned long tom;
+
+
+ tom = 0;
+ for(;;) {
+
+ unsigned index, canidate;
+ uint32_t csbase, csmask;
+ unsigned size;
+ csbase = 0;
+ canidate = 0;
+ for(index = 0; index < 8; index++) {
+ uint32_t value;
+ value = pci_read_config32(ctrl->f2, 0x40 + (index << 2));
+
+ if (!(value & 1)) {
+ continue;
+ }
+
+
+ if (value <= csbase) {
+ continue;
+ }
+
+
+ if (tom & (1 << (index + 24))) {
+ continue;
+ }
+
+ csbase = value;
+ canidate = index;
+ }
+
+ if (csbase == 0) {
+ break;
+ }
+
+ size = csbase >> 21;
+
+ tom |= (1 << (canidate + 24));
+
+ csbase = (tom << 21) | 1;
+
+ tom += size;
+
+ csmask = ((size -1) << 21);
+ csmask |= 0xfe00;
+
+ pci_write_config32(ctrl->f2, 0x40 + (canidate << 2), csbase);
+
+ pci_write_config32(ctrl->f2, 0x60 + (canidate << 2), csmask);
+
+ }
+
+ return (tom & ~0xff000000) << 15;
+}
+static void order_dimms(const struct mem_controller *ctrl)
+{
+ unsigned long tom, tom_k, base_k;
+ unsigned node_id;
+ tom_k = interleave_chip_selects(ctrl);
+ if (!tom_k) {
+ tom_k = order_chip_selects(ctrl);
+ }
+
+ base_k = 0;
+ for(node_id = 0; node_id < ctrl->node_id; node_id++) {
+ uint32_t limit, base;
+ unsigned index;
+ index = node_id << 3;
+ base = pci_read_config32(ctrl->f1, 0x40 + index);
+
+ if ((base & 3) == 3) {
+ limit = pci_read_config32(ctrl->f1, 0x44 + index);
+ base_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
+ }
+ }
+ tom_k += base_k;
+ route_dram_accesses(ctrl, base_k, tom_k);
+ set_top_mem(tom_k);
+}
+static void disable_dimm(const struct mem_controller *ctrl, unsigned index)
+{
+ print_debug("disabling dimm");
+ print_debug_hex8(index);
+ print_debug("\r\n");
+ pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+0)<<2), 0);
+ pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+1)<<2), 0);
+}
+static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl)
+{
+ int i;
+ int registered;
+ int unbuffered;
+ uint32_t dcl;
+ unbuffered = 0;
+ registered = 0;
+ for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ int value;
+ value = spd_read_byte(ctrl->channel0[i], 21);
+ if (value < 0) {
+ disable_dimm(ctrl, i);
+ continue;
+ }
+
+ if (value & (1 << 1)) {
+ registered = 1;
+ }
+
+ else {
+ unbuffered = 1;
+ }
+ }
+ if (unbuffered && registered) {
+ die("Mixed buffered and registered dimms not supported");
+ }
+ if (unbuffered && is_opteron(ctrl)) {
+ die("Unbuffered Dimms not supported on Opteron");
+ }
+ dcl = pci_read_config32(ctrl->f2, 0x90 );
+ dcl &= ~(1<<18) ;
+ if (unbuffered) {
+ dcl |= (1<<18) ;
+ }
+ pci_write_config32(ctrl->f2, 0x90 , dcl);
+}
+static void spd_enable_2channels(const struct mem_controller *ctrl)
+{
+ int i;
+ uint32_t nbcap;
+
+
+ static const unsigned addresses[] = {
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 9,
+ 11,
+ 13,
+ 17,
+ 18,
+ 21,
+ 23,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 41,
+ 42,
+ };
+ nbcap = pci_read_config32(ctrl->f3, 0xE8 );
+ if (!(nbcap & 0x0001 )) {
+ return;
+ }
+ for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ unsigned device0, device1;
+ int value0, value1;
+ int j;
+ device0 = ctrl->channel0[i];
+ device1 = ctrl->channel1[i];
+ if (!device1)
+ return;
+ for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) {
+ unsigned addr;
+ addr = addresses[j];
+ value0 = spd_read_byte(device0, addr);
+ if (value0 < 0) {
+ break;
+ }
+ value1 = spd_read_byte(device1, addr);
+ if (value1 < 0) {
+ return;
+ }
+ if (value0 != value1) {
+ return;
+ }
+ }
+ }
+ print_debug("Enabling dual channel memory\r\n");
+ uint32_t dcl;
+ dcl = pci_read_config32(ctrl->f2, 0x90 );
+ dcl &= ~(1<<19) ;
+ dcl |= (1<<16) ;
+ pci_write_config32(ctrl->f2, 0x90 , dcl);
+}
+struct mem_param {
+ uint8_t cycle_time;
+ uint8_t divisor;
+ uint8_t tRC;
+ uint8_t tRFC;
+ uint32_t dch_memclk;
+ uint16_t dch_tref4k, dch_tref8k;
+ uint8_t dtl_twr;
+ char name[9];
+};
+static const struct mem_param *get_mem_param(unsigned min_cycle_time)
+{
+ static const struct mem_param speed[] = {
+ {
+ .name = "100Mhz\r\n",
+ .cycle_time = 0xa0,
+ .divisor = (10 <<1),
+ .tRC = 0x46,
+ .tRFC = 0x50,
+ .dch_memclk = 0 << 20 ,
+ .dch_tref4k = 0x00 ,
+ .dch_tref8k = 0x08 ,
+ .dtl_twr = 2,
+ },
+ {
+ .name = "133Mhz\r\n",
+ .cycle_time = 0x75,
+ .divisor = (7<<1)+1,
+ .tRC = 0x41,
+ .tRFC = 0x4B,
+ .dch_memclk = 2 << 20 ,
+ .dch_tref4k = 0x01 ,
+ .dch_tref8k = 0x09 ,
+ .dtl_twr = 2,
+ },
+ {
+ .name = "166Mhz\r\n",
+ .cycle_time = 0x60,
+ .divisor = (6<<1),
+ .tRC = 0x3C,
+ .tRFC = 0x48,
+ .dch_memclk = 5 << 20 ,
+ .dch_tref4k = 0x02 ,
+ .dch_tref8k = 0x0A ,
+ .dtl_twr = 3,
+ },
+ {
+ .name = "200Mhz\r\n",
+ .cycle_time = 0x50,
+ .divisor = (5<<1),
+ .tRC = 0x37,
+ .tRFC = 0x46,
+ .dch_memclk = 7 << 20 ,
+ .dch_tref4k = 0x03 ,
+ .dch_tref8k = 0x0B ,
+ .dtl_twr = 3,
+ },
+ {
+ .cycle_time = 0x00,
+ },
+ };
+ const struct mem_param *param;
+ for(param = &speed[0]; param->cycle_time ; param++) {
+ if (min_cycle_time > (param+1)->cycle_time) {
+ break;
+ }
+ }
+ if (!param->cycle_time) {
+ die("min_cycle_time to low");
+ }
+ print_debug(param->name);
+ return param;
+}
+static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
+{
+
+ const struct mem_param *param;
+ unsigned min_cycle_time, min_latency;
+ int i;
+ uint32_t value;
+ static const int latency_indicies[] = { 26, 23, 9 };
+ static const unsigned char min_cycle_times[] = {
+ [0 ] = 0x50,
+ [1 ] = 0x60,
+ [2 ] = 0x75,
+ [3 ] = 0xa0,
+ };
+ value = pci_read_config32(ctrl->f3, 0xE8 );
+ min_cycle_time = min_cycle_times[(value >> 5 ) & 3 ];
+ min_latency = 2;
+
+ for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ int new_cycle_time, new_latency;
+ int index;
+ int latencies;
+ int latency;
+
+ new_cycle_time = 0xa0;
+ new_latency = 5;
+ latencies = spd_read_byte(ctrl->channel0[i], 18);
+ if (latencies <= 0) continue;
+
+ latency = log2(latencies) -2;
+
+ for(index = 0; index < 3; index++, latency++) {
+ int value;
+ if ((latency < 2) || (latency > 4) ||
+ (!(latencies & (1 << latency)))) {
+ continue;
+ }
+ value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
+ if (value < 0) {
+ continue;
+ }
+
+ if ((value >= min_cycle_time) && (value < new_cycle_time)) {
+ new_cycle_time = value;
+ new_latency = latency;
+ }
+ }
+ if (new_latency > 4){
+ continue;
+ }
+
+ if (new_cycle_time > min_cycle_time) {
+ min_cycle_time = new_cycle_time;
+ }
+
+ if (new_latency > min_latency) {
+ min_latency = new_latency;
+ }
+ }
+
+
+ for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ int latencies;
+ int latency;
+ int index;
+ int value;
+ int dimm;
+ latencies = spd_read_byte(ctrl->channel0[i], 18);
+ if (latencies <= 0) {
+ goto dimm_err;
+ }
+
+ latency = log2(latencies) -2;
+
+ for(index = 0; index < 3; index++, latency++) {
+ if (!(latencies & (1 << latency))) {
+ continue;
+ }
+ if (latency == min_latency)
+ break;
+ }
+
+ if ((latency != min_latency) || (index >= 3)) {
+ goto dimm_err;
+ }
+
+
+ value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
+
+
+ if (value <= min_cycle_time) {
+ continue;
+ }
+
+ dimm_err:
+ disable_dimm(ctrl, i);
+ }
+
+ param = get_mem_param(min_cycle_time);
+
+ value = pci_read_config32(ctrl->f2, 0x94 );
+ value &= ~(0x7 << 20 );
+ value |= param->dch_memclk;
+ pci_write_config32(ctrl->f2, 0x94 , value);
+ static const unsigned latencies[] = { 1 , 5 , 2 };
+
+ value = pci_read_config32(ctrl->f2, 0x88 );
+ value &= ~(0x7 << 0 );
+ value |= latencies[min_latency - 2] << 0 ;
+ pci_write_config32(ctrl->f2, 0x88 , value);
+
+ return param;
+}
+static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ unsigned clocks, old_clocks;
+ uint32_t dtl;
+ int value;
+ value = spd_read_byte(ctrl->channel0[i], 41);
+ if (value < 0) return -1;
+ if ((value == 0) || (value == 0xff)) {
+ value = param->tRC;
+ }
+ clocks = ((value << 1) + param->divisor - 1)/param->divisor;
+ if (clocks < 7 ) {
+ clocks = 7 ;
+ }
+ if (clocks > 22 ) {
+ return -1;
+ }
+ dtl = pci_read_config32(ctrl->f2, 0x88 );
+ old_clocks = ((dtl >> 4 ) & 0xf ) + 7 ;
+ if (old_clocks > clocks) {
+ clocks = old_clocks;
+ }
+ dtl &= ~(0xf << 4 );
+ dtl |= ((clocks - 7 ) << 4 );
+ pci_write_config32(ctrl->f2, 0x88 , dtl);
+ return 0;
+}
+static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ unsigned clocks, old_clocks;
+ uint32_t dtl;
+ int value;
+ value = spd_read_byte(ctrl->channel0[i], 42);
+ if (value < 0) return -1;
+ if ((value == 0) || (value == 0xff)) {
+ value = param->tRFC;
+ }
+ clocks = ((value << 1) + param->divisor - 1)/param->divisor;
+ if (clocks < 9 ) {
+ clocks = 9 ;
+ }
+ if (clocks > 24 ) {
+ return -1;
+ }
+ dtl = pci_read_config32(ctrl->f2, 0x88 );
+ old_clocks = ((dtl >> 8 ) & 0xf ) + 9 ;
+ if (old_clocks > clocks) {
+ clocks = old_clocks;
+ }
+ dtl &= ~(0xf << 8 );
+ dtl |= ((clocks - 9 ) << 8 );
+ pci_write_config32(ctrl->f2, 0x88 , dtl);
+ return 0;
+}
+static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ unsigned clocks, old_clocks;
+ uint32_t dtl;
+ int value;
+ value = spd_read_byte(ctrl->channel0[i], 29);
+ if (value < 0) return -1;
+ clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
+ if (clocks < 2 ) {
+ clocks = 2 ;
+ }
+ if (clocks > 6 ) {
+ return -1;
+ }
+ dtl = pci_read_config32(ctrl->f2, 0x88 );
+ old_clocks = ((dtl >> 12 ) & 0x7 ) + 0 ;
+ if (old_clocks > clocks) {
+ clocks = old_clocks;
+ }
+ dtl &= ~(0x7 << 12 );
+ dtl |= ((clocks - 0 ) << 12 );
+ pci_write_config32(ctrl->f2, 0x88 , dtl);
+ return 0;
+}
+static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ unsigned clocks, old_clocks;
+ uint32_t dtl;
+ int value;
+ value = spd_read_byte(ctrl->channel0[i], 28);
+ if (value < 0) return -1;
+ clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
+ if (clocks < 2 ) {
+ clocks = 2 ;
+ }
+ if (clocks > 4 ) {
+ return -1;
+ }
+ dtl = pci_read_config32(ctrl->f2, 0x88 );
+ old_clocks = ((dtl >> 16 ) & 0x7 ) + 0 ;
+ if (old_clocks > clocks) {
+ clocks = old_clocks;
+ }
+ dtl &= ~(0x7 << 16 );
+ dtl |= ((clocks - 0 ) << 16 );
+ pci_write_config32(ctrl->f2, 0x88 , dtl);
+ return 0;
+}
+static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ unsigned clocks, old_clocks;
+ uint32_t dtl;
+ int value;
+ value = spd_read_byte(ctrl->channel0[i], 30);
+ if (value < 0) return -1;
+ clocks = ((value << 1) + param->divisor - 1)/param->divisor;
+ if (clocks < 5 ) {
+ clocks = 5 ;
+ }
+ if (clocks > 15 ) {
+ return -1;
+ }
+ dtl = pci_read_config32(ctrl->f2, 0x88 );
+ old_clocks = ((dtl >> 20 ) & 0xf ) + 0 ;
+ if (old_clocks > clocks) {
+ clocks = old_clocks;
+ }
+ dtl &= ~(0xf << 20 );
+ dtl |= ((clocks - 0 ) << 20 );
+ pci_write_config32(ctrl->f2, 0x88 , dtl);
+ return 0;
+}
+static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ unsigned clocks, old_clocks;
+ uint32_t dtl;
+ int value;
+ value = spd_read_byte(ctrl->channel0[i], 27);
+ if (value < 0) return -1;
+ clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1);
+ if (clocks < 2 ) {
+ clocks = 2 ;
+ }
+ if (clocks > 6 ) {
+ return -1;
+ }
+ dtl = pci_read_config32(ctrl->f2, 0x88 );
+ old_clocks = ((dtl >> 24 ) & 0x7 ) + 0 ;
+ if (old_clocks > clocks) {
+ clocks = old_clocks;
+ }
+ dtl &= ~(0x7 << 24 );
+ dtl |= ((clocks - 0 ) << 24 );
+ pci_write_config32(ctrl->f2, 0x88 , dtl);
+ return 0;
+}
+static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+ uint32_t dtl;
+ dtl = pci_read_config32(ctrl->f2, 0x88 );
+ dtl &= ~(0x1 << 28 );
+ dtl |= (param->dtl_twr - 2 ) << 28 ;
+ pci_write_config32(ctrl->f2, 0x88 , dtl);
+}
+static void init_Tref(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+ uint32_t dth;
+ dth = pci_read_config32(ctrl->f2, 0x8c );
+ dth &= ~(0x1f << 8 );
+ dth |= (param->dch_tref4k << 8 );
+ pci_write_config32(ctrl->f2, 0x8c , dth);
+}
+static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ uint32_t dth;
+ int value;
+ unsigned tref, old_tref;
+ value = spd_read_byte(ctrl->channel0[i], 3);
+ if (value < 0) return -1;
+ value &= 0xf;
+ tref = param->dch_tref8k;
+ if (value == 12) {
+ tref = param->dch_tref4k;
+ }
+ dth = pci_read_config32(ctrl->f2, 0x8c );
+ old_tref = (dth >> 8 ) & 0x1f ;
+ if ((value == 12) && (old_tref == param->dch_tref4k)) {
+ tref = param->dch_tref4k;
+ } else {
+ tref = param->dch_tref8k;
+ }
+ dth &= ~(0x1f << 8 );
+ dth |= (tref << 8 );
+ pci_write_config32(ctrl->f2, 0x8c , dth);
+ return 0;
+}
+static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ uint32_t dcl;
+ int value;
+ int dimm;
+ value = spd_read_byte(ctrl->channel0[i], 13);
+ if (value < 0) {
+ return -1;
+ }
+ dimm = i;
+ dimm += 20 ;
+ dcl = pci_read_config32(ctrl->f2, 0x90 );
+ dcl &= ~(1 << dimm);
+ if (value == 4) {
+ dcl |= (1 << dimm);
+ }
+ pci_write_config32(ctrl->f2, 0x90 , dcl);
+ return 0;
+}
+static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
+{
+ uint32_t dcl;
+ int value;
+ value = spd_read_byte(ctrl->channel0[i], 11);
+ if (value < 0) {
+ return -1;
+ }
+ if (value != 2) {
+ dcl = pci_read_config32(ctrl->f2, 0x90 );
+ dcl &= ~(1<<17) ;
+ pci_write_config32(ctrl->f2, 0x90 , dcl);
+ }
+ return 0;
+}
+static int count_dimms(const struct mem_controller *ctrl)
+{
+ int dimms;
+ unsigned index;
+ dimms = 0;
+ for(index = 0; index < 8; index += 2) {
+ uint32_t csbase;
+ csbase = pci_read_config32(ctrl->f2, (0x40 + index << 2));
+ if (csbase & 1) {
+ dimms += 1;
+ }
+ }
+ return dimms;
+}
+static void set_Twtr(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+ uint32_t dth;
+ unsigned clocks;
+ clocks = 1;
+ dth = pci_read_config32(ctrl->f2, 0x8c );
+ dth &= ~(0x1 << 0 );
+ dth |= ((clocks - 1 ) << 0 );
+ pci_write_config32(ctrl->f2, 0x8c , dth);
+}
+static void set_Trwt(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+ uint32_t dth, dtl;
+ unsigned divisor;
+ unsigned latency;
+ unsigned clocks;
+ clocks = 0;
+ dtl = pci_read_config32(ctrl->f2, 0x88 );
+ latency = (dtl >> 0 ) & 0x7 ;
+ divisor = param->divisor;
+ if (is_opteron(ctrl)) {
+ if (latency == 1 ) {
+ if (divisor == ((6 << 0) + 0)) {
+
+ clocks = 3;
+ }
+ else if (divisor > ((6 << 0)+0)) {
+
+ clocks = 2;
+ }
+ }
+ else if (latency == 5 ) {
+ clocks = 3;
+ }
+ else if (latency == 2 ) {
+ if (divisor == ((6 << 0)+0)) {
+
+ clocks = 4;
+ }
+ else if (divisor > ((6 << 0)+0)) {
+
+ clocks = 3;
+ }
+ }
+ }
+ else {
+ if (is_registered(ctrl)) {
+ if (latency == 1 ) {
+ clocks = 2;
+ }
+ else if (latency == 5 ) {
+ clocks = 3;
+ }
+ else if (latency == 2 ) {
+ clocks = 3;
+ }
+ }
+ else {
+ if (latency == 1 ) {
+ clocks = 3;
+ }
+ else if (latency == 5 ) {
+ clocks = 4;
+ }
+ else if (latency == 2 ) {
+ clocks = 4;
+ }
+ }
+ }
+ if ((clocks < 1 ) || (clocks > 6 )) {
+ die("Unknown Trwt");
+ }
+
+ dth = pci_read_config32(ctrl->f2, 0x8c );
+ dth &= ~(0x7 << 4 );
+ dth |= ((clocks - 1 ) << 4 );
+ pci_write_config32(ctrl->f2, 0x8c , dth);
+ return;
+}
+static void set_Twcl(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+
+ uint32_t dth;
+ unsigned clocks;
+ if (is_registered(ctrl)) {
+ clocks = 2;
+ } else {
+ clocks = 1;
+ }
+ dth = pci_read_config32(ctrl->f2, 0x8c );
+ dth &= ~(0x7 << 20 );
+ dth |= ((clocks - 1 ) << 20 );
+ pci_write_config32(ctrl->f2, 0x8c , dth);
+}
+static void set_read_preamble(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+ uint32_t dch;
+ unsigned divisor;
+ unsigned rdpreamble;
+ divisor = param->divisor;
+ dch = pci_read_config32(ctrl->f2, 0x94 );
+ dch &= ~(0xf << 8 );
+ rdpreamble = 0;
+ if (is_registered(ctrl)) {
+ if (divisor == ((10 << 1)+0)) {
+
+ rdpreamble = ((9 << 1)+ 0);
+ }
+ else if (divisor == ((7 << 1)+1)) {
+
+ rdpreamble = ((8 << 1)+0);
+ }
+ else if (divisor == ((6 << 1)+0)) {
+
+ rdpreamble = ((7 << 1)+1);
+ }
+ else if (divisor == ((5 << 1)+0)) {
+
+ rdpreamble = ((7 << 1)+0);
+ }
+ }
+ else {
+ int slots;
+ int i;
+ slots = 0;
+ for(i = 0; i < 4; i++) {
+ if (ctrl->channel0[i]) {
+ slots += 1;
+ }
+ }
+ if (divisor == ((10 << 1)+0)) {
+
+ if (slots <= 2) {
+
+ rdpreamble = ((9 << 1)+0);
+ } else {
+
+ rdpreamble = ((14 << 1)+0);
+ }
+ }
+ else if (divisor == ((7 << 1)+1)) {
+
+ if (slots <= 2) {
+
+ rdpreamble = ((7 << 1)+0);
+ } else {
+
+ rdpreamble = ((11 << 1)+0);
+ }
+ }
+ else if (divisor == ((6 << 1)+0)) {
+
+ if (slots <= 2) {
+
+ rdpreamble = ((7 << 1)+0);
+ } else {
+
+ rdpreamble = ((9 << 1)+0);
+ }
+ }
+ else if (divisor == ((5 << 1)+0)) {
+
+ if (slots <= 2) {
+
+ rdpreamble = ((5 << 1)+0);
+ } else {
+
+ rdpreamble = ((7 << 1)+0);
+ }
+ }
+ }
+ if ((rdpreamble < ((2<<1)+0) ) || (rdpreamble > ((9<<1)+1) )) {
+ die("Unknown rdpreamble");
+ }
+ dch |= (rdpreamble - ((2<<1)+0) ) << 8 ;
+ pci_write_config32(ctrl->f2, 0x94 , dch);
+}
+static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+ uint32_t dch;
+ int i;
+ unsigned async_lat;
+ int dimms;
+ dimms = count_dimms(ctrl);
+ dch = pci_read_config32(ctrl->f2, 0x94 );
+ dch &= ~(0xf << 0 );
+ async_lat = 0;
+ if (is_registered(ctrl)) {
+ if (dimms == 4) {
+
+ async_lat = 9;
+ }
+ else {
+
+ async_lat = 8;
+ }
+ }
+ else {
+ if (dimms > 3) {
+ die("Too many unbuffered dimms");
+ }
+ else if (dimms == 3) {
+
+ async_lat = 7;
+ }
+ else {
+
+ async_lat = 6;
+ }
+ }
+ dch |= ((async_lat - 0 ) << 0 );
+ pci_write_config32(ctrl->f2, 0x94 , dch);
+}
+static void set_idle_cycle_limit(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+ uint32_t dch;
+
+ dch = pci_read_config32(ctrl->f2, 0x94 );
+ dch &= ~(0x7 << 16 );
+ dch |= 3 << 16 ;
+ dch |= (1 << 19) ;
+ pci_write_config32(ctrl->f2, 0x94 , dch);
+}
+static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param)
+{
+ int dimms;
+ int i;
+ int rc;
+
+ init_Tref(ctrl, param);
+ for(i = 0; (i < 4) && ctrl->channel0[i]; i++) {
+ int rc;
+
+ if (update_dimm_Trc (ctrl, param, i) < 0) goto dimm_err;
+ if (update_dimm_Trfc(ctrl, param, i) < 0) goto dimm_err;
+ if (update_dimm_Trcd(ctrl, param, i) < 0) goto dimm_err;
+ if (update_dimm_Trrd(ctrl, param, i) < 0) goto dimm_err;
+ if (update_dimm_Tras(ctrl, param, i) < 0) goto dimm_err;
+ if (update_dimm_Trp (ctrl, param, i) < 0) goto dimm_err;
+
+ if (update_dimm_Tref(ctrl, param, i) < 0) goto dimm_err;
+
+ if (update_dimm_x4 (ctrl, param, i) < 0) goto dimm_err;
+ if (update_dimm_ecc(ctrl, param, i) < 0) goto dimm_err;
+ continue;
+ dimm_err:
+ disable_dimm(ctrl, i);
+
+ }
+
+ set_Twr(ctrl, param);
+
+ set_Twtr(ctrl, param);
+ set_Trwt(ctrl, param);
+ set_Twcl(ctrl, param);
+
+ set_read_preamble(ctrl, param);
+ set_max_async_latency(ctrl, param);
+ set_idle_cycle_limit(ctrl, param);
+}
+static void sdram_set_spd_registers(const struct mem_controller *ctrl)
+{
+ const struct mem_param *param;
+ spd_enable_2channels(ctrl);
+ spd_set_ram_size(ctrl);
+ spd_handle_unbuffered_dimms(ctrl);
+ param = spd_set_memclk(ctrl);
+ spd_set_dram_timing(ctrl, param);
+ order_dimms(ctrl);
+}
+static void sdram_enable(int controllers, const struct mem_controller *ctrl)
+{
+ int i;
+
+ for(i = 0; i < controllers; i++) {
+ uint32_t dch;
+ dch = pci_read_config32(ctrl[i].f2, 0x94 );
+ dch |= (1 << 25) ;
+ pci_write_config32(ctrl[i].f2, 0x94 , dch);
+ }
+
+ memreset(controllers, ctrl);
+ for(i = 0; i < controllers; i++) {
+ uint32_t dcl;
+
+ dcl = pci_read_config32(ctrl[i].f2, 0x90 );
+ if (dcl & (1<<17) ) {
+ uint32_t mnc;
+ print_debug("ECC enabled\r\n");
+ mnc = pci_read_config32(ctrl[i].f3, 0x44 );
+ mnc |= (1 << 22) ;
+ if (dcl & (1<<16) ) {
+ mnc |= (1 << 23) ;
+ }
+ pci_write_config32(ctrl[i].f3, 0x44 , mnc);
+ }
+ dcl |= (1<<3) ;
+ pci_write_config32(ctrl[i].f2, 0x90 , dcl);
+ dcl &= ~(1<<3) ;
+ dcl &= ~(1<<0) ;
+ dcl &= ~(1<<1) ;
+ dcl &= ~(1<<2) ;
+ dcl |= (1<<8) ;
+ pci_write_config32(ctrl[i].f2, 0x90 , dcl);
+ }
+ for(i = 0; i < controllers; i++) {
+ uint32_t dcl;
+ print_debug("Initializing memory: ");
+ int loops = 0;
+ do {
+ dcl = pci_read_config32(ctrl[i].f2, 0x90 );
+ 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");
+ }
+ if (dcl & (1<<17) ) {
+ print_debug("Clearing memory: ");
+ if (!is_cpu_pre_c0()) {
+
+ dcl &= ~((1<<11) | (1<<10) );
+ pci_write_config32(ctrl[i].f2, 0x90 , dcl);
+ do {
+ dcl = pci_read_config32(ctrl[i].f2, 0x90 );
+ } while(((dcl & (1<<11) ) == 0) || ((dcl & (1<<10) ) == 0) );
+ }
+ uint32_t base, last_scrub_k, scrub_k;
+ uint32_t cnt,zstart,zend;
+ msr_t msr,msr_201;
+
+ pci_write_config32(ctrl[i].f3, 0x58 ,
+ (0 << 16) | (0 << 8) | (0 << 0));
+
+ msr_201 = rdmsr(0x201);
+ zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8));
+ zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8));
+ zstart >>= 16;
+ zend >>=16;
+ print_debug("addr ");
+ print_debug_hex32(zstart);
+ print_debug("-");
+ print_debug_hex32(zend);
+ print_debug("\r\n");
+
+
+ msr = rdmsr(0x2ff );
+ msr.lo &= ~(1<<10);
+ wrmsr(0x2ff , msr);
+
+ msr = rdmsr(0xc0010015);
+ msr.lo |= (1<<17);
+ wrmsr(0xc0010015,msr);
+ for(;zstart<zend;zstart+=4) {
+
+ if(zstart == 0x0fc)
+ continue;
+
+
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+
+ msr.lo = 1 + ((zstart&0x0ff)<<24);
+ msr.hi = (zstart&0x0ff00)>>8;
+ wrmsr(0x200,msr);
+
+ msr.hi = 0x000000ff;
+ msr.lo = 0xfc000800;
+ wrmsr(0x201,msr);
+
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ msr.lo = (zstart&0xff) << 24;
+ msr.hi = (zstart&0xff00) >> 8;
+ wrmsr(0xc0000100,msr);
+ print_debug_char((zstart > 0x0ff)?'+':'-');
+
+
+ __asm__ volatile(
+ "1: \n\t"
+ "movl %0, %%fs:(%1)\n\t"
+ "addl $4,%1\n\t"
+ "subl $1,%2\n\t"
+ "jnz 1b\n\t"
+ :
+ : "a" (0), "D" (0), "c" (0x01000000)
+ );
+ }
+
+
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+
+ msr = rdmsr(0x2ff );
+ msr.lo |= 0x0400;
+ wrmsr(0x2ff , msr);
+
+ msr.lo = 6;
+ msr.hi = 0;
+ wrmsr(0x200,msr);
+ wrmsr(0x201,msr_201);
+
+ msr.lo = 0;
+ msr.hi = 0;
+ wrmsr(0xc0000100,msr);
+
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+
+ msr = rdmsr(0xc0010015);
+ msr.lo &= ~(1<<17);
+ wrmsr(0xc0010015,msr);
+
+ base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3));
+ base &= 0xffff0000;
+
+ pci_write_config32(ctrl[i].f3, 0x5C , base << 8);
+ pci_write_config32(ctrl[i].f3, 0x60 , base >> 24);
+
+ pci_write_config32(ctrl[i].f3, 0x58 ,
+ (22 << 16) | (22 << 8) | (22 << 0));
+ print_debug("done\r\n");
+ }
+ }
+}
+
+
+
+
+
+typedef uint8_t u8;
+typedef uint32_t u32;
+typedef int8_t bool;
+static void disable_probes(void)
+{
+
+
+ u32 val;
+ print_debug("Disabling read/write/fill probes for UP... ");
+ val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68);
+ val |= (1<<10)|(1<<9)|(1<<8)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1 << 0);
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68, val);
+ print_debug("done.\r\n");
+}
+
+static void wait_ap_stop(u8 node)
+{
+ unsigned long reg;
+ unsigned long i;
+ for(i=0;i< 1000 ;i++) {
+ unsigned long regx;
+ regx = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x6c);
+ if((regx & (1<<4))==1) break;
+ }
+ reg = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x6c);
+ reg &= ~(1<<4);
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c, reg);
+}
+static void notify_bsp_ap_is_stopped(void)
+{
+ unsigned long reg;
+ unsigned long apic_id;
+ apic_id = *((volatile unsigned long *)(0xfee00000 + 0x020 ));
+ apic_id >>= 24;
+
+ if(apic_id != 0) {
+
+ reg = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ apic_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6C);
+ reg |= 1<<4;
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ apic_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6C, reg);
+ }
+
+}
+
+static void enable_routing(u8 node)
+{
+ u32 val;
+
+
+ print_debug("Enabling routing table for node ");
+ print_debug_hex32(node);
+ val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c);
+ val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0));
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c, val);
+
+ if(node!=0) {
+ wait_ap_stop(node);
+ }
+
+ print_debug(" done.\r\n");
+}
+static void rename_temp_node(u8 node)
+{
+ uint32_t val;
+ print_debug("Renaming current temp node to ");
+ print_debug_hex32(node);
+ val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60);
+ val &= (~7);
+ val |= node;
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60, val);
+ print_debug(" done.\r\n");
+}
+static bool check_connection(u8 src, u8 dest, u8 link)
+{
+
+ u32 val;
+
+
+ val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ src ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x98+link);
+ if ( (val&0x17) != 0x03)
+ return 0;
+
+ val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ dest ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0);
+ if(val != 0x11001022)
+ return 0;
+ return 1;
+}
+static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2)
+{
+ static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
+ static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
+ uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask;
+ uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2;
+ uint8_t freq;
+
+
+ freq_cap1 = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 0x0a );
+ freq_cap2 = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 0x0a );
+
+
+ freq = log2(freq_cap1 & freq_cap2 & 0xff);
+
+ pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 0x09 , freq);
+ pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 0x09 , freq);
+
+ width_cap1 = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 6 );
+ width_cap2 = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 6 );
+
+ ln_width1 = link_width_to_pow2[width_cap1 & 7];
+ ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7];
+ if (ln_width1 > ln_width2) {
+ ln_width1 = ln_width2;
+ }
+ width = pow2_to_link_width[ln_width1];
+
+ ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7];
+ ln_width2 = link_width_to_pow2[width_cap2 & 7];
+ if (ln_width1 > ln_width2) {
+ ln_width1 = ln_width2;
+ }
+ width |= pow2_to_link_width[ln_width1] << 4;
+
+
+ pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 6 + 1, width);
+
+ width = ((width & 0x70) >> 4) | ((width & 0x7) << 4);
+ pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 6 + 1, width);
+}
+static void fill_row(u8 node, u8 row, u32 value)
+{
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x40+(row<<2), value);
+}
+static void setup_row(u8 source, u8 dest, u8 cpus)
+{
+ fill_row(source,dest,generate_row(source,dest,cpus));
+}
+static void setup_temp_row(u8 source, u8 dest, u8 cpus)
+{
+ fill_row(source,7,((generate_row( source,dest,cpus )&(~0x0f0000))|0x010000) );
+}
+static void setup_node(u8 node, u8 cpus)
+{
+ u8 row;
+ for(row=0; row<cpus; row++)
+ setup_row(node, row, cpus);
+}
+static void setup_remote_row(u8 source, u8 dest, u8 cpus)
+{
+ fill_row(7, dest, generate_row(source, dest, cpus));
+}
+static void setup_remote_node(u8 node, u8 cpus)
+{
+ static const uint8_t pci_reg[] = {
+ 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c,
+ 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78,
+ 0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc,
+ 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8,
+ 0xc4, 0xcc, 0xd4, 0xdc,
+ 0xc0, 0xc8, 0xd0, 0xd8,
+ 0xe0, 0xe4, 0xe8, 0xec,
+ };
+ uint8_t row;
+ int i;
+ print_debug("setup_remote_node\r\n");
+ for(row=0; row<cpus; row++)
+ setup_remote_row(node, row, cpus);
+
+ for(i = 0; i < sizeof(pci_reg)/sizeof(pci_reg[0]); i++) {
+ uint32_t value;
+ uint8_t reg;
+ reg = pci_reg[i];
+ value = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , reg);
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , reg, value);
+ }
+ print_debug("setup_remote_done\r\n");
+}
+static u8 setup_uniprocessor(void)
+{
+ print_debug("Enabling UP settings\r\n");
+ disable_probes();
+ return 1;
+}
+static u8 setup_smp(void)
+{
+ u8 cpus=2;
+ print_debug("Enabling SMP settings\r\n");
+ setup_row(0,0,cpus);
+
+ setup_temp_row(0,1,cpus);
+
+ if (!check_connection(0, 7, 0x20 )) {
+ print_debug("No connection to Node 1.\r\n");
+ fill_row( 0 ,7,0x00010101 ) ;
+ setup_uniprocessor();
+ return 1;
+ }
+
+ optimize_connection(0, 0x20 , 7, 0x20 );
+ setup_node(0, cpus);
+ setup_remote_node(1, cpus);
+ rename_temp_node(1);
+ enable_routing(1);
+
+ fill_row( 0 ,7,0x00010101 ) ;
+
+ print_debug_hex32(cpus);
+ print_debug(" nodes initialized.\r\n");
+ return cpus;
+}
+static unsigned detect_mp_capabilities(unsigned cpus)
+{
+ unsigned node, row, mask;
+ bool mp_cap= (-1) ;
+ print_debug("detect_mp_capabilities: ");
+ print_debug_hex32(cpus);
+ print_debug("\r\n");
+ if (cpus>2)
+ mask=0x06;
+ else
+ mask=0x02;
+ for (node=0; node<cpus; node++) {
+ if ((pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , 0xe8) & mask)!=mask)
+ mp_cap= (0) ;
+ }
+ if (mp_cap)
+ return cpus;
+
+ print_debug("One of the CPUs is not MP capable. Going back to UP\r\n");
+ for (node=cpus; node>0; node--)
+ for (row=cpus; row>0; row--)
+ fill_row(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node-1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , row-1, 0x00010101 );
+
+ return setup_uniprocessor();
+}
+static void coherent_ht_finalize(unsigned cpus)
+{
+ int node;
+ bool rev_a0;
+
+
+ print_debug("coherent_ht_finalize\r\n");
+ rev_a0= is_cpu_rev_a0();
+ for (node=0; node<cpus; node++) {
+ u32 val;
+ val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60);
+ val &= (~0x000F0070);
+ val |= ((cpus-1)<<16)|((cpus-1)<<4);
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x60,val);
+ val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68);
+ val |= 0x00008000;
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x68,val);
+ if (rev_a0) {
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x94,0);
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0xb4,0);
+ pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0xd4,0);
+ }
+ }
+ print_debug("done\r\n");
+}
+static int setup_coherent_ht_domain(void)
+{
+ unsigned cpus;
+ int reset_needed = 0;
+ enable_routing(0) ;
+ cpus=setup_smp();
+ cpus=detect_mp_capabilities(cpus);
+ coherent_ht_finalize(cpus);
+
+ coherent_ht_mainboard(cpus);
+ return reset_needed;
+}
+void sdram_no_memory(void)
+{
+ print_err("No memory!!\r\n");
+ while(1) {
+ hlt();
+ }
+}
+
+void sdram_initialize(int controllers, const struct mem_controller *ctrl)
+{
+ int i;
+
+ for(i = 0; i < controllers; i++) {
+ print_debug("Ram1.");
+ print_debug_hex8(i);
+ print_debug("\r\n");
+ sdram_set_registers(ctrl + i);
+ }
+
+ for(i = 0; i < controllers; i++) {
+ print_debug("Ram2.");
+ print_debug_hex8(i);
+ print_debug("\r\n");
+ sdram_set_spd_registers(ctrl + i);
+ }
+
+ print_debug("Ram3\r\n");
+ sdram_enable(controllers, ctrl);
+ print_debug("Ram4\r\n");
+}
+static void enable_lapic(void)
+{
+ msr_t msr;
+ msr = rdmsr(0x1b);
+ msr.hi &= 0xffffff00;
+ msr.lo &= 0x000007ff;
+ msr.lo |= 0xfee00000 | (1 << 11);
+ wrmsr(0x1b, msr);
+}
+static void stop_this_cpu(void)
+{
+ unsigned apicid;
+ apicid = apic_read(0x020 ) >> 24;
+
+ apic_write(0x310 , (( apicid )<<24) );
+ apic_write(0x300 , 0x08000 | 0x04000 | 0x00500 );
+
+ apic_wait_icr_idle();
+
+ apic_write(0x310 , (( apicid )<<24) );
+ apic_write(0x300 , 0x08000 | 0x00500 );
+
+ apic_wait_icr_idle();
+
+ for(;;) {
+ hlt();
+ }
+}
+static void pc87360_enable_serial(void)
+{
+ pnp_set_logical_device(0x2e , 0x03 );
+ pnp_set_enable(0x2e , 1);
+ pnp_set_iobase0(0x2e , 0x3f8);
+}
+static void main(void)
+{
+
+ static const struct mem_controller cpu[] = {
+ {
+ .node_id = 0,
+ .f0 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,
+ .f1 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ,
+ .f2 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,
+ .f3 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,
+ .channel0 = { (0xa<<3)|0, (0xa<<3)|2, 0, 0 },
+ .channel1 = { (0xa<<3)|1, (0xa<<3)|3, 0, 0 },
+ },
+ {
+ .node_id = 1,
+ .f0 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,
+ .f1 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ,
+ .f2 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,
+ .f3 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,
+ .channel0 = { (0xa<<3)|4, (0xa<<3)|6, 0, 0 },
+ .channel1 = { (0xa<<3)|5, (0xa<<3)|7, 0, 0 },
+ },
+ };
+ if (cpu_init_detected()) {
+ asm("jmp __cpu_reset");
+ }
+ enable_lapic();
+ init_timer();
+ if (!boot_cpu()) {
+ stop_this_cpu();
+ }
+ pc87360_enable_serial();
+ uart_init();
+ console_init();
+ setup_default_resource_map();
+ setup_coherent_ht_domain();
+ enumerate_ht_chain(0);
+ distinguish_cpu_resets(0);
+
+ enable_smbus();
+ memreset_setup();
+ sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu);
+
+}
diff --git a/util/romcc/tests/simple_test1.c b/util/romcc/tests/simple_test1.c
new file mode 100644
index 0000000000..feacbfdc38
--- /dev/null
+++ b/util/romcc/tests/simple_test1.c
@@ -0,0 +1,252 @@
+void land_test(void)
+{
+ int i;
+ i = 1 && 2;
+}
+void lor_test(void)
+{
+ int i;
+ i = 1 || 2;
+}
+
+void outb(unsigned char value, unsigned short port)
+{
+ __builtin_outb(value, port);
+}
+
+unsigned char inb(unsigned short port)
+{
+ return __builtin_inb(port);
+}
+
+static unsigned int config_cmd2(unsigned char bus, unsigned devfn, unsigned where)
+{
+ return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3) ;
+}
+
+/* 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
+
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+
+/* 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))
+ ;
+}
+
+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 dummy(void)
+{
+ uart_tx_byte(5);
+}
+
+#define PIIX4_DEVFN 0x90
+#define SMBUS_MEM_DEVICE_START 0x50
+#define SMBUS_MEM_DEVICE_END 0x53
+#define SMBUS_MEM_DEVICE_INC 1
+
+
+#define PM_BUS 0
+#define PM_DEVFN (PIIX4_DEVFN+3)
+
+#define SMBUS_IO_BASE 0x1000
+#define SMBHSTSTAT 0
+#define SMBHSTCTL 2
+#define SMBHSTCMD 3
+#define SMBHSTADD 4
+#define SMBHSTDAT0 5
+#define SMBHSTDAT1 6
+#define SMBBLKDAT 7
+
+static void smbus_wait_until_done(void)
+{
+ unsigned char byte;
+ do {
+ byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ }while((byte &1) == 1);
+#if 1
+ while( (byte & ~1) == 0) {
+ byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ }
+#endif
+}
+
+#if 0
+void ifthenelse(void)
+{
+ int i;
+ if (5 > 2) {
+ i = 1;
+ }
+ else {
+ i = 2;
+ }
+ i = i + 3;
+}
+#endif
+#if 0
+static int add(int left, int right)
+{
+ {
+ return left + right;
+ }
+}
+#else
+#if 0
+static int add(int left, int right)
+{
+ return left + right;
+}
+#endif
+#endif
+
+#if 0
+static void assign(void)
+{
+ int i, j;
+ i = j = 1;
+}
+#endif
+
+#if 0
+static void and(void)
+{
+ int i, j, k;
+ i = 1;
+ j = 2;
+ k = i && j;
+
+}
+static void and_test(void)
+{
+ and();
+}
+#endif
+#if 0
+#define INC_TEST 2
+static void inc(void)
+{
+ int i;
+ i = 5;
+#if (INC_TEST == 1)
+ i += 7;
+#endif
+#if (INC_TEST == 2)
+ ++i;
+#endif
+#if (INC_TEST == 3)
+ i++;
+#endif
+}
+
+#if 0
+static void inc_test(void)
+{
+ inc();
+}
+#endif
+#endif
+#if 0
+static void loop(void)
+{
+ int i;
+ for(i = 0; i < 10; i++) {
+ ;
+ } while(i < 10);
+}
+
+static void loop_test(void)
+{
+ loop();
+}
+#endif
+
+#if 0
+static void simple(void)
+{
+ add(1,2);
+}
+#endif
+
+#if 0
+static void fun(void)
+{
+ int bar;
+ bar = add(1, 2);
+}
+#endif
+
+
+#if 0
+static void func(void)
+{
+ int bar, baz;
+ int i;
+
+ baz = add(1, 2);
+ baz = add(1, 2);
+ bar = 1;
+ baz = 2;
+ for(i = 0; i < 10; i = i + 1) {
+ baz = i;
+ }
+ bar = 1 + 2 * 3;
+ bar = add(3, 4);
+ bar = add(bar, baz);
+}
+#endif
diff --git a/util/romcc/tests/simple_test60.c b/util/romcc/tests/simple_test60.c
index d277c94dd3..860bf3240d 100644
--- a/util/romcc/tests/simple_test60.c
+++ b/util/romcc/tests/simple_test60.c
@@ -27,6 +27,6 @@ static void test(void)
const struct mem_param *param;
param = &param0;
value = 0x48;
-#warning "this generates word loads instead of byte loads"
+#warning "this generated word loads instead of byte loads"
clocks = (value + (param->divisor << 1) - 1)/(param->divisor << 1);
}
diff --git a/util/romcc/tests/simple_test71.c b/util/romcc/tests/simple_test71.c
index 35956c5ea8..52ffc8d42c 100644
--- a/util/romcc/tests/simple_test71.c
+++ b/util/romcc/tests/simple_test71.c
@@ -6,16 +6,10 @@ static void main(void)
{
int i;
-#if 1
foo();
-#endif
-#if 1
foo();
-#endif
for(i = 0; i < 10; i++) {
-#if 1
foo();
-#endif
#if 0
foo();
#endif
diff --git a/util/romcc/tests/simple_test74.c b/util/romcc/tests/simple_test74.c
new file mode 100644
index 0000000000..177e00f29e
--- /dev/null
+++ b/util/romcc/tests/simple_test74.c
@@ -0,0 +1,88 @@
+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 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 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);
+
+}
+
+#define NR_exit 1
+#define NR_write 4
+
+/* Standard file descriptors */
+#define STDIN_FILENO 0 /* Standard input */
+#define STDOUT_FILENO 1 /* Standard output */
+#define STDERR_FILENO 2 /* Standard error output */
+
+typedef long ssize_t;
+typedef unsigned long size_t;
+
+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 console_tx_string(const char *str)
+{
+ unsigned char ch;
+ while(1) {
+
+ }
+ for(;1;) {
+ }
+ do {
+ } while(1);
+ if (1) {
+ }else {
+ }
+}
+
+
+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_test75.c b/util/romcc/tests/simple_test75.c
new file mode 100644
index 0000000000..1ad87bd2a0
--- /dev/null
+++ b/util/romcc/tests/simple_test75.c
@@ -0,0 +1,21 @@
+static void goto_test(void)
+{
+ int i;
+
+ i = 0;
+ goto bottom;
+ {
+ top:
+ i = i + 1;
+ }
+ bottom:
+ if (i < 10) {
+ goto top;
+ }
+ ;
+}
+
+static void main(void)
+{
+ goto_test();
+}
diff --git a/util/romcc/tests/simple_test76.c b/util/romcc/tests/simple_test76.c
new file mode 100644
index 0000000000..4f682d37d4
--- /dev/null
+++ b/util/romcc/tests/simple_test76.c
@@ -0,0 +1,69 @@
+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 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 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);
+
+}
+
+#define NR_exit 1
+#define NR_write 4
+/* Standard file descriptors */
+#define STDIN_FILENO 0 /* Standard input */
+#define STDOUT_FILENO 1 /* Standard output */
+#define STDERR_FILENO 2 /* Standard error output */
+
+typedef long ssize_t;
+typedef unsigned long size_t;
+
+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_test77.c b/util/romcc/tests/simple_test77.c
new file mode 100644
index 0000000000..74be92e39b
--- /dev/null
+++ b/util/romcc/tests/simple_test77.c
@@ -0,0 +1,5 @@
+static void main(void)
+{
+ do {
+ } while(1);
+}
diff --git a/util/romcc/tests/simple_test78.c b/util/romcc/tests/simple_test78.c
new file mode 100644
index 0000000000..5e6b27b4bf
--- /dev/null
+++ b/util/romcc/tests/simple_test78.c
@@ -0,0 +1,7 @@
+static void main(void)
+{
+ int x = 25;
+ do {
+ } while(1);
+ *((volatile int *)5) = x;
+}
diff --git a/util/romcc/tests/simple_test79.c b/util/romcc/tests/simple_test79.c
new file mode 100644
index 0000000000..2f501ca840
--- /dev/null
+++ b/util/romcc/tests/simple_test79.c
@@ -0,0 +1,5 @@
+static void main(void)
+{
+ do {
+ } while(0);
+}
diff --git a/util/romcc/tests/simple_test80.c b/util/romcc/tests/simple_test80.c
new file mode 100644
index 0000000000..3a31a0a1ec
--- /dev/null
+++ b/util/romcc/tests/simple_test80.c
@@ -0,0 +1,13 @@
+typedef __builtin_msr_t msr_t;
+
+static msr_t rdmsr(unsigned long index)
+{
+ return __builtin_rdmsr(index);
+}
+
+static void main(void)
+{
+ msr_t msr;
+ msr = rdmsr(0x12345678);
+}
+
diff --git a/util/romcc/tests/simple_test81.c b/util/romcc/tests/simple_test81.c
new file mode 100644
index 0000000000..e942679d67
--- /dev/null
+++ b/util/romcc/tests/simple_test81.c
@@ -0,0 +1,8 @@
+static void main(void)
+{
+ int i;
+ i = __builtin_inb(0x1234);
+ int j;
+ j = __builtin_inb(0xabcd);
+
+}
diff --git a/util/romcc/tests/simple_test82.c b/util/romcc/tests/simple_test82.c
new file mode 100644
index 0000000000..25b08babb4
--- /dev/null
+++ b/util/romcc/tests/simple_test82.c
@@ -0,0 +1,17 @@
+
+
+struct result {
+ int a, b, c, d;
+};
+
+static struct result main(int a, int b, int c, int d)
+{
+ struct result result;
+ result.a = d;
+ result.b = c;
+ result.c = b;
+ result.d = a;
+
+ return result;
+}
+
diff --git a/util/romcc/tests/simple_test83.c b/util/romcc/tests/simple_test83.c
new file mode 100644
index 0000000000..cf9f817fe2
--- /dev/null
+++ b/util/romcc/tests/simple_test83.c
@@ -0,0 +1,16 @@
+
+
+struct result {
+ int a, b, c, d;
+};
+
+static struct result main(int a, int b, int c, int d)
+{
+ struct result result;
+ result.a = d + 1;
+ result.b = c + 1;
+ result.c = b + 1;
+ result.d = a + 1;
+
+ return result;
+}
diff --git a/util/romcc/tests/simple_test84.c b/util/romcc/tests/simple_test84.c
new file mode 100644
index 0000000000..bc98bf3419
--- /dev/null
+++ b/util/romcc/tests/simple_test84.c
@@ -0,0 +1,28 @@
+struct stuff {
+ signed int a : 5;
+ signed int b : 6;
+ signed int c : 2;
+ unsigned int d : 3;
+};
+
+static void main(void)
+{
+ struct stuff var;
+ volatile int a, b, c, d;
+ a = 1;
+ b = 2;
+ c = 3;
+ d = 7;
+
+ var.a = a;
+ var.b = b;
+ var.c = c;
+ var.d = d;
+
+ a = var.a;
+ b = var.b;
+ c = var.c;
+ d = var.d;
+
+ asm(" " :: "r"(a), "r"(b), "r"(c), "r"(d));
+}
diff --git a/util/romcc/tests/simple_test85.c b/util/romcc/tests/simple_test85.c
new file mode 100644
index 0000000000..f223e2e3a5
--- /dev/null
+++ b/util/romcc/tests/simple_test85.c
@@ -0,0 +1,51 @@
+struct sub4 {
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned d;
+ unsigned e;
+ unsigned f;
+ unsigned g;
+};
+struct sub3 {
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned d;
+ unsigned e;
+ unsigned f;
+ struct sub4 s4;
+};
+struct sub2 {
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned d;
+ unsigned e;
+ struct sub3 s3;
+};
+struct sub1 {
+ unsigned a;
+ unsigned b;
+ struct sub2 s2;
+};
+
+struct stuff {
+ signed int a;
+ signed int b;
+ signed int c;
+ unsigned int d;
+ struct sub1 s1;
+};
+
+
+static void main(void)
+{
+ struct stuff *var;
+ unsigned int *foo;
+
+ var = (struct stuff *)(0x12345678);
+ foo = &var->d;
+ foo = &((*var).d);
+ foo = &var->s1.s2.s3.s4.g;
+}
diff --git a/util/romcc/tests/simple_test86.c b/util/romcc/tests/simple_test86.c
new file mode 100644
index 0000000000..d9d4c6584b
--- /dev/null
+++ b/util/romcc/tests/simple_test86.c
@@ -0,0 +1,5 @@
+static void main(void)
+{
+ asm("cpuid"
+ ::: "eax", "ebx", "ecx", "edx");
+}