RPA Toolkit
work on RPA2 unit tests
authorMartin Stoilov <martin@rpasearch.com>
Wed, 23 Feb 2011 05:18:20 +0000 (21:18 -0800)
committerMartin Stoilov <martin@rpasearch.com>
Wed, 23 Feb 2011 05:18:20 +0000 (21:18 -0800)
build/linux/build.mk
rpa2/rpacompiler.c
rpa2/rpacompiler.h
testrpa2/build/linux/testrpa2.mk [new file with mode: 0644]
testrpa2/build/linux/x86_64/Makefile [new file with mode: 0644]
testrpa2/common.h [new file with mode: 0644]
testrpa2/rpacompiler-rule.c [new file with mode: 0644]
testrpa2/rpavm-matchchr.c [new file with mode: 0644]
testrpa2/rpavm-mnode.c [new file with mode: 0644]
testrpa2/rpavm-test.c [new file with mode: 0644]

index 0179794..2d5c6f4 100644 (file)
@@ -5,6 +5,7 @@ all:
        +make -C $(SRCDIR)/rpa2/build/$(OS)/$(ARCHDIR) all
        +make -C $(SRCDIR)/rvm/build/$(OS)/$(ARCHDIR) all
        +make -C $(SRCDIR)/tests/build/$(OS)/$(ARCHDIR) all
+       +make -C $(SRCDIR)/testrpa2/build/$(OS)/$(ARCHDIR) all  
        +make -C $(SRCDIR)/rgrep/unix all
 
 distclean: clean
@@ -14,6 +15,7 @@ distclean: clean
        +make -C $(SRCDIR)/rpa2/build/$(OS)/$(ARCHDIR) distclean
        +make -C $(SRCDIR)/rvm/build/$(OS)/$(ARCHDIR) distclean
        +make -C $(SRCDIR)/tests/build/$(OS)/$(ARCHDIR) distclean
+       +make -C $(SRCDIR)/testrpa2/build/$(OS)/$(ARCHDIR) distclean    
        +make -C $(SRCDIR)/rgrep/unix distclean
 
 clean:
@@ -23,4 +25,5 @@ clean:
        +make -C $(SRCDIR)/rpa2/build/$(OS)/$(ARCHDIR) clean
        +make -C $(SRCDIR)/rvm/build/$(OS)/$(ARCHDIR) clean
        +make -C $(SRCDIR)/tests/build/$(OS)/$(ARCHDIR) clean
+       +make -C $(SRCDIR)/testrpa2/build/$(OS)/$(ARCHDIR) clean        
        +make -C $(SRCDIR)/rgrep/unix clean
index 9a69a67..102ab04 100644 (file)
@@ -1,5 +1,6 @@
 #include "rmem.h"
 #include "rpacompiler.h"
+#include "rstring.h"
 
 
 void rpacompiler_mnode_nan(rpa_compiler_t *co)
@@ -73,6 +74,7 @@ rpa_compiler_t *rpa_compiler_create()
        r_memset(co, 0, sizeof(*co));
        co->cg = rvm_codegen_create();
        co->scope = rvm_scope_create();
+       co->current.labelidx = -1;
        rpacompiler_mnode_nan(co);
        rpacompiler_mnode_opt(co);
        rpacompiler_mnode_mul(co);
@@ -89,3 +91,42 @@ void rpa_compiler_destroy(rpa_compiler_t *co)
        }
        r_free(co);
 }
+
+
+rint rpa_compiler_rule_begin(rpa_compiler_t *co, const rchar *name, ruint namesize)
+{
+       if (co->current.labelidx >= 0)
+               return -1;
+       co->current.labelidx = rvm_codegen_addlabel(co->cg, name, namesize);
+       r_snprintf(co->current.end, sizeof(co->current.end) - 1, "%__end:ld", co->current.labelidx);
+       co->current.end[sizeof(co->current.end) - 1] = '\0';
+       co->current.endidx = rvm_codemap_invalid_add_s(co->cg->codemap, co->current.end);
+       co->current.emitidx = rvm_codegen_adddata_s(co->cg, NULL, name, namesize);
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, co->current.emitidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       return 0;
+}
+
+
+rint rpa_compiler_rule_begin_s(rpa_compiler_t *co, const rchar *name)
+{
+       return rpa_compiler_rule_begin(co, name, r_strlen(name));
+}
+
+
+rint rpa_compiler_rule_end(rpa_compiler_t *co)
+{
+       if (co->current.labelidx < 0)
+               return -1;
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, co->current.emitidx, rvm_asm(RPA_EMITEND, DA, R1, R0, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       rvm_codegen_addlabel_s(co->cg, co->current.end);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R0, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       co->current.labelidx = -1;
+       return 0;
+}
+
index b6e16cf..4c6ddfa 100644 (file)
@@ -9,9 +9,16 @@
 extern "C" {
 #endif
 
+typedef struct rpa_ruledef_s {
+       rlong labelidx;
+       rlong emitidx;
+       rlong endidx;
+       rchar end[64];
+} rpa_ruledef_t;
 
 typedef struct rpa_compiler_s {
        rvm_codegen_t *cg;
+       rpa_ruledef_t current;
        rboolean optimized;
        rvm_scope_t *scope;
        rulong fpoff;
@@ -20,6 +27,9 @@ typedef struct rpa_compiler_s {
 
 rpa_compiler_t *rpa_compiler_create();
 void rpa_compiler_destroy(rpa_compiler_t *co);
+rint rpa_compiler_rule_begin(rpa_compiler_t *co, const rchar *name, ruint namesize);
+rint rpa_compiler_rule_begin_s(rpa_compiler_t *co, const rchar *name);
+rint rpa_compiler_rule_end(rpa_compiler_t *co);
 
 
 #ifdef __cplusplus
diff --git a/testrpa2/build/linux/testrpa2.mk b/testrpa2/build/linux/testrpa2.mk
new file mode 100644 (file)
index 0000000..18842e7
--- /dev/null
@@ -0,0 +1,41 @@
+RLIB_SRCDIR = $(SRCDIR)/rlib
+RVM_SRCDIR = $(SRCDIR)/rvm
+RPA2_SRCDIR = $(SRCDIR)/rpa2
+TESTS_SRCDIR = $(SRCDIR)/testrpa2
+INCLUDE = -I$(SRCDIR)/arch/$(OS)/$(ARCHDIR) -I$(RLIB_SRCDIR) -I$(RVM_SRCDIR) -I$(RPA2_SRCDIR)
+
+
+LIBS = -L$(RLIB_SRCDIR)/build/$(OS)/$(ARCHDIR)/out 
+LIBS += -L$(RVM_SRCDIR)/build/$(OS)/$(ARCHDIR)/out 
+LIBS += -L$(RPA2_SRCDIR)/build/$(OS)/$(ARCHDIR)/out 
+LIBS += -lrpa2 -lrvm -lrlib -lpthread -lm --static
+
+
+TESTS  += $(OUTDIR)/rpavm-test
+TESTS  += $(OUTDIR)/rpavm-matchchr
+TESTS  += $(OUTDIR)/rpavm-mnode
+TESTS  += $(OUTDIR)/rpacompiler-rule
+
+all : $(OUTDIR) $(TESTS)
+
+
+$(OUTDIR)/%: $(TESTS_SRCDIR)/%.c
+       + $(CC) $(CFLAGS) -o $(OUTDIR)/$* $(TESTS_SRCDIR)/$*.c  -lrpa2 $(LIBS) $(INCLUDE)
+
+
+$(OUTDIR)/%.o: $(TESTS_SRCDIR)/%.rpa
+       $(LD) -r -b binary -o $(OUTDIR)/$*.o $(TESTS_SRCDIR)/$*.rpa
+
+
+$(OUTDIR):
+       @mkdir $(OUTDIR)
+
+distclean: clean
+       @rm -f .depend
+       @rm -rf $(OUTDIR)
+
+clean:
+       @rm -f $(TESTS)
+       @rm -f *~
+       @rm -f $(SRCDIR)/*~
+
diff --git a/testrpa2/build/linux/x86_64/Makefile b/testrpa2/build/linux/x86_64/Makefile
new file mode 100644 (file)
index 0000000..0674df3
--- /dev/null
@@ -0,0 +1,29 @@
+ARCHDIR = x86_64
+OUTDIR = out
+OS = $(shell uname | tr "[:upper:]" "[:lower:]")
+SRCDIR = ../../../..
+
+
+CC = gcc
+AR = ar
+ifeq ($(BLDCFG), release)
+CFLAGS = -O3
+else
+ifeq ($(BLDCFG), profile)
+CFLAGS = -O0 -pg
+else
+CFLAGS = -g -O0 -Wall 
+endif
+endif
+
+ifeq ($(CCBLD), yes)
+CFLAGS += -fprofile-arcs -ftest-coverage
+endif
+
+CFLAGS += $(MACH) $(INCLUDE)
+
+CFLAGS := $(CFLAGS)
+LDFLAGS = $(MACH)
+
+
+include ../testrpa2.mk
diff --git a/testrpa2/common.h b/testrpa2/common.h
new file mode 100644 (file)
index 0000000..f3ad3be
--- /dev/null
@@ -0,0 +1,46 @@
+#include "rvmcpu.h"
+#include <stdio.h>
+
+#define EXECDEBUG 1
+
+
+#define VMTEST_REG(code, reg, val, msg) \
+       do { rvm_codegen_addins(code, rvm_asm(RVM_MOV, R8, DA, XX, reg)); \
+                rvm_codegen_addins(code, rvm_asm(RVM_MOV, R9, DA, XX, val)); \
+                rvm_codegen_addins(code, rvm_asmp(RVM_MOV, R10, DA, XX, msg)); \
+                rvm_codegen_addins(code, rvm_asm(RVM_OPSWI(rvm_cpu_getswi_s(stat->cpu, "rvm_vmtest_check_reg")), XX, XX, R0, 0)); \
+                rvm_codegen_addins(code, rvm_asm(RVM_NOP, XX, XX, XX, 0)); } while (0)
+
+#define VMTEST_STATUS(code, val, msg) \
+       do { rvm_codegen_addins(code, rvm_asm(RVM_MOV, R9, DA, XX, val)); \
+                rvm_codegen_addins(code, rvm_asmp(RVM_MOV, R10, DA, XX, msg)); \
+                rvm_codegen_addins(code, rvm_asm(RVM_OPSWI(rvm_cpu_getswi_s(stat->cpu, "rvm_vmtest_check_status")), XX, XX, R0, 0)); \
+                rvm_codegen_addins(code, rvm_asm(RVM_NOP, XX, XX, XX, 0)); } while (0)
+
+
+/*
+ * R10 - (const char*) msg
+ * R9 - argument (to compare)
+ * R8 - (0 : 7) Register to check
+ */
+static void rvm_vmtest_check_reg(rvmcpu_t *vm, rvm_asmins_t *ins)
+{
+       fprintf(stdout, "%s: %s\n", (const char*)RVM_CPUREG_GETU(vm, 10), RVM_CPUREG_GETU(vm, RVM_CPUREG_GETU(vm, 8)) == RVM_CPUREG_GETU(vm, 9) ? "PASSED" : "FAILED");
+}
+
+
+/*
+ * R10 - (const char*) msg
+ * R9 - argument (to compare the status register)
+ */
+static void rvm_vmtest_check_status(rvmcpu_t *vm, rvm_asmins_t *ins)
+{
+       fprintf(stdout, "%s: %s\n", (const char*)RVM_CPUREG_GETU(vm, 10), (vm->status & RVM_CPUREG_GETU(vm, 9))== RVM_CPUREG_GETU(vm, 9) ? "PASSED" : "FAILED");
+}
+
+
+static rvm_switable_t common_calltable[] = {
+       {"rvm_vmtest_check_reg", rvm_vmtest_check_reg},
+       {"rvm_vmtest_check_status", rvm_vmtest_check_status},
+       {NULL, NULL},
+};
diff --git a/testrpa2/rpacompiler-rule.c b/testrpa2/rpacompiler-rule.c
new file mode 100644 (file)
index 0000000..4ffc4b1
--- /dev/null
@@ -0,0 +1,133 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "rmem.h"
+#include "rpacompiler.h"
+#include "rpastat.h"
+#include "common.h"
+
+
+
+void code_rpa_matchabc(rpa_compiler_t *co, rpastat_t *stat)
+{
+       rpa_compiler_rule_begin_s(co, "rpa_matchabc");
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'a'));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, co->current.endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'b'));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, co->current.endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'c'));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, co->current.endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rpa_compiler_rule_end(co);
+}
+
+
+void code_rpa_matchxyz(rpa_compiler_t *co, rpastat_t *stat)
+{
+       rpa_compiler_rule_begin_s(co, "rpa_matchxyz");
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'x'));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, co->current.endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'y'));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, co->current.endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'z'));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, co->current.endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rpa_compiler_rule_end(co);
+}
+
+void code_rpa_matchmnode(rpa_compiler_t *co, rpastat_t *stat)
+{
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchabc", rvm_asm(RPA_BXLWHT, R_MNODE_NAN, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 3, "RPA_MNODE_NAN 'abc'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MNODE_NAN STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchxyz", rvm_asm(RPA_BXLWHT, R_MNODE_NAN, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, -1, "RPA_MNODE_NAN 'xyz'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_N, "RPA_MNODE_NAN STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchabc", rvm_asm(RPA_BXLWHT, R_MNODE_OPT, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 3, "RPA_MNODE_OPT 'abc'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MNODE_OPT STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchxyz", rvm_asm(RPA_BXLWHT, R_MNODE_OPT, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 0, "RPA_MNODE_OPT 'xyz'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_Z, "RPA_MNODE_OPT STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchabc", rvm_asm(RPA_BXLWHT, R_MNODE_MUL, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 12, "RPA_MNODE_MUL 'abc'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MNODE_MUL STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchxyz", rvm_asm(RPA_BXLWHT, R_MNODE_MUL, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, -1, "RPA_MNODE_MUL 'xyz'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_N, "RPA_MNODE_MUL STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchabc", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 12, "RPA_MNODE_MOP 'abc'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MNODE_MOP STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchxyz", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 0, "RPA_MNODE_MOP 'xyz'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_Z, "RPA_MNODE_MOP STATUS");
+
+
+}
+
+
+int main(int argc, char *argv[])
+{
+       rvm_codelabel_t *err;
+       rpa_compiler_t *co;
+       rpastat_t *stat;
+       ruint mainoff;
+       char teststr[] = "abcabcabcabc";
+
+       co = rpa_compiler_create();
+       stat = rpa_stat_create(4096);
+       rvm_cpu_addswitable(stat->cpu, common_calltable);
+
+       rpa_stat_init(stat, teststr, teststr, teststr+12);
+
+       mainoff = rvm_codegen_addins(co->cg, rvm_asml(RVM_NOP, XX, XX, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, R_TOP, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, FP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, SP, DA, XX, 0));
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_nan", rvm_asm(RVM_MOV, R_MNODE_NAN, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_mul", rvm_asm(RVM_MOV, R_MNODE_MUL, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_opt", rvm_asm(RVM_MOV, R_MNODE_OPT, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_mop", rvm_asm(RVM_MOV, R_MNODE_MOP, DA, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
+       code_rpa_matchmnode(co, stat);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_NOP, XX, XX, XX, 0xabc));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
+       code_rpa_matchabc(co, stat);
+       code_rpa_matchxyz(co, stat);
+
+       if (rvm_codegen_relocate(co->cg, &err) < 0) {
+               r_printf("Unresolved symbol: %s\n", err->name->str);
+               goto end;
+       }
+
+       rvm_cpu_exec(stat->cpu, rvm_codegen_getcode(co->cg, 0), mainoff);
+
+end:
+       rpa_stat_destroy(stat);
+       rpa_compiler_destroy(co);
+
+
+       r_printf("Max alloc mem: %ld\n", r_debug_get_maxmem());
+       r_printf("Leaked mem: %ld\n", r_debug_get_allocmem());
+       return 0;
+}
diff --git a/testrpa2/rpavm-matchchr.c b/testrpa2/rpavm-matchchr.c
new file mode 100644 (file)
index 0000000..10da273
--- /dev/null
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "rmem.h"
+#include "rpacompiler.h"
+#include "rpastat.h"
+#include "common.h"
+
+
+void code_rpa_matchchr(rpa_compiler_t *co, rpastat_t *stat)
+{
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'a'));
+       VMTEST_REG(co->cg, 0, 1, "RPA_MATCHCHR_NAN 'a'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MATCHCHR_NAN STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'b'));
+       VMTEST_REG(co->cg, 0, -1, "RPA_MATCHCHR_NAN 'b'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_N, "RPA_MATCHCHR_NAN STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_OPT, DA, XX, XX, 'a'));
+       VMTEST_REG(co->cg, 0, 1, "RPA_MATCHCHR_OPT 'a'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MATCHCHR_OPT STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_OPT, DA, XX, XX, 'b'));
+       VMTEST_REG(co->cg, 0, 0, "RPA_MATCHCHR_OPT 'b'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_Z, "RPA_MATCHCHR_OPT STATUS");
+
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_MOP, DA, XX, XX, 'a'));
+       VMTEST_REG(co->cg, 0, 3, "RPA_MATCHCHR_MOP 'a'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MATCHCHR_MOP STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_MOP, DA, XX, XX, 'b'));
+       VMTEST_REG(co->cg, 0, 0, "RPA_MATCHCHR_MOP 'b'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_Z, "RPA_MATCHCHR_MOP STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_MUL, DA, XX, XX, 'a'));
+       VMTEST_REG(co->cg, 0, 3, "RPA_MATCHCHR_MUL 'a'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MATCHCHR_MUL STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_MUL, DA, XX, XX, 'b'));
+       VMTEST_REG(co->cg, 0, -1, "RPA_MATCHCHR_MUL 'b'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_N, "RPA_MATCHCHR_MUL STATUS");
+
+}
+
+
+int main(int argc, char *argv[])
+{
+       rpa_compiler_t *co;
+       rpastat_t *stat;
+       ruint mainoff;
+       char teststr[] = "aaaaa";
+
+       co = rpa_compiler_create();
+       stat = rpa_stat_create(4096);
+       rvm_cpu_addswitable(stat->cpu, common_calltable);
+
+       rpa_stat_init(stat, teststr, teststr, teststr+3);
+
+       mainoff = rvm_codegen_addins(co->cg, rvm_asml(RVM_NOP, XX, XX, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, R_TOP, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, FP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, SP, DA, XX, 0));
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_nan", rvm_asm(RVM_MOV, R_MNODE_NAN, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_mul", rvm_asm(RVM_MOV, R_MNODE_MUL, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_opt", rvm_asm(RVM_MOV, R_MNODE_OPT, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_mop", rvm_asm(RVM_MOV, R_MNODE_MOP, DA, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
+       code_rpa_matchchr(co, stat);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_NOP, XX, XX, XX, 0xabc));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
+
+       rvm_cpu_exec(stat->cpu, rvm_codegen_getcode(co->cg, 0), mainoff);
+
+       rpa_stat_destroy(stat);
+       rpa_compiler_destroy(co);
+
+
+       r_printf("Max alloc mem: %ld\n", r_debug_get_maxmem());
+       r_printf("Leaked mem: %ld\n", r_debug_get_allocmem());
+       return 0;
+}
diff --git a/testrpa2/rpavm-mnode.c b/testrpa2/rpavm-mnode.c
new file mode 100644 (file)
index 0000000..b3749ff
--- /dev/null
@@ -0,0 +1,167 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "rmem.h"
+#include "rpacompiler.h"
+#include "rpastat.h"
+#include "common.h"
+
+
+
+void code_rpa_matchabc(rpa_compiler_t *co, rpastat_t *stat)
+{
+       rulong ruleidx;
+       const rchar *rule = "rpa_matchabc";
+       const rchar *ruleend = "rpa_matchabc_end";
+
+       ruleidx = rvm_codegen_addstring_s(co->cg, NULL, rule);
+       rvm_codegen_addlabel_s(co->cg, rule);
+
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'a'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'b'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'c'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITEND, DA, R1, R0, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       rvm_codegen_addlabel_s(co->cg, ruleend);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R0, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+}
+
+
+void code_rpa_matchxyz(rpa_compiler_t *co, rpastat_t *stat)
+{
+       rulong ruleidx;
+       const rchar *rule = "rpa_matchxyz";
+       const rchar *ruleend = "rpa_matchxyz_end";
+
+       ruleidx = rvm_codegen_addstring_s(co->cg, NULL, rule);
+       rvm_codegen_addlabel_s(co->cg, rule);
+
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'x'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'y'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'z'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITEND, DA, R1, R0, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       rvm_codegen_addlabel_s(co->cg, ruleend);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R0, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+}
+
+void code_rpa_matchmnode(rpa_compiler_t *co, rpastat_t *stat)
+{
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchabc", rvm_asm(RPA_BXLWHT, R_MNODE_NAN, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 3, "RPA_MNODE_NAN 'abc'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MNODE_NAN STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchxyz", rvm_asm(RPA_BXLWHT, R_MNODE_NAN, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, -1, "RPA_MNODE_NAN 'xyz'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_N, "RPA_MNODE_NAN STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchabc", rvm_asm(RPA_BXLWHT, R_MNODE_OPT, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 3, "RPA_MNODE_OPT 'abc'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MNODE_OPT STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchxyz", rvm_asm(RPA_BXLWHT, R_MNODE_OPT, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 0, "RPA_MNODE_OPT 'xyz'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_Z, "RPA_MNODE_OPT STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchabc", rvm_asm(RPA_BXLWHT, R_MNODE_MUL, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 12, "RPA_MNODE_MUL 'abc'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MNODE_MUL STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchxyz", rvm_asm(RPA_BXLWHT, R_MNODE_MUL, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, -1, "RPA_MNODE_MUL 'xyz'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_N, "RPA_MNODE_MUL STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchabc", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 12, "RPA_MNODE_MOP 'abc'");
+       VMTEST_STATUS(co->cg, 0, "RPA_MNODE_MOP STATUS");
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_matchxyz", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       VMTEST_REG(co->cg, 0, 0, "RPA_MNODE_MOP 'xyz'");
+       VMTEST_STATUS(co->cg, RVM_STATUS_Z, "RPA_MNODE_MOP STATUS");
+
+
+}
+
+
+int main(int argc, char *argv[])
+{
+       rvm_codelabel_t *err;
+       rpa_compiler_t *co;
+       rpastat_t *stat;
+       ruint mainoff;
+       char teststr[] = "abcabcabcabc";
+
+       co = rpa_compiler_create();
+       stat = rpa_stat_create(4096);
+       rvm_cpu_addswitable(stat->cpu, common_calltable);
+
+       rpa_stat_init(stat, teststr, teststr, teststr+12);
+
+       mainoff = rvm_codegen_addins(co->cg, rvm_asml(RVM_NOP, XX, XX, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, R_TOP, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, FP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, SP, DA, XX, 0));
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_nan", rvm_asm(RVM_MOV, R_MNODE_NAN, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_mul", rvm_asm(RVM_MOV, R_MNODE_MUL, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_opt", rvm_asm(RVM_MOV, R_MNODE_OPT, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_mop", rvm_asm(RVM_MOV, R_MNODE_MOP, DA, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
+       code_rpa_matchmnode(co, stat);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_NOP, XX, XX, XX, 0xabc));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
+       code_rpa_matchabc(co, stat);
+       code_rpa_matchxyz(co, stat);
+
+       if (rvm_codegen_relocate(co->cg, &err) < 0) {
+               r_printf("Unresolved symbol: %s\n", err->name->str);
+               goto end;
+       }
+
+       rvm_cpu_exec(stat->cpu, rvm_codegen_getcode(co->cg, 0), mainoff);
+
+end:
+       rpa_stat_destroy(stat);
+       rpa_compiler_destroy(co);
+
+
+       r_printf("Max alloc mem: %ld\n", r_debug_get_maxmem());
+       r_printf("Leaked mem: %ld\n", r_debug_get_allocmem());
+       return 0;
+}
diff --git a/testrpa2/rpavm-test.c b/testrpa2/rpavm-test.c
new file mode 100644 (file)
index 0000000..04bd144
--- /dev/null
@@ -0,0 +1,342 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "rmem.h"
+#include "rpacompiler.h"
+#include "rpastat.h"
+
+
+static int debuginfo = 0;
+static int parseinfo = 0;
+static int compileonly = 0;
+
+
+
+void codegen_rpa_match_aorb(rpa_compiler_t *co)
+{
+       rulong ruleidx;
+       const rchar *rule = "rpa_match_aorb";
+       const rchar *ruleend = "rpa_match_aorb_end";
+
+       ruleidx = rvm_codegen_addstring_s(co->cg, NULL, rule);
+       rvm_codegen_addlabel_s(co->cg, rule);
+
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'a'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_MOP, DA, XX, XX, 'b'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R0, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       rvm_codegen_addlabel_s(co->cg, ruleend);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITEND, DA, R1, R0, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+}
+
+
+void codegen_rpa_match_xyz(rpa_compiler_t *co)
+{
+       rulong ruleidx;
+       const rchar *rule = "rpa_match_xyz";
+       const rchar *ruleend = "rpa_match_xyz_end";
+
+       ruleidx = rvm_codegen_addstring_s(co->cg, NULL, rule);
+       rvm_codegen_addlabel_s(co->cg, rule);
+
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_match_squared", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'x'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_MOP, DA, XX, XX, 'y'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'z'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITEND, DA, R1, R0, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       rvm_codegen_addlabel_s(co->cg, ruleend);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R0, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+}
+
+
+void codegen_rpa_match_abc(rpa_compiler_t *co)
+{
+       rulong ruleidx;
+       const rchar *rule = "rpa_match_abc";
+       const rchar *ruleend = "rpa_match_abc_end";
+
+       ruleidx = rvm_codegen_addstring_s(co->cg, NULL, rule);
+       rvm_codegen_addlabel_s(co->cg, rule);
+
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'a'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_MOP, DA, XX, XX, 'b'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, 'c'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITEND, DA, R1, R0, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       rvm_codegen_addlabel_s(co->cg, ruleend);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R0, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+}
+
+
+void codegen_rpa_match_xyzorabc(rpa_compiler_t *co)
+{
+       rulong ruleidx;
+       const rchar *rule = "rpa_match_xyzorabc";
+       const rchar *ruleend = "rpa_match_xyzorabc_end";
+
+       ruleidx = rvm_codegen_addstring_s(co->cg, NULL, rule);
+       rvm_codegen_addlabel_s(co->cg, rule);
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_match_xyz", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_match_abc", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R0, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       rvm_codegen_addlabel_s(co->cg, ruleend);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITEND, DA, R1, R0, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+}
+
+
+
+void codegen_rpa_match_squared(rpa_compiler_t *co)
+{
+       rulong ruleidx;
+       const rchar *rule = "rpa_match_squared";
+       const rchar *ruleend = "rpa_match_squared_end";
+
+       ruleidx = rvm_codegen_addstring_s(co->cg, NULL, rule);
+       rvm_codegen_addlabel_s(co->cg, rule);
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, '['));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_match_xyzorabc", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_match_aorb", rvm_asm(RPA_BXLWHT, R_MNODE_MOP, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, ']'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHSPCHR_MOP, DA, XX, XX, 'n'));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_BRANCH, ruleend, rvm_asm(RVM_BLES, DA, XX, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
+       rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_STRING, ruleidx, rvm_asm(RPA_EMITEND, DA, R1, R0, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+       rvm_codegen_addlabel_s(co->cg, ruleend);
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_TOP)|BIT(R_WHT)|BIT(LR)));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R0, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
+}
+
+
+
+
+
+
+void codegen_unmap_file(rstr_t *buf)
+{
+       if (buf) {
+               munmap(buf->str, buf->size);
+               r_free(buf);
+       }
+}
+
+
+rstr_t *codegen_map_file(const char *filename)
+{
+       struct stat st;
+       rstr_t *str;
+       char *buffer;
+
+
+       int fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               return (void*)0;
+       }
+       if (fstat(fd, &st) < 0) {
+               close(fd);
+               return (void*)0;
+       }
+       buffer = (char*)mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+       if (buffer == (void*)-1) {
+               close(fd);
+               return (void*)0;
+       }
+       str = (rstr_t *)r_malloc(sizeof(*str));
+       if (!str)
+               goto error;
+       r_memset(str, 0, sizeof(*str));
+       str->str = buffer;
+       str->size = st.st_size;
+       close(fd);
+       return str;
+
+error:
+       munmap(buffer, st.st_size);
+       close(fd);
+       return str;
+}
+
+
+int main(int argc, char *argv[])
+{
+       rstr_t *script = NULL, *unmapscript = NULL;
+       rvm_codelabel_t *err;
+       rpa_compiler_t *co;
+       rpastat_t *stat;
+       ruint mainoff;
+       rint i;
+
+       co = rpa_compiler_create();
+       stat = rpa_stat_create(4096);
+
+       for (i = 1; i < argc; i++) {
+               if (r_strcmp(argv[i], "-L") == 0) {
+               } else if (r_strcmp(argv[i], "-d") == 0) {
+                       debuginfo = 1;
+               } else if (r_strcmp(argv[i], "-c") == 0) {
+                       compileonly = 1;
+               } else if (r_strcmp(argv[i], "-p") == 0) {
+                       parseinfo = 1;
+               }
+       }
+
+       for (i = 1; i < argc; i++) {
+               if (r_strcmp(argv[i], "-e") == 0) {
+                       if (++i < argc) {
+                               rstr_t bnfexpr = { argv[i], r_strlen(argv[i]) };
+                               rpa_stat_init(stat, bnfexpr.str, bnfexpr.str, bnfexpr.str + bnfexpr.size);
+                       }
+               }
+       }
+
+       for (i = 1; i < argc; i++) {
+               if (r_strcmp(argv[i], "-f") == 0) {
+                       if (++i < argc) {
+                               script = codegen_map_file(argv[i]);
+                               if (script) {
+                                       rpa_stat_init(stat, script->str, script->str, script->str + script->size);
+                                       unmapscript = script;
+                               }
+                       }
+                       goto exec;
+               }
+       }
+
+
+exec:
+
+       mainoff = rvm_codegen_addins(co->cg, rvm_asml(RVM_NOP, XX, XX, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, R_TOP, DA, XX, -1));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, FP, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asml(RVM_MOV, SP, DA, XX, 0));
+
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_nan", rvm_asm(RVM_MOV, R_MNODE_NAN, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_mul", rvm_asm(RVM_MOV, R_MNODE_MUL, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_opt", rvm_asm(RVM_MOV, R_MNODE_OPT, DA, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpacompiler_mnode_mop", rvm_asm(RVM_MOV, R_MNODE_MOP, DA, XX, 0));
+
+       rvm_codegen_addins(co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
+       rvm_codegen_addrelocins_s(co->cg, RVM_RELOC_JUMP, "rpa_match_squared", rvm_asm(RPA_BXLWHT, R_MNODE_MUL, DA, XX, 0));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_NOP, XX, XX, XX, 0xabc));
+       rvm_codegen_addins(co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
+
+       codegen_rpa_match_abc(co);
+       codegen_rpa_match_xyz(co);
+       codegen_rpa_match_xyzorabc(co);
+       codegen_rpa_match_aorb(co);
+       codegen_rpa_match_squared(co);
+
+       if (rvm_codegen_relocate(co->cg, &err) < 0) {
+               r_printf("Unresolved symbol: %s\n", err->name->str);
+               goto end;
+       }
+
+       if (debuginfo) {
+               fprintf(stdout, "\nGenerated Code:\n");
+               rvm_asm_dump(rvm_codegen_getcode(co->cg, 0), rvm_codegen_getcodesize(co->cg));
+               if (rvm_codegen_getcodesize(co->cg)) {
+                       if (!compileonly) {
+                               fprintf(stdout, "\nExecution:\n");
+                               rvm_cpu_exec_debug(stat->cpu, rvm_codegen_getcode(co->cg, 0), mainoff);
+                       }
+               }
+       } else {
+               if (!compileonly)
+                       rvm_cpu_exec(stat->cpu, rvm_codegen_getcode(co->cg, 0), mainoff);
+       }
+
+       r_printf("Matched: %d\n", RVM_CPUREG_GETU(stat->cpu, R0));
+end:
+
+       for (i = 0; 0 && i < r_array_length(stat->records); i++) {
+               rparecord_t *rec = (rparecord_t *)r_array_slot(stat->records, i);
+               if (rec->type & RPA_RECORD_MATCH) {
+                       r_printf("%d: rule: %s(%d, %d)\n", i, rec->rule, (rint)rec->top, (rint)rec->size);
+               }
+       }
+
+       rpa_stat_destroy(stat);
+       rpa_compiler_destroy(co);
+       if (unmapscript)
+               codegen_unmap_file(unmapscript);
+
+
+       if (debuginfo) {
+               r_printf("Max alloc mem: %ld\n", r_debug_get_maxmem());
+               r_printf("Leaked mem: %ld\n", r_debug_get_allocmem());
+       }
+       return 0;
+}