From 2eee391aef8efbc26da48819daf7f62054d0ccbe Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 17 Sep 2016 22:21:47 +0200 Subject: [PATCH 001/230] Basic skeleton of em parser. --- build.lua | 1 + mach/proto/mcg/build.lua | 37 ++++++ mach/proto/mcg/main.c | 250 ++++++++++++++++++++++++++++++++++++ mach/proto/mcg/push_pop.awk | 52 ++++++++ mach/proto/mcg/push_pop.h | 12 ++ 5 files changed, 352 insertions(+) create mode 100644 mach/proto/mcg/build.lua create mode 100644 mach/proto/mcg/main.c create mode 100644 mach/proto/mcg/push_pop.awk create mode 100644 mach/proto/mcg/push_pop.h diff --git a/build.lua b/build.lua index b5de879c8..abe441279 100644 --- a/build.lua +++ b/build.lua @@ -32,6 +32,7 @@ installable { "util/misc+pkg", "util/opt+pkg", "examples+pkg", + "mach/proto/mcg+pkg", plat_packages } } diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua new file mode 100644 index 000000000..ef53f2802 --- /dev/null +++ b/mach/proto/mcg/build.lua @@ -0,0 +1,37 @@ +normalrule { + name = "push_pop_c", + outleaves = { "push_pop.c" }, + ins = { + "./push_pop.awk", + "h/em_table" + }, + commands = { + "awk -f %{ins[1]} %{ins[2]} > %{outs}" + } +} + +cprogram { + name = "mcg", + srcs = { + "./*.c", + "+push_pop_c", + }, + deps = { + "h+emheaders", + "modules+headers", + "modules/src/read_em+lib_kv", + "modules/src/em_code+lib_k", + "modules/src/em_data+lib", + "modules/src/alloc+lib", + "modules/src/system+lib", + } +} + +-- Just for test purposes for now +installable { + name = "pkg", + map = { + ["$(PLATDEP)/mcg"] = "+mcg" + } +} + diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c new file mode 100644 index 000000000..2c04bca56 --- /dev/null +++ b/mach/proto/mcg/main.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include "em.h" +#include "em_comp.h" +#include "em_pseu.h" +#include "em_mnem.h" +#include "em_flag.h" +#include "em_ptyp.h" + +extern char em_pseu[][4]; +extern char em_mnem[][4]; +extern char em_flag[]; + +static void fatal(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + + va_end(ap); + exit(1); +} + +static const char* type_to_str(int type) +{ + switch (type) + { + case EM_MNEM: return "EM_MNEM"; + case EM_PSEU: return "EM_PSEU"; + case EM_STARTMES: return "EM_STARTMES"; + case EM_MESARG: return "EM_MESARG"; + case EM_ENDMES: return "EM_ENDMES"; + case EM_DEFILB: return "EM_DEFILB"; + case EM_DEFDLB: return "EM_DEFDLB"; + case EM_DEFDNAM: return "EM_DEFDNAM"; + case EM_ERROR: return "EM_ERROR"; + case EM_FATAL: return "EM_FATAL"; + case EM_EOF: return "EM_EOF"; + } + + assert(0 && "invalid EM type"); +} + +static const char* argtype_to_str(int type) +{ + if (type == 0) return "..."; + if (type == ilb_ptyp) return "ilb"; + if (type == nof_ptyp) return "nof"; + if (type == sof_ptyp) return "sof"; + if (type == cst_ptyp) return "cst"; + if (type == pro_ptyp) return "pro"; + if (type == str_ptyp) return "str"; + if (type == ico_ptyp) return "ico"; + if (type == uco_ptyp) return "uco"; + if (type == fco_ptyp) return "fco"; + return "???"; +} + +int main(int argc, const char* argv[]) +{ + struct e_instr insn; + + if (!EM_open(argv[1])) + fatal("Couldn't open input file: %s", EM_error); + + EM_getinstr(&insn); + printf("; word size = %d\n", EM_wordsize); + printf("; pointer size = %d\n", EM_pointersize); + + while (insn.em_type != EM_EOF) + { + printf("%s %s ", + type_to_str(insn.em_type), + argtype_to_str(insn.em_arg.ema_argtype)); + + switch (insn.em_type) + { + case EM_PSEU: + printf("%s ", em_pseu[insn.em_opcode - sp_fpseu]); + switch (insn.em_opcode) + { + case ps_exp: /* external proc */ + case ps_exa: /* external array */ + case ps_inp: /* internal proc */ + case ps_ina: /* internal array */ + switch (insn.em_arg.ema_argtype) + { + case pro_ptyp: + printf("name=%s\n", insn.em_pnam); + break; + + case sof_ptyp: + printf("name=%s offset=0x%x\n", + insn.em_dnam, + insn.em_off); + break; + + default: + printf("name=?\n"); + } + break; + + case ps_con: /* .data */ + case ps_rom: /* .rom */ + printf("size=%d ", + insn.em_size); + + switch (insn.em_arg.ema_argtype) + { + case ico_ptyp: + case uco_ptyp: + case fco_ptyp: + case str_ptyp: + printf("val=%s\n", insn.em_string); + break; + + default: + printf("val=?\n"); + } + break; + + case ps_pro: /* procedure start */ + printf("\n\n%s %d\n", + insn.em_arg.ema_pnam, + insn.em_arg.ema_szoroff); + break; + + case ps_end: /* procedure end */ + printf("%d\n\n\n", + insn.em_arg.ema_szoroff); + break; + + default: + printf("???\n"); + } + break; + + case EM_DEFILB: + printf("code label %d\n", insn.em_ilb); + break; + + case EM_DEFDLB: + printf("data label %d\n", insn.em_dlb); + break; + + case EM_DEFDNAM: + printf("data label %s\n", insn.em_dnam); + break; + + case EM_STARTMES: + for (;;) + { + switch (insn.em_arg.ema_argtype) + { + case cst_ptyp: + printf("%d ", insn.em_cst); + break; + + case str_ptyp: + printf("%s ", insn.em_string); + break; + + default: + printf("(unknown %s) ", + argtype_to_str(insn.em_arg.ema_argtype)); + } + + EM_getinstr(&insn); + if (insn.em_type == EM_ENDMES) + break; + assert(insn.em_type == EM_MESARG); + } + printf("\n"); + break; + + case EM_MNEM: + { + int flag = em_flag[insn.em_opcode - sp_fmnem]; + printf("%s %c%c%c%c ", + em_mnem[insn.em_opcode - sp_fmnem], + "/CDNFLGWSZOPBR"[flag & EM_PAR], + (flag & FLO_C) ? 'c' : '.', + (flag & FLO_P) ? 'p' : '.', + (flag & FLO_T) ? 't' : '.'); + + if (flag & EM_PAR) + { + switch (insn.em_argtype) + { + case ilb_ptyp: + printf("ilb "); + break; + + case nof_ptyp: + printf("nof "); + break; + + case sof_ptyp: + printf("sof "); + break; + + case cst_ptyp: + printf("cst 0x%08x ", insn.em_cst); + break; + + case pro_ptyp: + printf("pro "); + break; + + case str_ptyp: + printf("str "); + break; + + case ico_ptyp: + printf("ico "); + break; + + case uco_ptyp: + printf("uco "); + break; + + case fco_ptyp: + printf("fco "); + break; + + default: + printf("???"); + } + } + printf("\n"); + break; + } + + default: + printf("%d\n", insn.em_opcode); + break; + } + + EM_getinstr(&insn); + } + + EM_close(); + return 0; +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/push_pop.awk b/mach/proto/mcg/push_pop.awk new file mode 100644 index 000000000..125e6a807 --- /dev/null +++ b/mach/proto/mcg/push_pop.awk @@ -0,0 +1,52 @@ +BEGIN { + print "#include " + print "#include \"push_pop.h\"" + print "" + + s = 0; + count = 0; +} + +/^aar/ { + s = 1; +} + +/^[a-z]/ { + if (!s) + next; + + opcode[count++] = $1; + data[$1] = $3; +} + +END { + for (op in data) + { + print "static const struct stackop so_" op "[] = {"; + + pushpops = data[op] + if (pushpops != "0") + { + for (i=1; i<=length(pushpops); i+=2) + { + printf "\t{ "; + if (substr(pushpops, i, 1) == "+") + printf "true, "; + else + printf "false, "; + + printf("'%s' },\n", substr(pushpops, i+1, 1)); + } + } + print "\t{ false, 0 }" + + print "};"; + print ""; + } + + print "const struct stackop* stackops[] = {"; + for (i=0; i Date: Sun, 18 Sep 2016 00:02:16 +0200 Subject: [PATCH 002/230] Abstract out the EM reader; skeleton of the tree builder. --- mach/proto/mcg/main.c | 233 +-------------------------- mach/proto/mcg/mcg.h | 47 ++++++ mach/proto/mcg/parse_em.c | 295 +++++++++++++++++++++++++++++++++++ mach/proto/mcg/push_pop.awk | 4 +- mach/proto/mcg/push_pop.h | 2 +- mach/proto/mcg/treebuilder.c | 94 +++++++++++ modules/h/em_label.h | 3 +- 7 files changed, 446 insertions(+), 232 deletions(-) create mode 100644 mach/proto/mcg/mcg.h create mode 100644 mach/proto/mcg/parse_em.c create mode 100644 mach/proto/mcg/treebuilder.c diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 2c04bca56..035259d54 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -1,19 +1,7 @@ -#include -#include -#include -#include -#include "em.h" +#include "mcg.h" #include "em_comp.h" -#include "em_pseu.h" -#include "em_mnem.h" -#include "em_flag.h" -#include "em_ptyp.h" -extern char em_pseu[][4]; -extern char em_mnem[][4]; -extern char em_flag[]; - -static void fatal(const char* msg, ...) +void fatal(const char* msg, ...) { va_list ap; va_start(ap, msg); @@ -22,226 +10,15 @@ static void fatal(const char* msg, ...) fprintf(stderr, "\n"); va_end(ap); - exit(1); + abort(); } -static const char* type_to_str(int type) +int main(int argc, char* argv[]) { - switch (type) - { - case EM_MNEM: return "EM_MNEM"; - case EM_PSEU: return "EM_PSEU"; - case EM_STARTMES: return "EM_STARTMES"; - case EM_MESARG: return "EM_MESARG"; - case EM_ENDMES: return "EM_ENDMES"; - case EM_DEFILB: return "EM_DEFILB"; - case EM_DEFDLB: return "EM_DEFDLB"; - case EM_DEFDNAM: return "EM_DEFDNAM"; - case EM_ERROR: return "EM_ERROR"; - case EM_FATAL: return "EM_FATAL"; - case EM_EOF: return "EM_EOF"; - } - - assert(0 && "invalid EM type"); -} - -static const char* argtype_to_str(int type) -{ - if (type == 0) return "..."; - if (type == ilb_ptyp) return "ilb"; - if (type == nof_ptyp) return "nof"; - if (type == sof_ptyp) return "sof"; - if (type == cst_ptyp) return "cst"; - if (type == pro_ptyp) return "pro"; - if (type == str_ptyp) return "str"; - if (type == ico_ptyp) return "ico"; - if (type == uco_ptyp) return "uco"; - if (type == fco_ptyp) return "fco"; - return "???"; -} - -int main(int argc, const char* argv[]) -{ - struct e_instr insn; - if (!EM_open(argv[1])) fatal("Couldn't open input file: %s", EM_error); - EM_getinstr(&insn); - printf("; word size = %d\n", EM_wordsize); - printf("; pointer size = %d\n", EM_pointersize); - - while (insn.em_type != EM_EOF) - { - printf("%s %s ", - type_to_str(insn.em_type), - argtype_to_str(insn.em_arg.ema_argtype)); - - switch (insn.em_type) - { - case EM_PSEU: - printf("%s ", em_pseu[insn.em_opcode - sp_fpseu]); - switch (insn.em_opcode) - { - case ps_exp: /* external proc */ - case ps_exa: /* external array */ - case ps_inp: /* internal proc */ - case ps_ina: /* internal array */ - switch (insn.em_arg.ema_argtype) - { - case pro_ptyp: - printf("name=%s\n", insn.em_pnam); - break; - - case sof_ptyp: - printf("name=%s offset=0x%x\n", - insn.em_dnam, - insn.em_off); - break; - - default: - printf("name=?\n"); - } - break; - - case ps_con: /* .data */ - case ps_rom: /* .rom */ - printf("size=%d ", - insn.em_size); - - switch (insn.em_arg.ema_argtype) - { - case ico_ptyp: - case uco_ptyp: - case fco_ptyp: - case str_ptyp: - printf("val=%s\n", insn.em_string); - break; - - default: - printf("val=?\n"); - } - break; - - case ps_pro: /* procedure start */ - printf("\n\n%s %d\n", - insn.em_arg.ema_pnam, - insn.em_arg.ema_szoroff); - break; - - case ps_end: /* procedure end */ - printf("%d\n\n\n", - insn.em_arg.ema_szoroff); - break; - - default: - printf("???\n"); - } - break; - - case EM_DEFILB: - printf("code label %d\n", insn.em_ilb); - break; - - case EM_DEFDLB: - printf("data label %d\n", insn.em_dlb); - break; - - case EM_DEFDNAM: - printf("data label %s\n", insn.em_dnam); - break; - - case EM_STARTMES: - for (;;) - { - switch (insn.em_arg.ema_argtype) - { - case cst_ptyp: - printf("%d ", insn.em_cst); - break; - - case str_ptyp: - printf("%s ", insn.em_string); - break; - - default: - printf("(unknown %s) ", - argtype_to_str(insn.em_arg.ema_argtype)); - } - - EM_getinstr(&insn); - if (insn.em_type == EM_ENDMES) - break; - assert(insn.em_type == EM_MESARG); - } - printf("\n"); - break; - - case EM_MNEM: - { - int flag = em_flag[insn.em_opcode - sp_fmnem]; - printf("%s %c%c%c%c ", - em_mnem[insn.em_opcode - sp_fmnem], - "/CDNFLGWSZOPBR"[flag & EM_PAR], - (flag & FLO_C) ? 'c' : '.', - (flag & FLO_P) ? 'p' : '.', - (flag & FLO_T) ? 't' : '.'); - - if (flag & EM_PAR) - { - switch (insn.em_argtype) - { - case ilb_ptyp: - printf("ilb "); - break; - - case nof_ptyp: - printf("nof "); - break; - - case sof_ptyp: - printf("sof "); - break; - - case cst_ptyp: - printf("cst 0x%08x ", insn.em_cst); - break; - - case pro_ptyp: - printf("pro "); - break; - - case str_ptyp: - printf("str "); - break; - - case ico_ptyp: - printf("ico "); - break; - - case uco_ptyp: - printf("uco "); - break; - - case fco_ptyp: - printf("fco "); - break; - - default: - printf("???"); - } - } - printf("\n"); - break; - } - - default: - printf("%d\n", insn.em_opcode); - break; - } - - EM_getinstr(&insn); - } + parse_em(); EM_close(); return 0; diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h new file mode 100644 index 000000000..e008249ed --- /dev/null +++ b/mach/proto/mcg/mcg.h @@ -0,0 +1,47 @@ +#ifndef MCG_H +#define MCG_H + +#include +#include +#include +#include +#include +#include +#include +#include "em_arith.h" +#include "em_label.h" +#include "em.h" +#include "em_comp.h" +#include "em_pseu.h" +#include "em_mnem.h" +#include "em_flag.h" +#include "em_ptyp.h" + +extern char em_pseu[][4]; +extern char em_mnem[][4]; +extern char em_flag[]; + + +extern void fatal(const char* s, ...); + +extern void parse_em(void); + +extern void tb_filestart(void); +extern void tb_fileend(void); +extern void tb_symbol(const char* name, bool is_exported, bool is_proc); +extern void tb_dlabel(const char* label); +extern void tb_ilabel(const char* label); +extern void tb_data(const uint8_t* data, size_t size, bool is_ro); +extern void tb_data_offset(const char* label, arith offset, bool is_ro); +extern void tb_bss(size_t size, uint8_t init); +extern void tb_procstart(const char* label, size_t nlocals); +extern void tb_procend(void); +extern void tb_regvar(arith offset, int size, int type, int priority); + +extern void tb_insn_simple(int opcode, int flags); +extern void tb_insn_label(int opcode, int flags, const char* label, arith offset); +extern void tb_insn_value(int opcode, int flags, arith value); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c new file mode 100644 index 000000000..11aeb5c17 --- /dev/null +++ b/mach/proto/mcg/parse_em.c @@ -0,0 +1,295 @@ +#include "mcg.h" + +static struct e_instr insn; + +static const char* type_to_str(int type) +{ + switch (type) + { + case EM_MNEM: return "EM_MNEM"; + case EM_PSEU: return "EM_PSEU"; + case EM_STARTMES: return "EM_STARTMES"; + case EM_MESARG: return "EM_MESARG"; + case EM_ENDMES: return "EM_ENDMES"; + case EM_DEFILB: return "EM_DEFILB"; + case EM_DEFDLB: return "EM_DEFDLB"; + case EM_DEFDNAM: return "EM_DEFDNAM"; + case EM_ERROR: return "EM_ERROR"; + case EM_FATAL: return "EM_FATAL"; + case EM_EOF: return "EM_EOF"; + } + + assert(0 && "invalid EM type"); +} + +static const char* argtype_to_str(int type) +{ + if (type == 0) return "..."; + if (type == ilb_ptyp) return "ilb"; + if (type == nof_ptyp) return "nof"; + if (type == sof_ptyp) return "sof"; + if (type == cst_ptyp) return "cst"; + if (type == pro_ptyp) return "pro"; + if (type == str_ptyp) return "str"; + if (type == ico_ptyp) return "ico"; + if (type == uco_ptyp) return "uco"; + if (type == fco_ptyp) return "fco"; + return "???"; +} + +static void unknown_type(const char* s) +{ + fatal("%s with unknown type '%s'", + s, + argtype_to_str(insn.em_arg.ema_argtype)); +} + +static const uint8_t* arith_to_bytes(arith a, size_t sz) +{ + uint8_t* p = malloc(8); + + switch (sz) + { + case 1: *(uint8_t*)p = a; break; + case 2: *(uint16_t*)p = a; break; + case 4: *(uint32_t*)p = a; break; + case 8: *(uint64_t*)p = a; break; + default: + fatal("bad constant size '%d'", sz); + } + + return p; +} + +static const char* ilabel_to_str(label l) +{ + char s[16]; + sprintf(s, "__I%d", l); + return strdup(s); +} + +static const char* dlabel_to_str(label l) +{ + char s[16]; + sprintf(s, ".%d", l); + return strdup(s); +} + +static void parse_pseu(void) +{ + switch (insn.em_opcode) + { + case ps_exp: /* external proc */ + case ps_exa: /* external array */ + case ps_inp: /* internal proc */ + case ps_ina: /* internal array */ + { + bool export = (insn.em_opcode == ps_exp) || (insn.em_opcode == ps_exa); + bool proc = (insn.em_opcode == ps_exp) || (insn.em_opcode == ps_inp); + + switch (insn.em_arg.ema_argtype) + { + case pro_ptyp: + tb_symbol(strdup(insn.em_pnam), export, proc); + break; + + case sof_ptyp: + assert(insn.em_off == 0); + tb_symbol(strdup(insn.em_dnam), export, proc); + break; + + case nof_ptyp: + assert(insn.em_off == 0); + tb_symbol(dlabel_to_str(insn.em_dlb), export, proc); + break; + + default: + unknown_type("exp, exa, inp, ina"); + } + break; + } + + case ps_con: /* .data */ + case ps_rom: /* .rom */ + { + bool ro = (insn.em_opcode == ps_rom); + + switch (insn.em_arg.ema_argtype) + { + case ico_ptyp: + case uco_ptyp: + { + arith val = atol(insn.em_string); + tb_data(arith_to_bytes(val, insn.em_size), insn.em_size, ro); + break; + } + + case str_ptyp: + tb_data(strdup(insn.em_string), insn.em_size, ro); + break; + + case cst_ptyp: + tb_data(arith_to_bytes(insn.em_cst, EM_wordsize), EM_wordsize, ro); + break; + + case nof_ptyp: + tb_data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro); + break; + + case ilb_ptyp: + tb_data_offset(ilabel_to_str(insn.em_ilb), 0, ro); + break; + + default: + unknown_type("con, rom"); + } + break; + } + + case ps_bss: + { + switch (insn.em_arg.ema_argtype) + { + case cst_ptyp: + tb_bss(EM_bsssize, EM_bssinit); + break; + + default: + unknown_type("bss"); + } + break; + } + + case ps_pro: /* procedure start */ + if (insn.em_nlocals == -1) + fatal("procedures with unspecified number of locals are not supported yet"); + + tb_procstart(strdup(insn.em_pnam), insn.em_nlocals); + break; + + case ps_end: /* procedure end */ + tb_procend(); + break; + + default: + fatal("unknown pseudo with opcode %d\n", insn.em_opcode); + } +} + +static arith mes_get_cst(void) +{ + EM_getinstr(&insn); + if (insn.em_type != EM_MESARG) + fatal("malformed MES"); + return insn.em_cst; +} + +static void parse_mes(void) +{ + assert(insn.em_arg.ema_argtype == cst_ptyp); + switch (insn.em_cst) + { + case 0: /* error */ + fatal("MES 0 received (explicit halt)"); + + case 3: /* register variable */ + { + arith offset = mes_get_cst(); + int size = mes_get_cst(); + int type = mes_get_cst(); + int priority = mes_get_cst(); + tb_regvar(offset, size, type, priority); + break; + } + } + + while ((insn.em_type == EM_STARTMES) || (insn.em_type == EM_MESARG)) + EM_getinstr(&insn); + + if (insn.em_type != EM_ENDMES) + fatal("malformed MES"); +} + +void parse_em(void) +{ + EM_getinstr(&insn); + tb_filestart(); + + while (insn.em_type != EM_EOF) + { + switch (insn.em_type) + { + case EM_PSEU: + parse_pseu(); + break; + + case EM_DEFILB: + tb_ilabel(ilabel_to_str(insn.em_ilb)); + break; + + case EM_DEFDLB: + tb_dlabel(dlabel_to_str(insn.em_dlb)); + break; + + case EM_DEFDNAM: + tb_dlabel(strdup(insn.em_dnam)); + break; + + case EM_STARTMES: + parse_mes(); + break; + + case EM_MNEM: + { + int flags = em_flag[insn.em_opcode - sp_fmnem]; + + if (flags & EM_PAR) + { + switch (insn.em_argtype) + { + case ilb_ptyp: + tb_insn_label(insn.em_opcode, flags, + ilabel_to_str(insn.em_ilb), 0); + break; + + case nof_ptyp: + tb_insn_label(insn.em_opcode, flags, + dlabel_to_str(insn.em_dlb), insn.em_off); + break; + + case sof_ptyp: + tb_insn_label(insn.em_opcode, flags, + strdup(insn.em_dnam), insn.em_off); + break; + + case pro_ptyp: + tb_insn_label(insn.em_opcode, flags, + strdup(insn.em_pnam), 0); + break; + + case cst_ptyp: + tb_insn_value(insn.em_opcode, flags, + insn.em_cst); + break; + + default: + unknown_type("instruction"); + } + } + else + tb_insn_simple(insn.em_opcode, flags); + + break; + } + + default: + fatal("unrecognised instruction type '%d'", insn.em_type); + } + + EM_getinstr(&insn); + } + + tb_fileend(); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/push_pop.awk b/mach/proto/mcg/push_pop.awk index 125e6a807..83560912e 100644 --- a/mach/proto/mcg/push_pop.awk +++ b/mach/proto/mcg/push_pop.awk @@ -44,9 +44,9 @@ END { print ""; } - print "const struct stackop* stackops[] = {"; + print "const struct stackop* const stackops[] = {"; for (i=0; i Date: Sun, 18 Sep 2016 00:23:42 +0200 Subject: [PATCH 003/230] ANSIise to fix warnings. --- modules/src/idf/idf_pkg.body | 124 ++++++++++++++++++----------------- modules/src/idf/idf_pkg.spec | 4 +- 2 files changed, 67 insertions(+), 61 deletions(-) diff --git a/modules/src/idf/idf_pkg.body b/modules/src/idf/idf_pkg.body index 4b71bfaaa..8f970aef7 100644 --- a/modules/src/idf/idf_pkg.body +++ b/modules/src/idf/idf_pkg.body @@ -1,15 +1,15 @@ /* SYMBOL TABLE HANDLING */ -#include +#include -#define IDF_HASHSIZE 307 /* size of hashtable, must be odd */ +#define IDF_HASHSIZE 307 /* size of hashtable, must be odd */ -#define IDF_STARTHASH(hs) (hs = 0) -#define IDF_ENHASH(hs,ch) (hs = (hs << 2) + ch) -#define IDF_STOPHASH(hs) (hs = hs % IDF_HASHSIZE) +#define IDF_STARTHASH(hs) (hs = 0) +#define IDF_ENHASH(hs, ch) (hs = (hs << 2) + ch) +#define IDF_STOPHASH(hs) (hs = hs % IDF_HASHSIZE) -static struct idf *IDF_hashtable[IDF_HASHSIZE]; - /* All identifiers can in principle be reached through +static struct idf* IDF_hashtable[IDF_HASHSIZE]; +/* All identifiers can in principle be reached through IDF_hashtable; IDF_hashtable[hc] is the start of a chain of idf's whose tags all hash to hc. Any identifier is entered into this @@ -17,69 +17,71 @@ static struct idf *IDF_hashtable[IDF_HASHSIZE]; (variable, selector, structure tag, etc.). */ -_PROTOTYPE(static struct idf *IDF_new, (char *, int, int)); +static struct idf* IDF_new(char* tg, int size, int cpy); -void -init_idf() +void init_idf() { } -static struct idf * -IDF_new(tg, size, cpy) - register char *tg; - register int size; +static struct idf* IDF_new(char* tg, int size, int cpy) { static int nidf; - static struct idf *pidf; + static struct idf* pidf; static struct idf null_idf; - register struct idf *id; + register struct idf* id; #define NIDS 50 -#define IBUFSIZ 2048 +#define IBUFSIZ 2048 static unsigned int icnt; - static char *ip; - register char *p; + static char* ip; + register char* p; - - if (! nidf--) { + if (!nidf--) + { nidf += NIDS; - pidf = (struct idf *) Malloc(NIDS * sizeof (struct idf)); + pidf = (struct idf*)Malloc(NIDS * sizeof(struct idf)); } id = pidf; pidf++; *id = null_idf; - if (cpy) { - if (size > icnt) { - icnt = size > IBUFSIZ ? size : IBUFSIZ; + if (cpy) + { + if (size > icnt) + { + icnt = size > IBUFSIZ ? size : IBUFSIZ; p = Malloc(icnt); } - else p = ip; + else + p = ip; icnt -= size; id->id_text = p; - while (size--) { + while (size--) + { *p++ = *tg++; } ip = p; } - else id->id_text = tg; + else + id->id_text = tg; return id; } -#ifdef IDF_DEBUG -void -hash_stat() +#ifdef IDF_DEBUG +void hash_stat(void) { register int i; int total_count = 0; print("Hash table tally:\n"); - for (i = 0; i < IDF_HASHSIZE; i++) { - register struct idf *notch = IDF_hashtable[i]; + for (i = 0; i < IDF_HASHSIZE; i++) + { + register struct idf* notch = IDF_hashtable[i]; register int cnt = 0; - print ("%d ", i); - while (notch) { + print("%d ", i); + while (notch) + { cnt++; print("'%s' ", notch->id_text); notch = notch->id_next; @@ -91,40 +93,38 @@ hash_stat() print("End hash table tally\n"); } -void -idfappfun(fun, opt) - int (*fun)(); - int opt; +void idfappfun(int (*fun)(), int opt) { - register int i; + register int i; - for (i = 0; i < IDF_HASHSIZE; i++) { - register struct idf *notch = IDF_hashtable[i]; + for (i = 0; i < IDF_HASHSIZE; i++) + { + register struct idf* notch = IDF_hashtable[i]; - while (notch) { + while (notch) + { (*fun)(notch, opt); notch = notch->id_next; } } } -#endif /* IDF_DEBUG */ +#endif /* IDF_DEBUG */ -struct idf * -str2idf(tg, cpy) - char tg[]; +struct idf* str2idf(char tg[], int cpy) { /* str2idf() returns an entry in the symbol table for the identifier tg. If necessary, an entry is created. */ - register char *cp = tg; - struct idf **hook; - register struct idf *notch; + register char* cp = tg; + struct idf** hook; + register struct idf* notch; register unsigned int hash; register int c; int size; IDF_STARTHASH(hash); - while (c = *cp++) { + while (c = *cp++) + { IDF_ENHASH(hash, c); } IDF_STOPHASH(hash); @@ -137,25 +137,31 @@ str2idf(tg, cpy) */ hook = &IDF_hashtable[hash]; - while ((notch = *hook)) { - register char *s1 = tg; + while ((notch = *hook)) + { + register char* s1 = tg; cp = notch->id_text; - while (!(c = (*s1 - *cp++))) { - if (*s1++ == '\0') { + while (!(c = (*s1 - *cp++))) + { + if (*s1++ == '\0') + { break; } } - if (c == 0) return notch; - if (c < 0) break; + if (c == 0) + return notch; + if (c < 0) + break; hook = ¬ch->id_next; } /* a new struct idf must be inserted at the hook */ - if (cpy < 0) return 0; + if (cpy < 0) + return 0; notch = IDF_new(tg, size, cpy); notch->id_next = *hook; - *hook = notch; /* hooked in */ + *hook = notch; /* hooked in */ return notch; } diff --git a/modules/src/idf/idf_pkg.spec b/modules/src/idf/idf_pkg.spec index 42d65d25f..3db6b9d5f 100644 --- a/modules/src/idf/idf_pkg.spec +++ b/modules/src/idf/idf_pkg.spec @@ -27,7 +27,7 @@ struct idf { Initializes the namelist. */ -_PROTOTYPE(void init_idf, (void)); +extern void init_idf(void); /* struct idf * str2idf(tg, cp) char *tg; @@ -40,6 +40,6 @@ _PROTOTYPE(void init_idf, (void)); If cp < 0, the string is not entered, but only looked for. */ -_PROTOTYPE(struct idf *str2idf, (char *, int)); +struct idf *str2idf(char* tg, int cp); #define findidf(tg) str2idf(tg, -1) From 176cd7365c5bf441624ac5f0771c233ca21de3f6 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 18 Sep 2016 23:24:54 +0200 Subject: [PATCH 004/230] Archival checking of the half-written IR treebuilder. --- mach/proto/mcg/array.c | 39 ++++ mach/proto/mcg/array.h | 23 ++ mach/proto/mcg/basicblock.c | 70 ++++++ mach/proto/mcg/build.lua | 22 +- mach/proto/mcg/data.c | 113 ++++++++++ mach/proto/mcg/ir.c | 137 ++++++++++++ mach/proto/mcg/ir.dat | 33 +++ mach/proto/mcg/ir.h | 53 +++++ mach/proto/mcg/ircodes.sh | 14 ++ mach/proto/mcg/main.c | 24 ++- mach/proto/mcg/mcg.h | 55 ++++- mach/proto/mcg/parse_em.c | 63 +++--- mach/proto/mcg/push_pop.awk | 52 ----- mach/proto/mcg/push_pop.h | 12 -- mach/proto/mcg/symbol.c | 41 ++++ mach/proto/mcg/treebuilder.c | 405 +++++++++++++++++++++++++++++++---- 16 files changed, 998 insertions(+), 158 deletions(-) create mode 100644 mach/proto/mcg/array.c create mode 100644 mach/proto/mcg/array.h create mode 100644 mach/proto/mcg/basicblock.c create mode 100644 mach/proto/mcg/data.c create mode 100644 mach/proto/mcg/ir.c create mode 100644 mach/proto/mcg/ir.dat create mode 100644 mach/proto/mcg/ir.h create mode 100755 mach/proto/mcg/ircodes.sh delete mode 100644 mach/proto/mcg/push_pop.awk delete mode 100644 mach/proto/mcg/push_pop.h create mode 100644 mach/proto/mcg/symbol.c diff --git a/mach/proto/mcg/array.c b/mach/proto/mcg/array.c new file mode 100644 index 000000000..1b72352b0 --- /dev/null +++ b/mach/proto/mcg/array.c @@ -0,0 +1,39 @@ +#include "mcg.h" +#include "array.h" + +void array_append(void*** array, int* count, int* max, void* value) +{ + if (*count == *max) + { + int newmax = (*max == 0) ? 8 : (*max * 2); + void** newarray = realloc(*array, newmax * sizeof(void*)); + if (!newarray) + fatal("memory allocation failure"); + + *max = newmax; + *array = newarray; + } + + (*array)[*count] = value; + (*count)++; +} + +bool array_contains(void** array, int count, void* value) +{ + int i; + + for (i=0; i +#include + +static int next_id = 0; + +void bb_init(void) +{ + init_idf(); +} + +struct basicblock* bb_get(const char* name) +{ + struct idf* p; + + if (!name) + name = aprintf("___anon_bb_%d", next_id++); + p = str2idf((char*) name, 0); + if (!p->block) + { + p->block = calloc(sizeof(struct basicblock), 1); + p->block->name = name; + } + return p->block; +} + +void bb_alias(struct basicblock* block, const char* name) +{ + struct idf* p = str2idf((char*) name, -1); + assert(p == NULL); + + p = str2idf((char*) name, 0); + p->block = block; +} + +void bb_wire_outs_to_ins(struct basicblock* inblock, struct basicblock* outblock) +{ + int i; + + if (!outblock->is_wired) + { + for (i=0; iouts_count; i++) + { + struct ir* value = inblock->outs[i]; + APPEND(outblock->ins, + new_phiir(value->size) + ); + } + outblock->is_wired = true; + } + + assert(inblock->outs_count == outblock->ins_count); + for (i=0; iouts_count; i++) + { + struct ir* srcvalue = inblock->outs[i]; + struct ir* destvalue = outblock->ins[i]; + assert(srcvalue->size == destvalue->size); + assert(destvalue->opcode == IR_PHI); + + APPENDU(destvalue->u.phivalue.srcs, srcvalue); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index ef53f2802..5db304b46 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -1,12 +1,12 @@ normalrule { - name = "push_pop_c", - outleaves = { "push_pop.c" }, + name = "ircodes", + outleaves = { "ircodes.h", "ircodes.c" }, ins = { - "./push_pop.awk", - "h/em_table" + "./ircodes.sh", + "./ir.dat" }, commands = { - "awk -f %{ins[1]} %{ins[2]} > %{outs}" + "%{ins[1]} %{ins[2]} %{outs[1]} %{outs[2]}" } } @@ -14,16 +14,22 @@ cprogram { name = "mcg", srcs = { "./*.c", - "+push_pop_c", + matching(filenamesof("+ircodes"), "%.c$") }, deps = { + "+ircodes", "h+emheaders", "modules+headers", - "modules/src/read_em+lib_kv", + "modules/src/alloc+lib", "modules/src/em_code+lib_k", "modules/src/em_data+lib", - "modules/src/alloc+lib", + "modules/src/idf+lib", + "modules/src/read_em+lib_kv", "modules/src/system+lib", + "./*.h", + }, + vars = { + ["+cflags"] = {"-Werror-implicit-function-declaration"} } } diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c new file mode 100644 index 000000000..acc14c0fd --- /dev/null +++ b/mach/proto/mcg/data.c @@ -0,0 +1,113 @@ +#include "mcg.h" +#include + +static struct symbol* pending; + +void data_label(const char* label) +{ + if (pending) + fatal("two consecutive data labels ('%s' and '%s')", + pending->name, label); + + pending = symbol_get(label); + if (pending->is_defined) + fatal("label '%s' defined twice", pending->name); + pending->is_defined = true; +} + +static const char* section_to_str(int section) +{ + switch (section) + { + case SECTION_ROM: return ".rom"; + case SECTION_DATA: return ".data"; + case SECTION_BSS: return ".bss"; + case SECTION_TEXT: return ".text"; + default: return "unknown"; + } +} + +static void emit_header(int desired_section) +{ + if (pending) + { + if (pending->section == SECTION_UNKNOWN) + pending->section = desired_section; + else if (pending->section != desired_section) + fatal("label '%s' can't change sections", pending->name); + + printf("\n.sect %s\n", section_to_str(pending->section)); + printf("%s:\n", pending->name); + pending = NULL; + } +} + +void data_int(arith data, size_t size, bool is_ro) +{ + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + assert((size == 1) || (size == 2) || (size == 4) || (size == 8)); + printf("\t.data%d 0x%0*lld\n", size, size*2, data); +} + +void data_block(const uint8_t* data, size_t size, bool is_ro) +{ + const uint8_t* start = data; + const uint8_t* end = data + size; + const uint8_t* p = data; + + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + + start = p = data; + while (p < end) + { + while ((p < end) && isprint(*p)) + p++; + + if (start < p) + { + printf("\t.ascii \""); + while (start < p) + { + printf("%c", *start); + start++; + } + printf("\"\n"); + } + + while ((p < end) && !isprint(*p)) + p++; + + if (start < p) + { + bool first = true; + + printf("\t.data1 "); + while (start < p) + { + if (!first) + printf(", "); + printf("0x%02x", *start); + start++; + first = false; + } + printf("\n"); + } + } +} + +void data_offset(const char* label, arith offset, bool is_ro) +{ + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + printf("\t.data%d %s+%lld\n", EM_pointersize, label, offset); +} + +void data_bss(arith size, int init) +{ + if (init != 0) + fatal("non-zero-initialised bss not supported"); + + emit_header(SECTION_BSS); + printf("\t.space %lld\n", size); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c new file mode 100644 index 000000000..8973bfc73 --- /dev/null +++ b/mach/proto/mcg/ir.c @@ -0,0 +1,137 @@ +#include "mcg.h" + +static int next_id = 0; + +struct ir* new_ir0(int opcode, int size) +{ + struct ir* ir = calloc(sizeof(struct ir), 1); + ir->id = next_id++; + ir->opcode = opcode; + ir->size = size; + + switch (ir->opcode) + { + case IR_JUMP: + case IR_CJUMP: + ir->terminates = true; + break; + } + + return ir; +} + +struct ir* new_ir1(int opcode, int size, + struct ir* c1) +{ + struct ir* ir = new_ir0(opcode, size); + ir->children[0] = c1; + return ir; +} + +struct ir* new_ir2(int opcode, int size, + struct ir* c1, struct ir* c2) +{ + struct ir* ir = new_ir0(opcode, size); + ir->children[0] = c1; + ir->children[1] = c2; + return ir; +} + +struct ir* new_ir3(int opcode, int size, + struct ir* c1, struct ir* c2, struct ir* c3) +{ + struct ir* ir = new_ir0(opcode, size); + ir->children[0] = c1; + ir->children[1] = c2; + ir->children[2] = c3; + return ir; +} + +struct ir* new_labelir(const char* label) +{ + struct ir* ir = new_ir0(IR_LABEL, EM_pointersize); + ir->u.lvalue = label; + return ir; +} + +struct ir* new_wordir(arith value) +{ + struct ir* ir = new_ir0(IR_ICONST, EM_wordsize); + ir->u.ivalue = value; + return ir; +} + +struct ir* new_regir(int reg) +{ + struct ir* ir = new_ir0(IR_REG, EM_pointersize); + ir->u.rvalue = reg; + return ir; +} + +struct ir* new_bbir(struct basicblock* bb) +{ + struct ir* ir = new_ir0(IR_BLOCK, EM_pointersize); + ir->u.bvalue = bb; + return ir; +} + +struct ir* new_anyir(int size) +{ + return new_ir0(IR_ANY, size); +} + +struct ir* new_phiir(int size) +{ + return new_ir0(IR_PHI, size); +} + +void ir_print(const struct ir* ir) +{ + int i; + for (i=0; ichildren)/sizeof(*ir->children); i++) + { + if (ir->children[i]) + ir_print(ir->children[i]); + } + + printf("\t; %c ", + ir->sequence ? 'S' : ' '); + printf("$%d = ", ir->id); + printf("%s%d(", + ir_names[ir->opcode], + ir->size); + + switch (ir->opcode) + { + case IR_ICONST: + printf("%d", ir->u.ivalue); + break; + + case IR_LABEL: + printf("%s", ir->u.lvalue); + break; + + case IR_REG: + printf("%d", ir->u.rvalue); + break; + + case IR_BLOCK: + printf("%s", ir->u.bvalue->name); + break; + + default: + for (i=0; ichildren)/sizeof(*ir->children); i++) + { + if (ir->children[i]) + { + if (i > 0) + printf(", "); + printf("$%d", ir->children[i]->id); + } + } + } + + printf(")\n"); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat new file mode 100644 index 000000000..044f9c0f3 --- /dev/null +++ b/mach/proto/mcg/ir.dat @@ -0,0 +1,33 @@ +# Simple terminals +ICONST +REG +LABEL +BLOCK +ANY +PHI + +# Memory operations +LOAD +STORE + +# Arithemetic operations +ADD + +# Conversions +FROMI1 +FROMI2 +FROMI4 +FROMI8 + +# Comparisons +COMPARES +COMPAREU + +# Flow control +JUMP +CJUMP +RET + +# Special +SETREG + diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h new file mode 100644 index 000000000..33b892528 --- /dev/null +++ b/mach/proto/mcg/ir.h @@ -0,0 +1,53 @@ +#ifndef IR_H +#define IR_H + +#include "ircodes.h" + +enum +{ + IRR_LB = -1, + IRR_AB = -2, + IRR_SP = -3, + IRR_RR = -4, +}; + +struct ir +{ + int id; + int opcode; + int size; + struct ir* children[3]; + union { + arith ivalue; + int rvalue; + const char* lvalue; + struct basicblock* bvalue; + struct { + ARRAY(struct ir, srcs); + } phivalue; + } u; + bool sequence : 1; + bool terminates : 1; +}; + +extern const char* ir_names[]; + +extern struct ir* new_ir0(int opcode, int size); +extern struct ir* new_ir1(int opcode, int size, + struct ir* c1); +extern struct ir* new_ir2(int opcode, int size, + struct ir* c1, struct ir* c2); +extern struct ir* new_ir3(int opcode, int size, + struct ir* c1, struct ir* c2, struct ir* c3); + +extern struct ir* new_labelir(const char* label); +extern struct ir* new_regir(int reg); +extern struct ir* new_wordir(arith value); +extern struct ir* new_bbir(struct basicblock* bb); +extern struct ir* new_anyir(int size); +extern struct ir* new_phiir(int size); + +extern void ir_print(const struct ir* ir); + +#endif + diff --git a/mach/proto/mcg/ircodes.sh b/mach/proto/mcg/ircodes.sh new file mode 100755 index 000000000..8f88b8bf4 --- /dev/null +++ b/mach/proto/mcg/ircodes.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +in=$1 +header=$2 +source=$3 + +echo "enum {" > $header +sed -n 's/^[A-Z].*$/IR_&,/p' < $in >> $header +echo "};" >> $header + +echo "const char* ir_names[] = {" > $source +sed -n 's/^[A-Z].*$/"&",/p' < $in >> $source +echo "};" >> $source + diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 035259d54..a89b5a7d9 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -1,5 +1,4 @@ #include "mcg.h" -#include "em_comp.h" void fatal(const char* msg, ...) { @@ -13,8 +12,31 @@ void fatal(const char* msg, ...) abort(); } +const char* aprintf(const char* fmt, ...) +{ + int n; + char* p; + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + p = malloc(n); + if (!p) + return NULL; + + va_start(ap, fmt); + vsnprintf(p, n, fmt, ap); + va_end(ap); + + return p; +} + int main(int argc, char* argv[]) { + symbol_init(); + if (!EM_open(argv[1])) fatal("Couldn't open input file: %s", EM_error); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index e008249ed..06e8160eb 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -16,24 +16,69 @@ #include "em_mnem.h" #include "em_flag.h" #include "em_ptyp.h" +#include "array.h" +#include "ir.h" extern char em_pseu[][4]; extern char em_mnem[][4]; extern char em_flag[]; +enum { + SECTION_UNKNOWN = 0, + SECTION_ROM, + SECTION_DATA, + SECTION_BSS, + SECTION_TEXT +}; + +struct symbol { + const char* name; + int section; + bool is_defined : 1; + bool is_exported : 1; + bool is_proc : 1; +}; + +enum { + PARAM_NONE, + PARAM_VALUE, + PARAM_LABEL +}; + +struct basicblock { + const char* name; + ARRAY(struct ir, irs); + ARRAY(struct basicblock, inblocks); + ARRAY(struct basicblock, outblocks); + ARRAY(struct ir, outs); + ARRAY(struct ir, ins); + bool is_wired : 1; +}; extern void fatal(const char* s, ...); +extern const char* aprintf(const char* fmt, ...); extern void parse_em(void); +extern void symbol_init(void); +extern bool symbol_exists(const char* name); +extern struct symbol* symbol_get(const char* name); +extern void symbol_declare(const char* name, bool is_exported, bool is_proc); + +extern void data_label(const char* name); +extern void data_int(arith data, size_t size, bool is_ro); +extern void data_block(const uint8_t* data, size_t size, bool is_ro); +extern void data_offset(const char* label, arith offset, bool is_ro); +extern void data_bss(arith size, int init); + +extern void bb_init(void); +extern struct basicblock* bb_get(const char* name); +extern void bb_alias(struct basicblock* block, const char* name); +extern void bb_wire_outs_to_ins(struct basicblock* outblock, struct basicblock* inblock); + extern void tb_filestart(void); extern void tb_fileend(void); -extern void tb_symbol(const char* name, bool is_exported, bool is_proc); -extern void tb_dlabel(const char* label); extern void tb_ilabel(const char* label); -extern void tb_data(const uint8_t* data, size_t size, bool is_ro); -extern void tb_data_offset(const char* label, arith offset, bool is_ro); -extern void tb_bss(size_t size, uint8_t init); extern void tb_procstart(const char* label, size_t nlocals); extern void tb_procend(void); extern void tb_regvar(arith offset, int size, int type, int priority); diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 11aeb5c17..22ac92e81 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -1,6 +1,7 @@ #include "mcg.h" static struct e_instr insn; +static const char* current_proc; static const char* type_to_str(int type) { @@ -44,35 +45,15 @@ static void unknown_type(const char* s) argtype_to_str(insn.em_arg.ema_argtype)); } -static const uint8_t* arith_to_bytes(arith a, size_t sz) -{ - uint8_t* p = malloc(8); - - switch (sz) - { - case 1: *(uint8_t*)p = a; break; - case 2: *(uint16_t*)p = a; break; - case 4: *(uint32_t*)p = a; break; - case 8: *(uint64_t*)p = a; break; - default: - fatal("bad constant size '%d'", sz); - } - - return p; -} - static const char* ilabel_to_str(label l) { - char s[16]; - sprintf(s, "__I%d", l); - return strdup(s); + assert(current_proc != NULL); + return aprintf("__%s_I%d", current_proc, l); } static const char* dlabel_to_str(label l) { - char s[16]; - sprintf(s, ".%d", l); - return strdup(s); + return aprintf("__D%d", l); } static void parse_pseu(void) @@ -90,17 +71,17 @@ static void parse_pseu(void) switch (insn.em_arg.ema_argtype) { case pro_ptyp: - tb_symbol(strdup(insn.em_pnam), export, proc); + symbol_declare(strdup(insn.em_pnam), export, proc); break; case sof_ptyp: assert(insn.em_off == 0); - tb_symbol(strdup(insn.em_dnam), export, proc); + symbol_declare(strdup(insn.em_dnam), export, proc); break; case nof_ptyp: assert(insn.em_off == 0); - tb_symbol(dlabel_to_str(insn.em_dlb), export, proc); + symbol_declare(dlabel_to_str(insn.em_dlb), export, proc); break; default: @@ -120,24 +101,24 @@ static void parse_pseu(void) case uco_ptyp: { arith val = atol(insn.em_string); - tb_data(arith_to_bytes(val, insn.em_size), insn.em_size, ro); + data_int(val, insn.em_size, ro); break; } case str_ptyp: - tb_data(strdup(insn.em_string), insn.em_size, ro); + data_block(strdup(insn.em_string), insn.em_size, ro); break; case cst_ptyp: - tb_data(arith_to_bytes(insn.em_cst, EM_wordsize), EM_wordsize, ro); + data_int(insn.em_cst, EM_wordsize, ro); break; case nof_ptyp: - tb_data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro); + data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro); break; case ilb_ptyp: - tb_data_offset(ilabel_to_str(insn.em_ilb), 0, ro); + data_offset(ilabel_to_str(insn.em_ilb), 0, ro); break; default: @@ -151,7 +132,7 @@ static void parse_pseu(void) switch (insn.em_arg.ema_argtype) { case cst_ptyp: - tb_bss(EM_bsssize, EM_bssinit); + data_bss(EM_bsssize, insn.em_cst); break; default: @@ -164,11 +145,13 @@ static void parse_pseu(void) if (insn.em_nlocals == -1) fatal("procedures with unspecified number of locals are not supported yet"); - tb_procstart(strdup(insn.em_pnam), insn.em_nlocals); + current_proc = strdup(insn.em_pnam); + tb_procstart(current_proc, insn.em_nlocals); break; case ps_end: /* procedure end */ tb_procend(); + current_proc = NULL; break; default: @@ -228,16 +211,16 @@ void parse_em(void) break; case EM_DEFDLB: - tb_dlabel(dlabel_to_str(insn.em_dlb)); + data_label(dlabel_to_str(insn.em_dlb)); break; case EM_DEFDNAM: - tb_dlabel(strdup(insn.em_dnam)); + data_label(strdup(insn.em_dnam)); break; case EM_STARTMES: parse_mes(); - break; + break; case EM_MNEM: { @@ -268,8 +251,12 @@ void parse_em(void) break; case cst_ptyp: - tb_insn_value(insn.em_opcode, flags, - insn.em_cst); + if ((flags & EM_PAR) == PAR_B) + tb_insn_label(insn.em_opcode, flags, + ilabel_to_str(insn.em_ilb), 0); + else + tb_insn_value(insn.em_opcode, flags, + insn.em_cst); break; default: diff --git a/mach/proto/mcg/push_pop.awk b/mach/proto/mcg/push_pop.awk deleted file mode 100644 index 83560912e..000000000 --- a/mach/proto/mcg/push_pop.awk +++ /dev/null @@ -1,52 +0,0 @@ -BEGIN { - print "#include " - print "#include \"push_pop.h\"" - print "" - - s = 0; - count = 0; -} - -/^aar/ { - s = 1; -} - -/^[a-z]/ { - if (!s) - next; - - opcode[count++] = $1; - data[$1] = $3; -} - -END { - for (op in data) - { - print "static const struct stackop so_" op "[] = {"; - - pushpops = data[op] - if (pushpops != "0") - { - for (i=1; i<=length(pushpops); i+=2) - { - printf "\t{ "; - if (substr(pushpops, i, 1) == "+") - printf "true, "; - else - printf "false, "; - - printf("'%s' },\n", substr(pushpops, i+1, 1)); - } - } - print "\t{ false, 0 }" - - print "};"; - print ""; - } - - print "const struct stackop* const stackops[] = {"; - for (i=0; i +#include + +void symbol_init(void) +{ + init_idf(); +} + +bool symbol_exists(const char* name) +{ + return !!findidf((char*) name); +} + +struct symbol* symbol_get(const char* name) +{ + struct idf* p = str2idf((char*) name, 0); + p->symbol.name = p->id_text; + return &p->symbol; +} + +void symbol_declare(const char* name, bool is_exported, bool is_proc) +{ + struct symbol* s = symbol_get(name); + s->is_exported = is_exported; + + if (is_proc) + { + if (s->section == SECTION_UNKNOWN) + s->section = SECTION_TEXT; + else if (s->section != SECTION_TEXT) + fatal("section mismatch for '%s'", name); + } +} + diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index b8bff66b7..c7abd5cc8 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1,5 +1,43 @@ #include "mcg.h" +static struct symbol* currentproc; +static struct basicblock* rootbb; +static struct basicblock* currentbb; + +static int stackptr; +static struct ir* stack[64]; + +static void resetstack(void) +{ + stackptr = 0; +} + +static void push(struct ir* ir) +{ + if (stackptr == sizeof(stack)/sizeof(*stack)) + fatal("stack overflow"); + + stack[stackptr++] = ir; +} + +static struct ir* pop(void) +{ + if (stackptr == 0) + fatal("stack underflow"); + + return stack[--stackptr]; +} + +static struct ir* appendir(struct ir* ir) +{ + assert(currentbb != NULL); + ir->sequence = true; + APPEND(currentbb->irs, ir); + + ir_print(ir); + return ir; +} + void tb_filestart(void) { } @@ -8,86 +46,369 @@ void tb_fileend(void) { } -void tb_symbol(const char* name, bool is_exported, bool is_proc) +static void materialise(void) { - printf("; symbol name=%s, exported=%s, is_proc=%s\n", - name, - is_exported ? "yes" : "no", - is_proc ? "yes" : "no"); + int i; + + for (i=0; i 0) + { + printf("\t; block exiting with %d on stack:\n", stackptr); + for (i=0; iid, ir->size); + APPENDU(currentbb->outs, ir); + } + } + + for (i=0; ioutblocks_count; i++) + bb_wire_outs_to_ins(currentbb, currentbb->outblocks[i]); + + currentbb = bb; + printf("; new block: %s\n", currentbb->name); + + resetstack(); + + if (currentbb->ins_count > 0) + { + printf("\t; block entering with %d on stack:\n", currentbb->ins_count); + for (i=0; iins_count; i++) + { + struct ir* ir = currentbb->ins[i]; + printf("\t; $%d size %d\n", ir->id, ir->size); + push(ir); + } + } } void tb_ilabel(const char* label) { - printf("; ilabel name=%s\n", label); -} + materialise(); -void tb_data(const uint8_t* data, size_t size, bool is_ro) -{ - printf("; data size=%d ro=%s\n", - size, - is_ro ? "yes" : "no"); -} + #if 0 + if (currentbb->irs_count == 0) + { + /* Current BB has no instructions, so just alias it to the + * new name. + */ + bb_alias(currentbb, label); + } + else + #endif + { + struct basicblock* newbb = bb_get(label); -void tb_data_offset(const char* label, arith offset, bool is_ro) -{ - printf("; data label=%s offset=%d ro=%s\n", - label, offset, - is_ro ? "yes" : "no"); -} + if ((currentbb->irs_count == 0) || + !currentbb->irs[currentbb->irs_count-1]->terminates) + { + APPEND(currentbb->outblocks, newbb); + appendir( + new_ir1( + IR_JUMP, 0, + new_labelir(label) + ) + ); + } -void tb_bss(size_t size, uint8_t init) -{ - printf("; bss size=%d init=0x%x\n", - size, init); + changeblock(newbb); + } } void tb_procstart(const char* label, size_t nlocals) { - printf("; proc name=%s nlocals=%d\n", label, nlocals); + assert(currentproc == NULL); + + currentproc = symbol_get(label); + currentproc->section = SECTION_TEXT; + + rootbb = calloc(sizeof(struct basicblock), 1); + currentbb = rootbb; + + resetstack(); } void tb_procend(void) { - printf("; endproc\n"); + assert(currentproc != NULL); + + printf("\n.text\n"); + printf("%s:\n", currentproc->name); + + currentproc = NULL; } void tb_regvar(arith offset, int size, int type, int priority) { - printf("; regvar offset=%d size=%d type=%d priority=%d\n", - offset, size, type, priority); + /* ignored */ } -static void printinsn(int opcode, int flags) +static struct ir* address_of_local(int index) { - printf("; insn %s %c%c%c%c ", - em_mnem[opcode - sp_fmnem], - "/CDNFLGWSZOPBR"[flags & EM_PAR], - (flags & FLO_C) ? 'c' : '.', - (flags & FLO_P) ? 'p' : '.', - (flags & FLO_T) ? 't' : '.'); + return + new_ir2( + IR_ADD, EM_pointersize, + new_regir((index < 0) ? IRR_LB : IRR_AB), + new_wordir(index) + ); +} + +static struct ir* tristate_compare(int size, int opcode) +{ + struct ir* right = pop(); + struct ir* left = pop(); + + return + new_ir2( + opcode, size, + left, right + ); +} + +static struct ir* convert(int destsize, int srcsize, int opcode) +{ + switch (srcsize) + { + case 1: opcode += 0; break; + case 2: opcode += 1; break; + case 4: opcode += 2; break; + case 8: opcode += 3; break; + default: + fatal("can't convert from things of size %d", srcsize); + } + + return + new_ir1( + opcode, destsize, + pop() + ); } void tb_insn_simple(int opcode, int flags) { - printinsn(opcode, flags); - printf("\n"); + switch (opcode) + { + case op_cii: + { + struct ir* destsize = pop(); + struct ir* srcsize = pop(); + + assert(srcsize->opcode == IR_ICONST); + assert(destsize->opcode == IR_ICONST); + + push( + convert(destsize->u.ivalue, srcsize->u.ivalue, IR_FROMI1) + ); + break; + } + + default: + fatal("unknown insn_simple instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } } void tb_insn_label(int opcode, int flags, const char* label, arith offset) { - printinsn(opcode, flags); - printf("label=%s offset=%d\n", label, offset); + materialise(); + + switch (opcode) + { + case op_zne: + { + struct basicblock* truebb = bb_get(label); + struct basicblock* falsebb = bb_get(NULL); + + APPENDU(currentbb->outblocks, truebb); + APPENDU(currentbb->outblocks, falsebb); + + appendir( + new_ir3( + IR_CJUMP, 0, + pop(), + new_bbir(truebb), + new_bbir(falsebb) + ) + ); + + changeblock(falsebb); + break; + } + + case op_bra: + { + struct basicblock* destbb = bb_get(label); + APPENDU(currentbb->outblocks, destbb); + + appendir( + new_ir1( + IR_JUMP, 0, + new_bbir(destbb) + ) + ); + break; + } + + default: + fatal("unknown insn_label instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } } void tb_insn_value(int opcode, int flags, arith value) { - printinsn(opcode, flags); - printf("value=%d\n", value); + struct ir* left; + struct ir* right; + + switch (opcode) + { + case op_lol: + push( + new_ir1( + IR_LOAD, EM_wordsize, + address_of_local(value) + ) + ); + break; + + case op_stl: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_local(value), + pop() + ) + ); + break; + + case op_loc: + push( + new_wordir(value) + ); + break; + + case op_loi: + push( + new_ir1( + IR_LOAD, value, + pop() + ) + ); + break; + + case op_sti: + right = pop(); + left = pop(); + + appendir( + new_ir2( + IR_STORE, value, + right, left + ) + ); + break; + + case op_cmi: + push( + tristate_compare(value, IR_COMPARES) + ); + break; + + case op_cmu: + push( + tristate_compare(value, IR_COMPAREU) + ); + break; + + case op_ads: + right = pop(); + left = pop(); + + if (value != EM_pointersize) + right = convert(EM_pointersize, value, IR_FROMI1); + + push( + new_ir2( + IR_ADD, EM_wordsize, + left, right + ) + ); + break; + + case op_dup: + { + struct ir* v = pop(); + appendir(v); + push(v); + push(v); + break; + } + + case op_asp: + { + switch (value) + { + case 0: + break; + + case -1: + case -2: + case -4: + case -8: + push(new_anyir(-value)); + break; + + default: + appendir( + new_ir2( + IR_SETREG, EM_pointersize, + new_regir(IRR_SP), + new_ir2( + IR_ADD, EM_pointersize, + new_regir(IRR_SP), + new_wordir(value) + ) + ) + ); + break; + } + break; + } + + case op_ret: + { + if (value > 0) + { + left = pop(); + assert(left->size == value); + appendir( + new_ir2( + IR_SETREG, value, + new_regir(IRR_RR), + left + ) + ); + } + + appendir( + new_ir0( + IR_RET, 0 + ) + ); + break; + } + + default: + fatal("unknown insn_value instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } } /* vim: set sw=4 ts=4 expandtab : */ From 6ce2495aeb46fc703c321a9817a2bf17540873ee Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 19 Sep 2016 23:06:59 +0200 Subject: [PATCH 005/230] Store the EM code up front and build the basic block graph *before* generating the IR code. Lots more IR code. --- mach/proto/mcg/build.lua | 5 +- mach/proto/mcg/ir.c | 54 +--- mach/proto/mcg/ir.dat | 25 +- mach/proto/mcg/ir.h | 8 +- mach/proto/mcg/mcg.h | 49 +++- mach/proto/mcg/parse_em.c | 186 +++++++++--- mach/proto/mcg/treebuilder.c | 543 +++++++++++++++++++++++------------ 7 files changed, 589 insertions(+), 281 deletions(-) diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index 5db304b46..c94d44ece 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -29,7 +29,10 @@ cprogram { "./*.h", }, vars = { - ["+cflags"] = {"-Werror-implicit-function-declaration"} + ["+cflags"] = { + "-Werror-implicit-function-declaration", + "-Wint-conversion" + } } } diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index 8973bfc73..814171586 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -8,42 +8,23 @@ struct ir* new_ir0(int opcode, int size) ir->id = next_id++; ir->opcode = opcode; ir->size = size; - - switch (ir->opcode) - { - case IR_JUMP: - case IR_CJUMP: - ir->terminates = true; - break; - } - return ir; } struct ir* new_ir1(int opcode, int size, - struct ir* c1) + struct ir* left) { struct ir* ir = new_ir0(opcode, size); - ir->children[0] = c1; + ir->left = left; return ir; } struct ir* new_ir2(int opcode, int size, - struct ir* c1, struct ir* c2) + struct ir* left, struct ir* right) { struct ir* ir = new_ir0(opcode, size); - ir->children[0] = c1; - ir->children[1] = c2; - return ir; -} - -struct ir* new_ir3(int opcode, int size, - struct ir* c1, struct ir* c2, struct ir* c3) -{ - struct ir* ir = new_ir0(opcode, size); - ir->children[0] = c1; - ir->children[1] = c2; - ir->children[2] = c3; + ir->left = left; + ir->right = right; return ir; } @@ -87,15 +68,13 @@ struct ir* new_phiir(int size) void ir_print(const struct ir* ir) { - int i; - for (i=0; ichildren)/sizeof(*ir->children); i++) - { - if (ir->children[i]) - ir_print(ir->children[i]); - } + if (ir->left) + ir_print(ir->left); + if (ir->right) + ir_print(ir->right); printf("\t; %c ", - ir->sequence ? 'S' : ' '); + ir->is_sequence ? 'S' : ' '); printf("$%d = ", ir->id); printf("%s%d(", ir_names[ir->opcode], @@ -120,15 +99,10 @@ void ir_print(const struct ir* ir) break; default: - for (i=0; ichildren)/sizeof(*ir->children); i++) - { - if (ir->children[i]) - { - if (i > 0) - printf(", "); - printf("$%d", ir->children[i]->id); - } - } + if (ir->left) + printf("$%d", ir->left->id); + if (ir->right) + printf(", $%d", ir->right->id); } printf(")\n"); diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat index 044f9c0f3..ea47cb0a0 100644 --- a/mach/proto/mcg/ir.dat +++ b/mach/proto/mcg/ir.dat @@ -3,15 +3,26 @@ ICONST REG LABEL BLOCK +PAIR ANY PHI +# Magic stack operations +PUSH +POP + # Memory operations LOAD STORE # Arithemetic operations ADD +SUB +MUL +DIV +MOD +NEG +NOT # Conversions FROMI1 @@ -19,15 +30,27 @@ FROMI2 FROMI4 FROMI8 -# Comparisons +FROMU1 +FROMU2 +FROMU4 +FROMU8 + +# Tristate comparisons COMPARES COMPAREU +# Boolean comparisons +IFEQ +IFLT +IFLE + # Flow control +CALL JUMP CJUMP RET # Special SETREG +GETREG diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 33b892528..6574ecb80 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -16,7 +16,8 @@ struct ir int id; int opcode; int size; - struct ir* children[3]; + struct ir* left; + struct ir* right; union { arith ivalue; int rvalue; @@ -26,8 +27,7 @@ struct ir ARRAY(struct ir, srcs); } phivalue; } u; - bool sequence : 1; - bool terminates : 1; + bool is_sequence : 1; }; extern const char* ir_names[]; @@ -37,8 +37,6 @@ extern struct ir* new_ir1(int opcode, int size, struct ir* c1); extern struct ir* new_ir2(int opcode, int size, struct ir* c1, struct ir* c2); -extern struct ir* new_ir3(int opcode, int size, - struct ir* c1, struct ir* c2, struct ir* c3); extern struct ir* new_labelir(const char* label); extern struct ir* new_regir(int reg); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 06e8160eb..ce332fff9 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -31,7 +31,8 @@ enum { SECTION_TEXT }; -struct symbol { +struct symbol +{ const char* name; int section; bool is_defined : 1; @@ -39,20 +40,50 @@ struct symbol { bool is_proc : 1; }; -enum { +enum +{ PARAM_NONE, - PARAM_VALUE, - PARAM_LABEL + PARAM_IVALUE, + PARAM_LVALUE, + PARAM_BVALUE, }; -struct basicblock { +struct insn +{ + int opcode; + int paramtype; + union { + arith ivalue; + struct { + const char* label; + arith offset; + } lvalue; + struct { + struct basicblock* left; + struct basicblock* right; + } bvalue; + } u; +}; + +struct procedure +{ const char* name; + struct basicblock* root_bb; + size_t nlocals; + ARRAY(struct basicblock, blocks); +}; + +struct basicblock +{ + const char* name; + ARRAY(struct insn, insns); ARRAY(struct ir, irs); ARRAY(struct basicblock, inblocks); ARRAY(struct basicblock, outblocks); ARRAY(struct ir, outs); ARRAY(struct ir, ins); bool is_wired : 1; + bool is_terminated : 1; }; extern void fatal(const char* s, ...); @@ -78,15 +109,9 @@ extern void bb_wire_outs_to_ins(struct basicblock* outblock, struct basicblock* extern void tb_filestart(void); extern void tb_fileend(void); -extern void tb_ilabel(const char* label); -extern void tb_procstart(const char* label, size_t nlocals); -extern void tb_procend(void); +extern void tb_procedure(struct procedure* proc); extern void tb_regvar(arith offset, int size, int type, int priority); -extern void tb_insn_simple(int opcode, int flags); -extern void tb_insn_label(int opcode, int flags, const char* label, arith offset); -extern void tb_insn_value(int opcode, int flags, arith value); - #endif /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 22ac92e81..9310dda40 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -1,7 +1,8 @@ #include "mcg.h" static struct e_instr insn; -static const char* current_proc; +static struct procedure* current_proc; +static struct basicblock* current_bb; static const char* type_to_str(int type) { @@ -48,7 +49,7 @@ static void unknown_type(const char* s) static const char* ilabel_to_str(label l) { assert(current_proc != NULL); - return aprintf("__%s_I%d", current_proc, l); + return aprintf("__%s_I%d", current_proc->name, l); } static const char* dlabel_to_str(label l) @@ -56,6 +57,103 @@ static const char* dlabel_to_str(label l) return aprintf("__D%d", l); } +static struct insn* new_insn(int opcode) +{ + struct insn* insn = calloc(sizeof(struct insn), 1); + insn->opcode = opcode; + return insn; +} + +static void queue_insn_simple(int opcode) +{ + struct insn* insn = new_insn(opcode); + insn->paramtype = PARAM_NONE; + APPEND(current_bb->insns, insn); + + switch (opcode) + { + case op_ret: + current_bb->is_terminated = true; + current_bb = NULL; + break; + } +} + +static void queue_insn_value(int opcode, arith value) +{ + struct insn* insn = new_insn(opcode); + insn->paramtype = PARAM_IVALUE; + insn->u.ivalue = value; + APPEND(current_bb->insns, insn); +} + +static void queue_insn_label(int opcode, const char* label, arith offset) +{ + struct insn* insn = new_insn(opcode); + insn->paramtype = PARAM_LVALUE; + insn->u.lvalue.label = label; + insn->u.lvalue.offset = offset; + APPEND(current_bb->insns, insn); +} + +static void queue_insn_block(int opcode, struct basicblock* left, struct basicblock* right) +{ + struct insn* insn = new_insn(opcode); + insn->paramtype = PARAM_BVALUE; + insn->u.bvalue.left = left; + insn->u.bvalue.right = right; + APPEND(current_bb->insns, insn); + + APPENDU(current_bb->outblocks, left); + if (right) + APPENDU(current_bb->outblocks, right); + APPENDU(current_bb->inblocks, current_bb); + + current_bb->is_terminated = true; + current_bb = NULL; +} + +static void queue_insn_ilabel(int opcode, int label) +{ + const char* name = ilabel_to_str(insn.em_ilb); + struct basicblock* left = bb_get(name); + + switch (opcode) + { + case op_bra: + queue_insn_block(insn.em_opcode, left, NULL); + break; + + case op_zeq: + case op_zne: + case op_zlt: + case op_zle: + case op_zgt: + case op_zge: + queue_insn_block(insn.em_opcode, left, bb_get(NULL)); + break; + + default: + fatal("parse_em: unhandled conditional '%s'", + em_mnem[opcode - sp_fmnem]); + } +} + +static void change_basicblock(struct basicblock* newbb) +{ + APPENDU(current_proc->blocks, newbb); + + if (current_bb && !current_bb->is_terminated) + queue_insn_block(op_bra, newbb, NULL); + + current_bb = newbb; +} + +static void queue_ilabel(arith label) +{ + change_basicblock(bb_get(ilabel_to_str(label))); +} + static void parse_pseu(void) { switch (insn.em_opcode) @@ -142,16 +240,19 @@ static void parse_pseu(void) } case ps_pro: /* procedure start */ - if (insn.em_nlocals == -1) - fatal("procedures with unspecified number of locals are not supported yet"); - - current_proc = strdup(insn.em_pnam); - tb_procstart(current_proc, insn.em_nlocals); + current_proc = calloc(sizeof(struct procedure), 1); + current_proc->name = strdup(insn.em_pnam); + current_proc->root_bb = bb_get(current_proc->name); + current_proc->nlocals = insn.em_nlocals; + current_bb = current_proc->root_bb; + APPEND(current_proc->blocks, current_bb); break; case ps_end: /* procedure end */ - tb_procend(); + tb_procedure(current_proc); + current_proc = NULL; + current_bb = NULL; break; default: @@ -207,7 +308,7 @@ void parse_em(void) break; case EM_DEFILB: - tb_ilabel(ilabel_to_str(insn.em_ilb)); + queue_ilabel(insn.em_ilb); break; case EM_DEFDLB: @@ -223,51 +324,48 @@ void parse_em(void) break; case EM_MNEM: - { - int flags = em_flag[insn.em_opcode - sp_fmnem]; - - if (flags & EM_PAR) + if (current_bb) { - switch (insn.em_argtype) + int flags = em_flag[insn.em_opcode - sp_fmnem]; + + if (flags & EM_PAR) { - case ilb_ptyp: - tb_insn_label(insn.em_opcode, flags, - ilabel_to_str(insn.em_ilb), 0); - break; + switch (insn.em_argtype) + { + case ilb_ptyp: + queue_insn_ilabel(insn.em_opcode, insn.em_ilb); + break; - case nof_ptyp: - tb_insn_label(insn.em_opcode, flags, - dlabel_to_str(insn.em_dlb), insn.em_off); - break; + case nof_ptyp: + queue_insn_label(insn.em_opcode, + dlabel_to_str(insn.em_dlb), insn.em_off); + break; - case sof_ptyp: - tb_insn_label(insn.em_opcode, flags, - strdup(insn.em_dnam), insn.em_off); - break; + case sof_ptyp: + queue_insn_label(insn.em_opcode, + strdup(insn.em_dnam), insn.em_off); + break; - case pro_ptyp: - tb_insn_label(insn.em_opcode, flags, - strdup(insn.em_pnam), 0); - break; + case pro_ptyp: + queue_insn_label(insn.em_opcode, + strdup(insn.em_pnam), 0); + break; - case cst_ptyp: - if ((flags & EM_PAR) == PAR_B) - tb_insn_label(insn.em_opcode, flags, - ilabel_to_str(insn.em_ilb), 0); - else - tb_insn_value(insn.em_opcode, flags, - insn.em_cst); - break; + case cst_ptyp: + if ((flags & EM_PAR) == PAR_B) + queue_insn_ilabel(insn.em_opcode, insn.em_ilb); + else + queue_insn_value(insn.em_opcode, insn.em_cst); + break; - default: - unknown_type("instruction"); + default: + unknown_type("instruction"); + } } + else + queue_insn_simple(insn.em_opcode); } - else - tb_insn_simple(insn.em_opcode, flags); - break; - } default: fatal("unrecognised instruction type '%d'", insn.em_type); diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index c7abd5cc8..acd8f30cd 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1,13 +1,15 @@ #include "mcg.h" static struct symbol* currentproc; -static struct basicblock* rootbb; -static struct basicblock* currentbb; +static struct basicblock* current_bb; static int stackptr; static struct ir* stack[64]; -static void resetstack(void) +static struct ir* convert(struct ir* src, int destsize, int opcode); +static struct ir* appendir(struct ir* ir); + +static void reset_stack(void) { stackptr = 0; } @@ -17,27 +19,86 @@ static void push(struct ir* ir) if (stackptr == sizeof(stack)/sizeof(*stack)) fatal("stack overflow"); + /* If we try to push something which is too small, convert it to a word + * first. */ + + if (ir->size < EM_wordsize) + ir = convert(ir, EM_wordsize, IR_FROMU1); + stack[stackptr++] = ir; } -static struct ir* pop(void) +static struct ir* pop(int size) { if (stackptr == 0) - fatal("stack underflow"); + { + /* Nothing in our fake stack, so we have to read from the real stack. */ - return stack[--stackptr]; + if (size < EM_wordsize) + size = EM_wordsize; + return + new_ir0( + IR_POP, size + ); + } + else + { + struct ir* ir = stack[--stackptr]; + + /* If we try to pop something which is smaller than a word, convert it first. */ + + if (size < EM_wordsize) + ir = convert(ir, size, IR_FROMU1); + + if (ir->size != size) + fatal("expected an item on stack of size %d, but got %d\n", size, ir->size); + return ir; + } +} + +static void print_stack(void) +{ + int i; + + printf("\t; stack:"); + for (i=0; iid, ir->size); + } + printf(" (top)\n"); } static struct ir* appendir(struct ir* ir) { - assert(currentbb != NULL); - ir->sequence = true; - APPEND(currentbb->irs, ir); + int i; + + assert(current_bb != NULL); + ir->is_sequence = true; + APPEND(current_bb->irs, ir); ir_print(ir); return ir; } +static void materialise_stack(void) +{ + int i; + + for (i=stackptr-1; i>=0; i--) + { + struct ir* ir = stack[i]; + appendir( + new_ir1( + IR_PUSH, ir->size, + ir + ) + ); + } + + reset_stack(); +} + void tb_filestart(void) { } @@ -46,105 +107,6 @@ void tb_fileend(void) { } -static void materialise(void) -{ - int i; - - for (i=0; i 0) - { - printf("\t; block exiting with %d on stack:\n", stackptr); - for (i=0; iid, ir->size); - APPENDU(currentbb->outs, ir); - } - } - - for (i=0; ioutblocks_count; i++) - bb_wire_outs_to_ins(currentbb, currentbb->outblocks[i]); - - currentbb = bb; - printf("; new block: %s\n", currentbb->name); - - resetstack(); - - if (currentbb->ins_count > 0) - { - printf("\t; block entering with %d on stack:\n", currentbb->ins_count); - for (i=0; iins_count; i++) - { - struct ir* ir = currentbb->ins[i]; - printf("\t; $%d size %d\n", ir->id, ir->size); - push(ir); - } - } -} - -void tb_ilabel(const char* label) -{ - materialise(); - - #if 0 - if (currentbb->irs_count == 0) - { - /* Current BB has no instructions, so just alias it to the - * new name. - */ - bb_alias(currentbb, label); - } - else - #endif - { - struct basicblock* newbb = bb_get(label); - - if ((currentbb->irs_count == 0) || - !currentbb->irs[currentbb->irs_count-1]->terminates) - { - APPEND(currentbb->outblocks, newbb); - appendir( - new_ir1( - IR_JUMP, 0, - new_labelir(label) - ) - ); - } - - changeblock(newbb); - } -} - -void tb_procstart(const char* label, size_t nlocals) -{ - assert(currentproc == NULL); - - currentproc = symbol_get(label); - currentproc->section = SECTION_TEXT; - - rootbb = calloc(sizeof(struct basicblock), 1); - currentbb = rootbb; - - resetstack(); -} - -void tb_procend(void) -{ - assert(currentproc != NULL); - - printf("\n.text\n"); - printf("%s:\n", currentproc->name); - - currentproc = NULL; -} - void tb_regvar(arith offset, int size, int type, int priority) { /* ignored */ @@ -160,10 +122,29 @@ static struct ir* address_of_local(int index) ); } +static struct ir* convert(struct ir* src, int destsize, int opcode) +{ + switch (src->size) + { + case 1: opcode += 0; break; + case 2: opcode += 1; break; + case 4: opcode += 2; break; + case 8: opcode += 3; break; + default: + fatal("can't convert from things of size %d", src->size); + } + + return + new_ir1( + opcode, destsize, + src + ); +} + static struct ir* tristate_compare(int size, int opcode) { - struct ir* right = pop(); - struct ir* left = pop(); + struct ir* right = pop(size); + struct ir* left = pop(size); return new_ir2( @@ -172,103 +153,140 @@ static struct ir* tristate_compare(int size, int opcode) ); } -static struct ir* convert(int destsize, int srcsize, int opcode) -{ - switch (srcsize) - { - case 1: opcode += 0; break; - case 2: opcode += 1; break; - case 4: opcode += 2; break; - case 8: opcode += 3; break; - default: - fatal("can't convert from things of size %d", srcsize); - } - - return - new_ir1( - opcode, destsize, - pop() - ); -} - -void tb_insn_simple(int opcode, int flags) +static void insn_simple(int opcode) { switch (opcode) { case op_cii: { - struct ir* destsize = pop(); - struct ir* srcsize = pop(); + struct ir* destsize = pop(EM_wordsize); + struct ir* srcsize = pop(EM_wordsize); + struct ir* value; assert(srcsize->opcode == IR_ICONST); assert(destsize->opcode == IR_ICONST); + value = pop(srcsize->u.ivalue); push( - convert(destsize->u.ivalue, srcsize->u.ivalue, IR_FROMI1) + convert(value, destsize->u.ivalue, IR_FROMI1) ); break; } + case op_cmp: + push( + tristate_compare(EM_pointersize, IR_COMPAREU) + ); + break; + default: - fatal("unknown insn_simple instruction '%s'", + fatal("treebuilder: unknown simple instruction '%s'", em_mnem[opcode - sp_fmnem]); } } -void tb_insn_label(int opcode, int flags, const char* label, arith offset) +static void simple_branch2(int opcode, int size, + struct basicblock* truebb, struct basicblock* falsebb, + int irop) { - materialise(); + struct ir* right = pop(size); + struct ir* left = pop(size); + materialise_stack(); + appendir( + new_ir2( + IR_CJUMP, 0, + new_ir2( + irop, size, + left, right + ), + new_ir2( + IR_PAIR, 0, + new_bbir(truebb), + new_bbir(falsebb) + ) + ) + ); +} + +static void compare0_branch2(int opcode, + struct basicblock* truebb, struct basicblock* falsebb, + int irop) +{ + push( + new_wordir(0) + ); + + simple_branch2(opcode, EM_wordsize, truebb, falsebb, irop); +} + +static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock* rightbb) +{ switch (opcode) { - case op_zne: - { - struct basicblock* truebb = bb_get(label); - struct basicblock* falsebb = bb_get(NULL); + case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_IFEQ); break; + case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_IFLT); break; + case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_IFLE); break; - APPENDU(currentbb->outblocks, truebb); - APPENDU(currentbb->outblocks, falsebb); - - appendir( - new_ir3( - IR_CJUMP, 0, - pop(), - new_bbir(truebb), - new_bbir(falsebb) - ) - ); - - changeblock(falsebb); - break; - } + case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_IFEQ); break; + case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_IFLT); break; + case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_IFLE); break; case op_bra: { - struct basicblock* destbb = bb_get(label); - APPENDU(currentbb->outblocks, destbb); + materialise_stack(); appendir( new_ir1( IR_JUMP, 0, - new_bbir(destbb) + new_bbir(leftbb) ) ); break; } default: - fatal("unknown insn_label instruction '%s'", + fatal("treebuilder: unknown bvalue instruction '%s'", em_mnem[opcode - sp_fmnem]); } } -void tb_insn_value(int opcode, int flags, arith value) +static void simple_alu1(int opcode, int size, int irop) { - struct ir* left; - struct ir* right; + struct ir* val = pop(size); + push( + new_ir1( + irop, size, + val + ) + ); +} + +static void simple_alu2(int opcode, int size, int irop) +{ + struct ir* right = pop(size); + struct ir* left = pop(size); + + push( + new_ir2( + irop, size, + left, right + ) + ); +} + +static void insn_ivalue(int opcode, arith value) +{ switch (opcode) { + case op_adi: simple_alu2(opcode, value, IR_ADD); break; + case op_sbi: simple_alu2(opcode, value, IR_SUB); break; + case op_mli: simple_alu2(opcode, value, IR_MUL); break; + case op_dvi: simple_alu2(opcode, value, IR_DIV); break; + case op_rmi: simple_alu2(opcode, value, IR_MOD); break; + case op_ngi: simple_alu1(opcode, value, IR_NEG); break; + case op_lol: push( new_ir1( @@ -283,11 +301,17 @@ void tb_insn_value(int opcode, int flags, arith value) new_ir2( IR_STORE, EM_wordsize, address_of_local(value), - pop() + pop(EM_wordsize) ) ); break; + case op_lal: + push( + address_of_local(value) + ); + break; + case op_loc: push( new_wordir(value) @@ -298,22 +322,24 @@ void tb_insn_value(int opcode, int flags, arith value) push( new_ir1( IR_LOAD, value, - pop() + pop(EM_pointersize) ) ); break; case op_sti: - right = pop(); - left = pop(); + { + struct ir* ptr = pop(EM_pointersize); + struct ir* val = pop(value); appendir( new_ir2( IR_STORE, value, - right, left + ptr, val ) ); break; + } case op_cmi: push( @@ -328,24 +354,59 @@ void tb_insn_value(int opcode, int flags, arith value) break; case op_ads: - right = pop(); - left = pop(); + { + struct ir* off = pop(value); + struct ir* ptr = pop(EM_pointersize); if (value != EM_pointersize) - right = convert(EM_pointersize, value, IR_FROMI1); + off = convert(off, EM_pointersize, IR_FROMI1); push( new_ir2( - IR_ADD, EM_wordsize, - left, right + IR_ADD, EM_pointersize, + ptr, off ) ); break; + } + case op_adp: + { + struct ir* ptr = pop(EM_pointersize); + + push( + new_ir2( + IR_ADD, EM_pointersize, + ptr, + new_wordir(value) + ) + ); + break; + } + + case op_sbs: + { + struct ir* right = pop(EM_pointersize); + struct ir* left = pop(EM_pointersize); + + struct ir* delta = + new_ir2( + IR_SUB, EM_pointersize, + left, right + ); + + if (value != EM_pointersize) + delta = convert(delta, value, IR_FROMI1); + + push(delta); + break; + } + case op_dup: { - struct ir* v = pop(); - appendir(v); + struct ir* v = pop(value); + if (!v->is_sequence) + appendir(v); push(v); push(v); break; @@ -386,13 +447,12 @@ void tb_insn_value(int opcode, int flags, arith value) { if (value > 0) { - left = pop(); - assert(left->size == value); + struct ir* retval = pop(value); appendir( new_ir2( IR_SETREG, value, new_regir(IRR_RR), - left + retval ) ); } @@ -405,11 +465,138 @@ void tb_insn_value(int opcode, int flags, arith value) break; } + case op_lfr: + { + push( + appendir( + new_ir1( + IR_GETREG, value, + new_regir(IRR_RR) + ) + ) + ); + break; + } + default: - fatal("unknown insn_value instruction '%s'", + fatal("treebuilder: unknown ivalue instruction '%s'", em_mnem[opcode - sp_fmnem]); } } +static void insn_lvalue(int opcode, const char* label, arith offset) +{ + switch (opcode) + { + case op_lae: + push( + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(label), + new_wordir(offset) + ) + ); + break; + + case op_loe: + push( + new_ir1( + IR_LOAD, EM_wordsize, + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(label), + new_wordir(offset) + ) + ) + ); + break; + + case op_ste: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(label), + new_wordir(offset) + ), + pop(EM_wordsize) + ) + ); + break; + + case op_cal: + assert(offset == 0); + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(label) + ) + ); + break; + + default: + fatal("treebuilder: unknown lvalue instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } +} + +static void generate_tree(struct basicblock* bb) +{ + int i; + + printf("; BLOCK %s\n", bb->name); + current_bb = bb; + reset_stack(); + + for (i=0; iinsns_count; i++) + { + struct insn* insn = bb->insns[i]; + printf("\t; EM: %s ", em_mnem[insn->opcode - sp_fmnem]); + switch (insn->paramtype) + { + case PARAM_NONE: + printf("\n"); + insn_simple(insn->opcode); + break; + + case PARAM_IVALUE: + printf("value=%d\n", insn->u.ivalue); + insn_ivalue(insn->opcode, insn->u.ivalue); + break; + + case PARAM_LVALUE: + printf("label=%s offset=%d\n", + insn->u.lvalue.label, insn->u.lvalue.offset); + insn_lvalue(insn->opcode, insn->u.lvalue.label, insn->u.lvalue.offset); + break; + + case PARAM_BVALUE: + printf("true=%s", insn->u.bvalue.left->name); + if (insn->u.bvalue.right) + printf(" false=%s", insn->u.bvalue.right->name); + printf("\n"); + insn_bvalue(insn->opcode, insn->u.bvalue.left, insn->u.bvalue.right); + break; + + default: + assert(0); + } + + print_stack(); + } + + assert(stackptr == 0); +} + +void tb_procedure(struct procedure* current_proc) +{ + int i; + + for (i=0; iblocks_count; i++) + generate_tree(current_proc->blocks[i]); +} + /* vim: set sw=4 ts=4 expandtab : */ From dcba03646b0bc956743650060f1113e19aab582c Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 19 Sep 2016 23:30:41 +0200 Subject: [PATCH 006/230] Treebuilder now gets to the bottom of my test file, merrily generating (probably horribly broken) IR. --- mach/proto/mcg/ir.dat | 22 +++++++------ mach/proto/mcg/parse_em.c | 44 +++++++++++++++++++------ mach/proto/mcg/treebuilder.c | 63 ++++++++++++++++++++++++++++-------- 3 files changed, 97 insertions(+), 32 deletions(-) diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat index ea47cb0a0..4de21c007 100644 --- a/mach/proto/mcg/ir.dat +++ b/mach/proto/mcg/ir.dat @@ -24,16 +24,20 @@ MOD NEG NOT -# Conversions -FROMI1 -FROMI2 -FROMI4 -FROMI8 +AND +OR +EOR -FROMU1 -FROMU2 -FROMU4 -FROMU8 +# Conversions +CII1 +CII2 +CII4 +CII8 + +CIU1 +CIU2 +CIU4 +CIU8 # Tristate comparisons COMPARES diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 9310dda40..13320fe32 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -4,6 +4,8 @@ static struct e_instr insn; static struct procedure* current_proc; static struct basicblock* current_bb; +static void queue_insn_label(int opcode, const char* label, arith offset); + static const char* type_to_str(int type) { switch (type) @@ -57,6 +59,12 @@ static const char* dlabel_to_str(label l) return aprintf("__D%d", l); } +static void terminate_block(void) +{ + current_bb->is_terminated = true; + current_bb = NULL; +} + static struct insn* new_insn(int opcode) { struct insn* insn = calloc(sizeof(struct insn), 1); @@ -72,19 +80,38 @@ static void queue_insn_simple(int opcode) switch (opcode) { - case op_ret: - current_bb->is_terminated = true; - current_bb = NULL; + case op_bra: + terminate_block(); break; } } static void queue_insn_value(int opcode, arith value) { - struct insn* insn = new_insn(opcode); - insn->paramtype = PARAM_IVALUE; - insn->u.ivalue = value; - APPEND(current_bb->insns, insn); + switch (opcode) + { + case op_csa: + case op_csb: + { + const char* helper = aprintf(".%s%d", + (opcode == op_csa) ? "csa" : "csb", + value); + + queue_insn_label(op_cal, helper, 0); + queue_insn_value(op_asp, value + EM_pointersize); + queue_insn_value(op_lfr, value); + queue_insn_simple(op_bra); + break; + } + + default: + { + struct insn* insn = new_insn(opcode); + insn->paramtype = PARAM_IVALUE; + insn->u.ivalue = value; + APPEND(current_bb->insns, insn); + } + } } static void queue_insn_label(int opcode, const char* label, arith offset) @@ -109,8 +136,7 @@ static void queue_insn_block(int opcode, struct basicblock* left, struct basicbl APPENDU(current_bb->outblocks, right); APPENDU(current_bb->inblocks, current_bb); - current_bb->is_terminated = true; - current_bb = NULL; + terminate_block(); } static void queue_insn_ilabel(int opcode, int label) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index acd8f30cd..bf57026a0 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -23,7 +23,7 @@ static void push(struct ir* ir) * first. */ if (ir->size < EM_wordsize) - ir = convert(ir, EM_wordsize, IR_FROMU1); + ir = convert(ir, EM_wordsize, IR_CIU1); stack[stackptr++] = ir; } @@ -48,7 +48,7 @@ static struct ir* pop(int size) /* If we try to pop something which is smaller than a word, convert it first. */ if (size < EM_wordsize) - ir = convert(ir, size, IR_FROMU1); + ir = convert(ir, size, IR_CIU1); if (ir->size != size) fatal("expected an item on stack of size %d, but got %d\n", size, ir->size); @@ -153,25 +153,41 @@ static struct ir* tristate_compare(int size, int opcode) ); } +static void simple_convert(opcode) +{ + struct ir* destsize = pop(EM_wordsize); + struct ir* srcsize = pop(EM_wordsize); + struct ir* value; + + assert(srcsize->opcode == IR_ICONST); + assert(destsize->opcode == IR_ICONST); + + value = pop(srcsize->u.ivalue); + push( + convert(value, destsize->u.ivalue, opcode) + ); +} + static void insn_simple(int opcode) { switch (opcode) { - case op_cii: + case op_bra: { - struct ir* destsize = pop(EM_wordsize); - struct ir* srcsize = pop(EM_wordsize); - struct ir* value; + struct ir* dest = pop(EM_pointersize); - assert(srcsize->opcode == IR_ICONST); - assert(destsize->opcode == IR_ICONST); - - value = pop(srcsize->u.ivalue); - push( - convert(value, destsize->u.ivalue, IR_FROMI1) + materialise_stack(); + appendir( + new_ir1( + IR_JUMP, 0, + dest + ) ); break; } + + case op_cii: simple_convert(IR_CII1); break; + case op_ciu: simple_convert(IR_CIU1); break; case op_cmp: push( @@ -179,6 +195,20 @@ static void insn_simple(int opcode) ); break; + case op_cai: + { + struct ir* dest = pop(EM_pointersize); + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + dest + ) + ); + break; + } + default: fatal("treebuilder: unknown simple instruction '%s'", em_mnem[opcode - sp_fmnem]); @@ -287,6 +317,11 @@ static void insn_ivalue(int opcode, arith value) case op_rmi: simple_alu2(opcode, value, IR_MOD); break; case op_ngi: simple_alu1(opcode, value, IR_NEG); break; + case op_and: simple_alu2(opcode, value, IR_AND); break; + case op_ior: simple_alu2(opcode, value, IR_OR); break; + case op_xor: simple_alu2(opcode, value, IR_EOR); break; + case op_com: simple_alu1(opcode, value, IR_NOT); break; + case op_lol: push( new_ir1( @@ -359,7 +394,7 @@ static void insn_ivalue(int opcode, arith value) struct ir* ptr = pop(EM_pointersize); if (value != EM_pointersize) - off = convert(off, EM_pointersize, IR_FROMI1); + off = convert(off, EM_pointersize, IR_CII1); push( new_ir2( @@ -396,7 +431,7 @@ static void insn_ivalue(int opcode, arith value) ); if (value != EM_pointersize) - delta = convert(delta, value, IR_FROMI1); + delta = convert(delta, value, IR_CII1); push(delta); break; From 36d7d1ee4ed47f37a0feb4a6867df5809d1fff0b Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 20 Sep 2016 00:19:39 +0200 Subject: [PATCH 007/230] Create hacky fake basic blocks for data fragments, used to track which instruction labels descriptor blocks refer to; this allows csa and csb to know where they're going. --- mach/proto/mcg/basicblock.c | 28 ----------- mach/proto/mcg/mcg.h | 3 +- mach/proto/mcg/parse_em.c | 87 +++++++++++++++++++------------- mach/proto/mcg/treebuilder.c | 98 +++++++++++++++++++++++++++++------- 4 files changed, 134 insertions(+), 82 deletions(-) diff --git a/mach/proto/mcg/basicblock.c b/mach/proto/mcg/basicblock.c index 74d5e8add..0ac2a5567 100644 --- a/mach/proto/mcg/basicblock.c +++ b/mach/proto/mcg/basicblock.c @@ -39,32 +39,4 @@ void bb_alias(struct basicblock* block, const char* name) p->block = block; } -void bb_wire_outs_to_ins(struct basicblock* inblock, struct basicblock* outblock) -{ - int i; - - if (!outblock->is_wired) - { - for (i=0; iouts_count; i++) - { - struct ir* value = inblock->outs[i]; - APPEND(outblock->ins, - new_phiir(value->size) - ); - } - outblock->is_wired = true; - } - - assert(inblock->outs_count == outblock->ins_count); - for (i=0; iouts_count; i++) - { - struct ir* srcvalue = inblock->outs[i]; - struct ir* destvalue = outblock->ins[i]; - assert(srcvalue->size == destvalue->size); - assert(destvalue->opcode == IR_PHI); - - APPENDU(destvalue->u.phivalue.srcs, srcvalue); - } -} - /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index ce332fff9..997ae5340 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -82,7 +82,7 @@ struct basicblock ARRAY(struct basicblock, outblocks); ARRAY(struct ir, outs); ARRAY(struct ir, ins); - bool is_wired : 1; + bool is_root : 1; bool is_terminated : 1; }; @@ -105,7 +105,6 @@ extern void data_bss(arith size, int init); extern void bb_init(void); extern struct basicblock* bb_get(const char* name); extern void bb_alias(struct basicblock* block, const char* name); -extern void bb_wire_outs_to_ins(struct basicblock* outblock, struct basicblock* inblock); extern void tb_filestart(void); extern void tb_fileend(void); diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 13320fe32..a1c9889f7 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -2,7 +2,8 @@ static struct e_instr insn; static struct procedure* current_proc; -static struct basicblock* current_bb; +static struct basicblock* code_bb; +static struct basicblock* data_bb; static void queue_insn_label(int opcode, const char* label, arith offset); @@ -61,8 +62,8 @@ static const char* dlabel_to_str(label l) static void terminate_block(void) { - current_bb->is_terminated = true; - current_bb = NULL; + code_bb->is_terminated = true; + code_bb = NULL; } static struct insn* new_insn(int opcode) @@ -76,7 +77,7 @@ static void queue_insn_simple(int opcode) { struct insn* insn = new_insn(opcode); insn->paramtype = PARAM_NONE; - APPEND(current_bb->insns, insn); + APPEND(code_bb->insns, insn); switch (opcode) { @@ -88,29 +89,17 @@ static void queue_insn_simple(int opcode) static void queue_insn_value(int opcode, arith value) { + struct insn* insn = new_insn(opcode); + insn->paramtype = PARAM_IVALUE; + insn->u.ivalue = value; + APPEND(code_bb->insns, insn); + switch (opcode) { case op_csa: case op_csb: - { - const char* helper = aprintf(".%s%d", - (opcode == op_csa) ? "csa" : "csb", - value); - - queue_insn_label(op_cal, helper, 0); - queue_insn_value(op_asp, value + EM_pointersize); - queue_insn_value(op_lfr, value); - queue_insn_simple(op_bra); + terminate_block(); break; - } - - default: - { - struct insn* insn = new_insn(opcode); - insn->paramtype = PARAM_IVALUE; - insn->u.ivalue = value; - APPEND(current_bb->insns, insn); - } } } @@ -120,7 +109,14 @@ static void queue_insn_label(int opcode, const char* label, arith offset) insn->paramtype = PARAM_LVALUE; insn->u.lvalue.label = label; insn->u.lvalue.offset = offset; - APPEND(current_bb->insns, insn); + APPEND(code_bb->insns, insn); + + switch (opcode) + { + case op_bra: + terminate_block(); + break; + } } static void queue_insn_block(int opcode, struct basicblock* left, struct basicblock* right) @@ -129,12 +125,15 @@ static void queue_insn_block(int opcode, struct basicblock* left, struct basicbl insn->paramtype = PARAM_BVALUE; insn->u.bvalue.left = left; insn->u.bvalue.right = right; - APPEND(current_bb->insns, insn); + APPEND(code_bb->insns, insn); - APPENDU(current_bb->outblocks, left); + APPENDU(code_bb->outblocks, left); + APPENDU(left->inblocks, code_bb); if (right) - APPENDU(current_bb->outblocks, right); - APPENDU(current_bb->inblocks, current_bb); + { + APPENDU(code_bb->outblocks, right); + APPENDU(right->inblocks, code_bb); + } terminate_block(); } @@ -169,10 +168,10 @@ static void change_basicblock(struct basicblock* newbb) { APPENDU(current_proc->blocks, newbb); - if (current_bb && !current_bb->is_terminated) + if (code_bb && !code_bb->is_terminated) queue_insn_block(op_bra, newbb, NULL); - current_bb = newbb; + code_bb = newbb; } static void queue_ilabel(arith label) @@ -242,8 +241,21 @@ static void parse_pseu(void) break; case ilb_ptyp: - data_offset(ilabel_to_str(insn.em_ilb), 0, ro); + { + const char* label = ilabel_to_str(insn.em_ilb); + + /* This is really hacky; to handle basic block flow + * descriptor blocks, we need to track which bbs a descriptor + * can exit to. So we create fake bb objects for each + * block, purely to track this. + */ + + if (data_bb) + APPENDU(data_bb->outblocks, bb_get(label)); + + data_offset(label, 0, ro); break; + } default: unknown_type("con, rom"); @@ -270,15 +282,16 @@ static void parse_pseu(void) current_proc->name = strdup(insn.em_pnam); current_proc->root_bb = bb_get(current_proc->name); current_proc->nlocals = insn.em_nlocals; - current_bb = current_proc->root_bb; - APPEND(current_proc->blocks, current_bb); + code_bb = current_proc->root_bb; + code_bb->is_root = true; + APPEND(current_proc->blocks, code_bb); break; case ps_end: /* procedure end */ tb_procedure(current_proc); current_proc = NULL; - current_bb = NULL; + code_bb = NULL; break; default: @@ -338,8 +351,12 @@ void parse_em(void) break; case EM_DEFDLB: - data_label(dlabel_to_str(insn.em_dlb)); + { + const char* label = dlabel_to_str(insn.em_dlb); + data_label(label); + data_bb = bb_get(label); break; + } case EM_DEFDNAM: data_label(strdup(insn.em_dnam)); @@ -350,7 +367,7 @@ void parse_em(void) break; case EM_MNEM: - if (current_bb) + if (code_bb) { int flags = em_flag[insn.em_opcode - sp_fmnem]; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index bf57026a0..5b014ec5e 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -85,7 +85,7 @@ static void materialise_stack(void) { int i; - for (i=stackptr-1; i>=0; i--) + for (i=0; isize) @@ -153,7 +167,7 @@ static struct ir* tristate_compare(int size, int opcode) ); } -static void simple_convert(opcode) +static void simple_convert(int opcode) { struct ir* destsize = pop(EM_wordsize); struct ir* srcsize = pop(EM_wordsize); @@ -513,6 +527,42 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_csa: + case op_csb: + { + struct basicblock* data_bb; + int i; + const char* helper = aprintf(".%s%d", + (opcode == op_csa) ? "csa" : "csb", + value); + struct ir* descriptor = pop(EM_pointersize); + + if (descriptor->opcode != IR_LABEL) + fatal("csa/csb are only supported if they refer " + "directly to a descriptor block"); + + /* Splice the outgoing bbs in the data block into our own. */ + + data_bb = bb_get(descriptor->u.lvalue); + for (i=0; ioutblocks_count; i++) + { + struct basicblock* bb = data_bb->outblocks[i]; + printf("\t; may jump to %s\n", bb->name); + APPENDU(current_bb->outblocks, bb); + APPENDU(bb->inblocks, current_bb); + } + + push(descriptor); + materialise_stack(); + appendir( + new_ir1( + IR_JUMP, 0, + new_labelir(helper) + ) + ); + break; + } + default: fatal("treebuilder: unknown ivalue instruction '%s'", em_mnem[opcode - sp_fmnem]); @@ -525,11 +575,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset) { case op_lae: push( - new_ir2( - IR_ADD, EM_pointersize, - new_labelir(label), - new_wordir(offset) - ) + address_of_external(label, offset) ); break; @@ -537,11 +583,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset) push( new_ir1( IR_LOAD, EM_wordsize, - new_ir2( - IR_ADD, EM_pointersize, - new_labelir(label), - new_wordir(offset) - ) + address_of_external(label, offset) ) ); break; @@ -550,11 +592,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset) appendir( new_ir2( IR_STORE, EM_wordsize, - new_ir2( - IR_ADD, EM_pointersize, - new_labelir(label), - new_wordir(offset) - ), + address_of_external(label, offset), pop(EM_wordsize) ) ); @@ -570,6 +608,17 @@ static void insn_lvalue(int opcode, const char* label, arith offset) ) ); break; + + case op_bra: + assert(offset == 0); + materialise_stack(); + appendir( + new_ir1( + IR_JUMP, 0, + new_labelir(label) + ) + ); + break; default: fatal("treebuilder: unknown lvalue instruction '%s'", @@ -582,6 +631,13 @@ static void generate_tree(struct basicblock* bb) int i; printf("; BLOCK %s\n", bb->name); + if (bb->inblocks_count > 0) + { + printf("; Entered from:\n"); + for (i=0; iinblocks_count; i++) + printf("; %s\n", bb->inblocks[i]->name); + } + current_bb = bb; reset_stack(); @@ -623,6 +679,14 @@ static void generate_tree(struct basicblock* bb) } assert(stackptr == 0); + + if (bb->outblocks_count > 0) + { + printf("; Exiting to:\n"); + for (i=0; ioutblocks_count; i++) + printf("; %s\n", bb->outblocks[i]->name); + } + printf("\n"); } void tb_procedure(struct procedure* current_proc) From 13c117d15d1835b8911a9e24a00f52231c559e3d Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 20 Sep 2016 20:37:16 +0200 Subject: [PATCH 008/230] Import iburg. --- util/mcgg/LICENSE | 20 ++ util/mcgg/LOG | 39 +++ util/mcgg/README | 58 ++++ util/mcgg/UPSTREAM | 6 + util/mcgg/custom.mk | 0 util/mcgg/gram.y | 174 ++++++++++ util/mcgg/iburg.1 | 285 ++++++++++++++++ util/mcgg/iburg.c | 746 ++++++++++++++++++++++++++++++++++++++++++ util/mcgg/iburg.h | 65 ++++ util/mcgg/makefile | 23 ++ util/mcgg/sample4.brg | 109 ++++++ util/mcgg/sample5.brg | 85 +++++ 12 files changed, 1610 insertions(+) create mode 100644 util/mcgg/LICENSE create mode 100644 util/mcgg/LOG create mode 100644 util/mcgg/README create mode 100644 util/mcgg/UPSTREAM create mode 100644 util/mcgg/custom.mk create mode 100644 util/mcgg/gram.y create mode 100644 util/mcgg/iburg.1 create mode 100644 util/mcgg/iburg.c create mode 100644 util/mcgg/iburg.h create mode 100644 util/mcgg/makefile create mode 100644 util/mcgg/sample4.brg create mode 100644 util/mcgg/sample5.brg diff --git a/util/mcgg/LICENSE b/util/mcgg/LICENSE new file mode 100644 index 000000000..b21f90758 --- /dev/null +++ b/util/mcgg/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 1993,1994,1995,1996 David R. Hanson. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/util/mcgg/LOG b/util/mcgg/LOG new file mode 100644 index 000000000..3556af7cc --- /dev/null +++ b/util/mcgg/LOG @@ -0,0 +1,39 @@ +Tue Aug 12 10:03:34 PDT 1997 + +makefile: +Customized for use under NT. + +gram.y: +Fixed diagnostic formatting, handled cases when \n doesn't terminate +the input buffer; protected against versions of fgets that touch +buffer at EOF. + +sample4.brg: +Changed state value from int to long for 64-bit machines. + + +Tue May 7 14:20:11 PDT 1996 + +The distribution now includes the RCS files. +Specific changes are as follows; thanks to Francisco Arzu +(farzu@uvg.edu.gt) for these suggestions. + +gram.y: +Changed TERM to TERMINAL for bison. +Moved definition of yylineno for bison. +Changed hard-coded 32767 to maxcost, and checked +only costs against maxcost. +Replaced 0s in calls with NULL. + +iburg.1: +Document STATE_TYPE, -maxcost=ddd, and use of SHRT_MAX. + +iburg.c: +Implemented STATE_TYPE, default int. +Changed 32767 to maxcost, which is SHRT_MAX, SHRT_MAX/2 +(when sizeof(int)==sizeof(short)), or maxcost. Included limits.h. + + +Thu May 12 11:33:48 EDT 1994 + +initial release. diff --git a/util/mcgg/README b/util/mcgg/README new file mode 100644 index 000000000..339ca1553 --- /dev/null +++ b/util/mcgg/README @@ -0,0 +1,58 @@ +iburg -- A Code Generator Generator + +iburg is a code-generator generator that uses dynamic programming at +compile time. It's described in + +C. W. Fraser, D. R. Hanson and T. A. Proebsting, +Engineering a simple, efficient code generator generator, +ACM Letters on Prog. Languages and Systems 1, 3 (Sep. 1992), 213-226. +http://storage.webhop.net/documents/iburg.pdf + +iburg is written in and generates ANSI C and thus must be compiled +with an ANSI C compiler and preprocessor, e.g., gcc or lcc. To compile +iburg, type "make". There should be no warnings or errors (except +perhaps in the system-dependent YACC skeleton). If you need to +customize the makefile, edit custom.mk, which is included in makefile. +The default custom.mk is empty. + +sample.brg is from the paper in burg.ps, sample4.brg is from the paper +in iburg.ps, and sample5.brg is an example from a compilers course. +"make test" runs iburg on sample[45].brg and executes the resulting +programs. The output should be something like: + +% make test +./iburg -I sample4.brg sample4.c; cc -o test4 sample4.c; ./test4 +sample4.c +i = c + 4; +stmt: ASGNI(disp,reg) + disp: ADDRLP + reg: disp + disp: ADDI(reg,con) + reg: CVCI(INDIRC(disp)) + disp: ADDRLP + con: CNSTI +./iburg -I sample5.brg sample5.c; cc -o test5 sample5.c; ./test5 +sample5.c +stm: MOVE(MEM(loc),reg) + loc: NAME + reg: PLUS(MEM(loc),reg) + loc: PLUS(NAME,reg) + reg: MEM(loc) + loc: NAME + reg: con + con: CONST +% + +To install iburg, copy it and its man page to the appropriate local +directories, e.g., on UNIX: + +% cp iburg /usr/local +% cp iburg.1 /usr/local/man/man1 + +"make clobber" removes the executables and all derived files except +gram.c; "make clean" removes just object, core, and sample*.c files. + +Mail bug reports along with the shortest input that exposes them to +drh@drhanson.net. + +$Id$ diff --git a/util/mcgg/UPSTREAM b/util/mcgg/UPSTREAM new file mode 100644 index 000000000..9cd9ae41e --- /dev/null +++ b/util/mcgg/UPSTREAM @@ -0,0 +1,6 @@ +This is a copy of iburg from head of git here: + +https://github.com/drh/iburg + +Version: 2151dd7d126e2f804b822bb78059c870a3a15f5e + diff --git a/util/mcgg/custom.mk b/util/mcgg/custom.mk new file mode 100644 index 000000000..e69de29bb diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y new file mode 100644 index 000000000..965c9e9df --- /dev/null +++ b/util/mcgg/gram.y @@ -0,0 +1,174 @@ +%{ +#include +#include +#include +#include "iburg.h" +static char rcsid[] = "$Id$"; +static int yylineno = 0; +%} +%union { + int n; + char *string; + Tree tree; +} +%term TERMINAL +%term START +%term PPERCENT + +%token ID +%token INT +%type lhs +%type tree +%type cost +%% +spec : decls PPERCENT rules { yylineno = 0; } + | decls { yylineno = 0; } + ; + +decls : /* lambda */ + | decls decl + ; + +decl : TERMINAL blist '\n' + | START lhs '\n' { + if (nonterm($2)->number != 1) + yyerror("redeclaration of the start symbol\n"); + } + | '\n' + | error '\n' { yyerrok; } + ; + +blist : /* lambda */ + | blist ID '=' INT { term($2, $4); } + ; + +rules : /* lambda */ + | rules lhs ':' tree '=' INT cost ';' '\n' { rule($2, $4, $6, $7); } + | rules '\n' + | rules error '\n' { yyerrok; } + ; + +lhs : ID { nonterm($$ = $1); } + ; + +tree : ID { $$ = tree($1, NULL, NULL); } + | ID '(' tree ')' { $$ = tree($1, $3, NULL); } + | ID '(' tree ',' tree ')' { $$ = tree($1, $3, $5); } + ; + +cost : /* lambda */ { $$ = 0; } + | '(' INT ')' { if ($2 > maxcost) { + yyerror("%d exceeds maximum cost of %d\n", $2, maxcost); + $$ = maxcost; + } else + $$ = $2; } + ; +%% +#include +#include + +int errcnt = 0; +FILE *infp = NULL; +FILE *outfp = NULL; +static char buf[BUFSIZ], *bp = buf; +static int ppercent = 0; + +static int get(void) { + if (*bp == 0) { + bp = buf; + *bp = 0; + if (fgets(buf, sizeof buf, infp) == NULL) + return EOF; + yylineno++; + while (buf[0] == '%' && buf[1] == '{' && (buf[2] == '\n' || buf[2] == '\r')) { + for (;;) { + if (fgets(buf, sizeof buf, infp) == NULL) { + yywarn("unterminated %{...%}\n"); + return EOF; + } + yylineno++; + if (strcmp(buf, "%}\n") == 0 || strcmp(buf, "%}\r\n") == 0) + break; + fputs(buf, outfp); + } + if (fgets(buf, sizeof buf, infp) == NULL) + return EOF; + yylineno++; + } + } + return *bp++; +} + +void yyerror(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (yylineno > 0) + fprintf(stderr, "line %d: ", yylineno); + vfprintf(stderr, fmt, ap); + if (fmt[strlen(fmt)-1] != '\n') + fprintf(stderr, "\n"); + errcnt++; +} + +int yylex(void) { + int c; + + while ((c = get()) != EOF) { + switch (c) { + case ' ': case '\f': case '\t': case '\r': + continue; + case '\n': + case '(': case ')': case ',': + case ';': case '=': case ':': + return c; + } + if (c == '%' && *bp == '%') { + bp++; + return ppercent++ ? 0 : PPERCENT; + } else if (c == '%' && strncmp(bp, "term", 4) == 0 + && isspace(bp[4])) { + bp += 4; + return TERMINAL; + } else if (c == '%' && strncmp(bp, "start", 5) == 0 + && isspace(bp[5])) { + bp += 5; + return START; + } else if (isdigit(c)) { + int n = 0; + do { + int d = c - '0'; + if (n > (INT_MAX - d)/10) + yyerror("integer greater than %d\n", INT_MAX); + else + n = 10*n + d; + c = get(); + } while (c != EOF && isdigit(c)); + bp--; + yylval.n = n; + return INT; + } else if (isalpha(c)) { + char *p = bp - 1; + while (isalpha(*bp) || isdigit(*bp) || *bp == '_') + bp++; + yylval.string = alloc(bp - p + 1); + strncpy(yylval.string, p, bp - p); + yylval.string[bp - p] = 0; + return ID; + } else if (isprint(c)) + yyerror("invalid character `%c'\n", c); + else + yyerror("invalid character `\\%03o'\n", (unsigned char)c); + } + return 0; +} + +void yywarn(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (yylineno > 0) + fprintf(stderr, "line %d: ", yylineno); + fprintf(stderr, "warning: "); + vfprintf(stderr, fmt, ap); +} diff --git a/util/mcgg/iburg.1 b/util/mcgg/iburg.1 new file mode 100644 index 000000000..582143bdb --- /dev/null +++ b/util/mcgg/iburg.1 @@ -0,0 +1,285 @@ +.TH IBURG 1 "local \- 1/26/93" +.\" $Id$ +.SH NAME +iburg \- code generator generator +.SH SYNOPSIS +.B iburg +[ +.I option +]... +[ [ +.I input +] +.I output +] +.br +.SH DESCRIPTION +.PP +.I iburg +reads BURG specification from +.I input +and writes a pattern-matching code generator to +.IR output . +If +.I input +is `\-' or is omitted, +.I iburg +reads the standard input; +If +.I output +is `\-' or is omitted, +.I iburg +writes to the standard output. +.PP +.I iburg +accepts BURG specifications that conform to the following EBNF grammar. +Terminals are enclosed in single quotes, all other symbols are nonterminals, +{X} denotes zero or more instances of X, and [X] denotes an optional X. +.PP +.nf +.RS +.ft CW +spec: { dcl } `%%' { rule } [ `%%' ] + +dcl: `%start' nonterm + `%term' { identifier `=' integer } + +rule: nonterm `:' tree `=' integer [ cost ] `;' + +cost: `(' integer ')' + +tree: term `(' tree `,' tree `)' + term `(' tree `)' + term + nonterm +.RE +.fi +.PP +Specifications are structurally similar to +.IR yacc 's. +Text between +`\f(CW%{\fP' +and +`\f(CW%}\fP' +is called the configuration section; there may be several such segments. +All are concatenated and copied verbatim into the head of the generated +parser, which is called burm. +Text after the second +`\f(CW%%\fP', +if any, is also copied verbatim into +.IR burm , +at the end. +.PP +Specifications consist of declarations, a +`\f(CW%%\fP' +separator, and rules. +Input is line-oriented; each declaration and rule must appear on a separate line, +and declarations must begin in column 1. +Declarations declare terminals \(em the operators in subject +trees \(em and associate a unique, positive external symbol +number with each one. +Non-terminals are declared by their presence +on the left side of rules. The +\f(CW%start\fP +declaration optionally declares a non-terminal as the start symbol. +In the grammar above, +\f(CWterm\fP +and +\f(CWnonterm\fP +denote identifiers that are terminals and non-terminals, respectively. +.PP +Rules define tree patterns in a fully parenthesized prefix +form. Every non-terminal denotes a tree. +Each operator has a fixed +arity, which is inferred from the rules in which it is used. +A chain rule is a rule whose pattern is another non-terminal. +If no start symbol is declared, the non-terminal defined by the first rule is used. +.PP +Each rule has a unique, positive external rule number, which +comes after the pattern and is preceded by a +`\f(CW=\fP'. +External rule numbers are used to report the +matching rule to a user-supplied semantic action routine. +Rules end with an optional non-negative, integer cost; omitted costs +default to zero. +.PP +The display below shows a fragment of a BURG specification. +This example uses upper-case for terminals and lower-case for non-terminals. +.PP +.nf +.ft CW +%{ +enum { ADDI=309, ADDRLP=295, ASGNI=53, + CNSTI=21, CVCI=85, I0I=661, INDIRC=67 }; + +typedef struct tree { + int op; + struct tree *kids[2]; + int val; + struct { int state; } x; +} *NODEPTR_TYPE, *Tree; +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define PANIC printf +#define STATE_LABEL(p) ((p)->x.state) + +int OP_LABEL(NODEPTR_TYPE p) { + switch (p->op) { + case CNSTI: if (p->val == 0) return 661 /* I0I */; + default: return p->op; + } +} +%} +%term ADDI=309 ADDRLP=295 ASGNI=53 +%term CNSTI=21 CVCI=85 I0I=661 INDIRC=67 +%% +stmt: ASGNI(disp,reg) = 4 (1); +stmt: reg = 5; +reg: ADDI(reg,rc) = 6 (1); +reg: CVCI(INDIRC(disp)) = 7 (1); +reg: I0I = 8; +reg: disp = 9 (1); +disp: ADDI(reg,con) = 10; +disp: ADDRLP = 11; +rc: con = 12; +rc: reg = 13; +con: CNSTI = 14; +con: I0I = 15; +%% +.fi +.PP +The configuration section configures +\f(CWburm\fP +for the trees being parsed and the client's environment. +As shown, this section must define +\f(CWNODEPTR_TYPE\fP +to be a visible typedef symbol for a pointer to a +node in the subject tree. +\f(CWburm\fP +invokes +\f(CWOP_LABEL(p)\fP, +\f(CWLEFT\_CHILD(p)\fP, and +\f(CWRIGHT\_CHILD(p)\fP +to read the operator and children from the node pointed to by \f(CWp\fP. +It invokes +\f(CWPANIC\fP +when it detects an error. +If the configuration section defines these operations as macros, they are implemented in-line; +otherwise, they must be implemented as functions. +.PP +By default, +\f(CWburm\fP +computes and stores a single integral state in each node of the subject tree. +The configuration section must define a macro +\f(CWSTATE_LABEL(p)\fP +to access the state field of the node pointed to +by \f(CWp\fP. It must be large enough to hold a pointer, and +a macro is required because it is used as an lvalue. +The configuration section may define the macro +\f(CWSTATE_TYPE\fP +to specify a different type for state values; if +\f(CWSTATE_TYPE\fP +is not defined, int is used. +.PP +The configuration section may also define +\f(CWALLOC(n)\fP +for allocating +\f(CWn\fP +bytes. +If +\f(CWALLOC\fP +is not defined, +.IR malloc (3) +is used. +.SH OPTIONS +.TP +.BI \-p \ prefix +.br +.ns +.TP +.BI \-p prefix +Use +.I prefix +as the disambiquating prefix for exported names and visible fields. +The default is `\f(CWburm\fP'. +.TP +.BI \-maxcost= ddd +Use the integral value +.I ddd +as the maximum cost. +The default is \f(CWSHRT_MAX\fR +when ints are bigger than shorts, and +\f(CWSHRT_MAX\fP/2 when ints and shorts are the same size. +.TP +.B \-I +Emit code for the following data values and functions. +.sp +.nf +.ft CW + char burm_arity[]; + char *burm_opname[]; + char *burm_ntname[]; + char *burm_string[]; + short burm_cost[][4]; + int burm_op_label(NODEPTR_TYPE p); + NODEPTR_TYPE burm_child(NODEPTR_TYPE p, int index); + STATE_TYPE burm_state_label(NODEPTR_TYPE p); +.sp +.fi +.ft R +\f(CWburm_arity\fP and +\f(CWburm_opname\fP +are indexed by external symbol numbers and gives their arities. +\f(CWburm_ntname\fP +is indexed by a non-terminal number and gives its string name. +\f(CWburm_string\fP +and +\f(CWburm_cost\fP +are indexed by an external rule number and give the string +representation and cost of each rule. +The functions encapsulate the similarly named macros. +.TP +.B \-T +Arrange for +.sp +.nf +.ft CW + void burm_trace(NODEPTR_TYPE p, int eruleno, + int cost, int bestcost); +.sp +.fi +.ft R +to be called at each successful match. +\f(CWp\fP +identifies the node and +\f(CWeruleno\fP +identifies the matching rule; +\f(CWeruleno\fP +is an index into \f(CWburm_string\fP. +\f(CWcost\fP +is the cost of the match and +\f(CWbestcost\fP +is the cost of the best previous match. The current match +wins only if +\f(CWcost\fP +is less than \f(CWbestcost\fP. +SHRT_MAX represents the infinite cost of no previous match. +\f(CWburm_trace\fP must be declared in the configuration section. +.SH "SEE ALSO" +C. W. Fraser, R. R. Henry and T. A. Proebsting, +`BURG \(em Fast optimal instruction selection and tree parsing,' +.I +SIGPLAN Notices +.BR 27 , +4 (Apr. 1992), 68-76. +.PP +C. W. Fraser, D. R. Hanson and T. A. Proebsting, +`Engineering a simple, efficient code generator generator,' +.I +ACM Letters on Programming Languages and Systems +.BR 1 , +3 (Sep. 1992), 213-226. +.br +.SH BUGS +Mail bug reports along with the shortest input +that exposes them to drh@drhanson.net. diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c new file mode 100644 index 000000000..18e80ad60 --- /dev/null +++ b/util/mcgg/iburg.c @@ -0,0 +1,746 @@ +#include +#include +#include +#include +#include +#include +#include +#include "iburg.h" + +static char rcsid[] = "$Id$"; + +int maxcost = SHRT_MAX; + +static char *prefix = "burm"; +static int Iflag = 0, Tflag = 0; +static int ntnumber = 0; +static Nonterm start = 0; +static Term terms; +static Nonterm nts; +static Rule rules; +static int nrules; + +static char *stringf(char *fmt, ...); +static void print(char *fmt, ...); +static void ckreach(Nonterm p); +static void emitclosure(Nonterm nts); +static void emitcost(Tree t, char *v); +static void emitdefs(Nonterm nts, int ntnumber); +static void emitfuncs(void); +static void emitheader(void); +static void emitkids(Rule rules, int nrules); +static void emitlabel(Nonterm start); +static void emitleaf(Term p, int ntnumber); +static void emitnts(Rule rules, int nrules); +static void emitrecord(char *pre, Rule r, int cost); +static void emitrule(Nonterm nts); +static void emitstate(Term terms, Nonterm start, int ntnumber); +static void emitstring(Rule rules); +static void emitstruct(Nonterm nts, int ntnumber); +static void emitterms(Term terms); +static void emittest(Tree t, char *v, char *suffix); + +int main(int argc, char *argv[]) { + int c, i; + Nonterm p; + + if (sizeof (short) == sizeof (int)) + maxcost = SHRT_MAX/2; + for (i = 1; i < argc; i++) + if (strcmp(argv[i], "-I") == 0) + Iflag = 1; + else if (strcmp(argv[i], "-T") == 0) + Tflag = 1; + else if (strncmp(argv[i], "-maxcost=", 9) == 0 && isdigit(argv[i][9])) + maxcost = atoi(argv[i] + 9); + else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2]) + prefix = &argv[i][2]; + else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc) + prefix = argv[++i]; + else if (*argv[i] == '-' && argv[i][1]) { + yyerror("usage: %s [-T | -I | -p prefix | -maxcost=ddd ]... [ [ input ] output \n", + argv[0]); + exit(1); + } else if (infp == NULL) { + if (strcmp(argv[i], "-") == 0) + infp = stdin; + else if ((infp = fopen(argv[i], "r")) == NULL) { + yyerror("%s: can't read `%s'\n", argv[0], argv[i]); + exit(1); + } + } else if (outfp == NULL) { + if (strcmp(argv[i], "-") == 0) + outfp = stdout; + if ((outfp = fopen(argv[i], "w")) == NULL) { + yyerror("%s: can't write `%s'\n", argv[0], argv[i]); + exit(1); + } + } + if (infp == NULL) + infp = stdin; + if (outfp == NULL) + outfp = stdout; + yyparse(); + if (start) + ckreach(start); + for (p = nts; p; p = p->link) + if (!p->reached) + yyerror("can't reach non-terminal `%s'\n", p->name); + emitheader(); + emitdefs(nts, ntnumber); + emitstruct(nts, ntnumber); + emitnts(rules, nrules); + emitterms(terms); + if (Iflag) + emitstring(rules); + emitrule(nts); + emitclosure(nts); + if (start) + emitstate(terms, start, ntnumber); + print("#ifdef STATE_LABEL\n"); + if (start) + emitlabel(start); + emitkids(rules, nrules); + emitfuncs(); + print("#endif\n"); + if (!feof(infp)) + while ((c = getc(infp)) != EOF) + putc(c, outfp); + return errcnt > 0; +} + +/* alloc - allocate nbytes or issue fatal error */ +void *alloc(int nbytes) { + void *p = calloc(1, nbytes); + + if (p == NULL) { + yyerror("out of memory\n"); + exit(1); + } + return p; +} + +/* stringf - format and save a string */ +static char *stringf(char *fmt, ...) { + va_list ap; + char *s, buf[512]; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + return strcpy(alloc(strlen(buf) + 1), buf); +} + +struct entry { + union { + char *name; + struct term t; + struct nonterm nt; + } sym; + struct entry *link; +} *table[211]; +#define HASHSIZE (sizeof table/sizeof table[0]) + +/* hash - return hash number for str */ +static unsigned hash(char *str) { + unsigned h = 0; + + while (*str) + h = (h<<1) + *str++; + return h; +} + +/* lookup - lookup symbol name */ +static void *lookup(char *name) { + struct entry *p = table[hash(name)%HASHSIZE]; + + for ( ; p; p = p->link) + if (strcmp(name, p->sym.name) == 0) + return &p->sym; + return 0; +} + +/* install - install symbol name */ +static void *install(char *name) { + struct entry *p = alloc(sizeof *p); + int i = hash(name)%HASHSIZE; + + p->sym.name = name; + p->link = table[i]; + table[i] = p; + return &p->sym; +} + +/* nonterm - create a new terminal id, if necessary */ +Nonterm nonterm(char *id) { + Nonterm p = lookup(id), *q = &nts; + + if (p && p->kind == NONTERM) + return p; + if (p && p->kind == TERM) + yyerror("`%s' is a terminal\n", id); + p = install(id); + p->kind = NONTERM; + p->number = ++ntnumber; + if (p->number == 1) + start = p; + while (*q && (*q)->number < p->number) + q = &(*q)->link; + assert(*q == 0 || (*q)->number != p->number); + p->link = *q; + *q = p; + return p; +} + +/* term - create a new terminal id with external symbol number esn */ +Term term(char *id, int esn) { + Term p = lookup(id), *q = &terms; + + if (p) + yyerror("redefinition of terminal `%s'\n", id); + else + p = install(id); + p->kind = TERM; + p->esn = esn; + p->arity = -1; + while (*q && (*q)->esn < p->esn) + q = &(*q)->link; + if (*q && (*q)->esn == p->esn) + yyerror("duplicate external symbol number `%s=%d'\n", + p->name, p->esn); + p->link = *q; + *q = p; + return p; +} + +/* tree - create & initialize a tree node with the given fields */ +Tree tree(char *id, Tree left, Tree right) { + Tree t = alloc(sizeof *t); + Term p = lookup(id); + int arity = 0; + + if (left && right) + arity = 2; + else if (left) + arity = 1; + if (p == NULL && arity > 0) { + yyerror("undefined terminal `%s'\n", id); + p = term(id, -1); + } else if (p == NULL && arity == 0) + p = (Term)nonterm(id); + else if (p && p->kind == NONTERM && arity > 0) { + yyerror("`%s' is a non-terminal\n", id); + p = term(id, -1); + } + if (p->kind == TERM && p->arity == -1) + p->arity = arity; + if (p->kind == TERM && arity != p->arity) + yyerror("inconsistent arity for terminal `%s'\n", id); + t->op = p; + t->nterms = p->kind == TERM; + if (t->left = left) + t->nterms += left->nterms; + if (t->right = right) + t->nterms += right->nterms; + return t; +} + +/* rule - create & initialize a rule with the given fields */ +Rule rule(char *id, Tree pattern, int ern, int cost) { + Rule r = alloc(sizeof *r), *q; + Term p = pattern->op; + + nrules++; + r->lhs = nonterm(id); + r->packed = ++r->lhs->lhscount; + for (q = &r->lhs->rules; *q; q = &(*q)->decode) + ; + *q = r; + r->pattern = pattern; + r->ern = ern; + r->cost = cost; + if (p->kind == TERM) { + r->next = p->rules; + p->rules = r; + } else if (pattern->left == NULL && pattern->right == NULL) { + Nonterm p = pattern->op; + r->chain = p->chain; + p->chain = r; + } + for (q = &rules; *q && (*q)->ern < r->ern; q = &(*q)->link) + ; + if (*q && (*q)->ern == r->ern) + yyerror("duplicate external rule number `%d'\n", r->ern); + r->link = *q; + *q = r; + return r; +} + +/* print - formatted output */ +static void print(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + for ( ; *fmt; fmt++) + if (*fmt == '%') + switch (*++fmt) { + case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break; + case 's': fputs(va_arg(ap, char *), outfp); break; + case 'P': fprintf(outfp, "%s_", prefix); break; + case 'T': { + Tree t = va_arg(ap, Tree); + print("%S", t->op); + if (t->left && t->right) + print("(%T,%T)", t->left, t->right); + else if (t->left) + print("(%T)", t->left); + break; + } + case 'R': { + Rule r = va_arg(ap, Rule); + print("%S: %T", r->lhs, r->pattern); + break; + } + case 'S': fputs(va_arg(ap, Term)->name, outfp); break; + case '1': case '2': case '3': case '4': case '5': { + int n = *fmt - '0'; + while (n-- > 0) + putc('\t', outfp); + break; + } + default: putc(*fmt, outfp); break; + } + else + putc(*fmt, outfp); + va_end(ap); +} + +/* reach - mark all non-terminals in tree t as reachable */ +static void reach(Tree t) { + Nonterm p = t->op; + + if (p->kind == NONTERM) + if (!p->reached) + ckreach(p); + if (t->left) + reach(t->left); + if (t->right) + reach(t->right); +} + +/* ckreach - mark all non-terminals reachable from p */ +static void ckreach(Nonterm p) { + Rule r; + + p->reached = 1; + for (r = p->rules; r; r = r->decode) + reach(r->pattern); +} + +/* emitcase - emit one case in function state */ +static void emitcase(Term p, int ntnumber) { + Rule r; + + print("%1case %d: /* %S */\n", p->esn, p); + switch (p->arity) { + case 0: case -1: + if (!Tflag) { + emitleaf(p, ntnumber); + return; + } + break; + case 1: print("%2assert(l);\n"); break; + case 2: print("%2assert(l && r);\n"); break; + default: assert(0); + } + for (r = p->rules; r; r = r->next) { + switch (p->arity) { + case 0: case -1: + print("%2{%1/* %R */\n%3c = ", r); + break; + case 1: + if (r->pattern->nterms > 1) { + print("%2if (%1/* %R */\n", r); + emittest(r->pattern->left, "l", " "); + print("%2) {\n%3c = "); + } else + print("%2{%1/* %R */\n%3c = ", r); + emitcost(r->pattern->left, "l"); + break; + case 2: + if (r->pattern->nterms > 1) { + print("%2if (%1/* %R */\n", r); + emittest(r->pattern->left, "l", + r->pattern->right->nterms ? " && " : " "); + emittest(r->pattern->right, "r", " "); + print("%2) {\n%3c = "); + } else + print("%2{%1/* %R */\n%3c = ", r); + emitcost(r->pattern->left, "l"); + emitcost(r->pattern->right, "r"); + break; + default: assert(0); + } + print("%d;\n", r->cost); + emitrecord("\t\t\t", r, 0); + print("%2}\n"); + } + print("%2break;\n"); +} + +/* emitclosure - emit the closure functions */ +static void emitclosure(Nonterm nts) { + Nonterm p; + + for (p = nts; p; p = p->link) + if (p->chain) + print("static void %Pclosure_%S(struct %Pstate *, int);\n", p); + print("\n"); + for (p = nts; p; p = p->link) + if (p->chain) { + Rule r; + print("static void %Pclosure_%S(struct %Pstate *p, int c) {\n", p); + for (r = p->chain; r; r = r->chain) + emitrecord("\t", r, r->cost); + print("}\n\n"); + } +} + +/* emitcost - emit cost computation for tree t */ +static void emitcost(Tree t, char *v) { + Nonterm p = t->op; + + if (p->kind == TERM) { + if (t->left) + emitcost(t->left, stringf("%s->left", v)); + if (t->right) + emitcost(t->right, stringf("%s->right", v)); + } else + print("%s->cost[%P%S_NT] + ", v, p); +} + +/* emitdefs - emit non-terminal defines and data structures */ +static void emitdefs(Nonterm nts, int ntnumber) { + Nonterm p; + + for (p = nts; p; p = p->link) + print("#define %P%S_NT %d\n", p, p->number); + print("int %Pmax_nt = %d;\n\n", ntnumber); + if (Iflag) { + print("char *%Pntname[] = {\n%10,\n"); + for (p = nts; p; p = p->link) + print("%1\"%S\",\n", p); + print("%10\n};\n\n"); + } +} + +/* emitfuncs - emit functions to access node fields */ +static void emitfuncs(void) { + print("int %Pop_label(NODEPTR_TYPE p) {\n" +"%1%Passert(p, PANIC(\"NULL tree in %Pop_label\\n\"));\n" +"%1return OP_LABEL(p);\n}\n\n"); + print("STATE_TYPE %Pstate_label(NODEPTR_TYPE p) {\n" +"%1%Passert(p, PANIC(\"NULL tree in %Pstate_label\\n\"));\n" +"%1return STATE_LABEL(p);\n}\n\n"); + print("NODEPTR_TYPE %Pchild(NODEPTR_TYPE p, int index) {\n" +"%1%Passert(p, PANIC(\"NULL tree in %Pchild\\n\"));\n" +"%1switch (index) {\n%1case 0:%1return LEFT_CHILD(p);\n" +"%1case 1:%1return RIGHT_CHILD(p);\n%1}\n" +"%1%Passert(0, PANIC(\"Bad index %%d in %Pchild\\n\", index));\n%1return 0;\n}\n\n"); +} + +/* emitheader - emit initial definitions */ +static void emitheader(void) { + print("#include \n#include \n"); + print("#ifndef STATE_TYPE\n#define STATE_TYPE int\n#endif\n"); + print("#ifndef ALLOC\n#define ALLOC(n) malloc(n)\n#endif\n" +"#ifndef %Passert\n#define %Passert(x,y) if (!(x)) { y; abort(); }\n#endif\n\n"); + if (Tflag) + print("static NODEPTR_TYPE %Pnp;\n\n"); +} + +/* computekids - compute paths to kids in tree t */ +static char *computekids(Tree t, char *v, char *bp, int *ip) { + Term p = t->op; + + if (p->kind == NONTERM) { + sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v); + bp += strlen(bp); + } else if (p->arity > 0) { + bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip); + if (p->arity == 2) + bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip); + } + return bp; +} + +/* emitkids - emit burm_kids */ +static void emitkids(Rule rules, int nrules) { + int i; + Rule r, *rc = alloc((nrules + 1)*sizeof *rc); + char **str = alloc((nrules + 1)*sizeof *str); + + for (i = 0, r = rules; r; r = r->link) { + int j = 0; + char buf[1024], *bp = buf; + *computekids(r->pattern, "p", bp, &j) = 0; + for (j = 0; str[j] && strcmp(str[j], buf); j++) + ; + if (str[j] == NULL) + str[j] = strcpy(alloc(strlen(buf) + 1), buf); + r->kids = rc[j]; + rc[j] = r; + } + print("NODEPTR_TYPE *%Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n" +"%1%Passert(p, PANIC(\"NULL tree in %Pkids\\n\"));\n" +"%1%Passert(kids, PANIC(\"NULL kids in %Pkids\\n\"));\n" +"%1switch (eruleno) {\n"); + for (i = 0; r = rc[i]; i++) { + for ( ; r; r = r->kids) + print("%1case %d: /* %R */\n", r->ern, r); + print("%s%2break;\n", str[i]); + } + print("%1default:\n%2%Passert(0, PANIC(\"Bad external rule number %%d in %Pkids\\n\", eruleno));\n%1}\n%1return kids;\n}\n\n"); +} + +/* emitlabel - emit the labelling functions */ +static void emitlabel(Nonterm start) { + print("static void %Plabel1(NODEPTR_TYPE p) {\n" +"%1%Passert(p, PANIC(\"NULL tree in %Plabel\\n\"));\n" +"%1switch (%Parity[OP_LABEL(p)]) {\n" +"%1case 0:\n"); + if (Tflag) + print("%2%Pnp = p;\n"); + print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p), 0, 0);\n%2break;\n" +"%1case 1:\n%2%Plabel1(LEFT_CHILD(p));\n"); + if (Tflag) + print("%2%Pnp = p;\n"); + print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p),\n" +"%3STATE_LABEL(LEFT_CHILD(p)), 0);\n%2break;\n" +"%1case 2:\n%2%Plabel1(LEFT_CHILD(p));\n%2%Plabel1(RIGHT_CHILD(p));\n"); + if (Tflag) + print("%2%Pnp = p;\n"); + print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p),\n" +"%3STATE_LABEL(LEFT_CHILD(p)),\n%3STATE_LABEL(RIGHT_CHILD(p)));\n%2break;\n" +"%1}\n}\n\n"); + print( +"STATE_TYPE %Plabel(NODEPTR_TYPE p) {\n%1%Plabel1(p);\n" +"%1return ((struct %Pstate *)STATE_LABEL(p))->rule.%P%S ? STATE_LABEL(p) : 0;\n" +"}\n\n", start); +} + +/* closure - fill in cost & rule with results of chain rules w/p as rhs */ +static void closure(int cost[], Rule rule[], Nonterm p, int c) { + Rule r; + + for (r = p->chain; r; r = r->chain) + if (c + r->cost < cost[r->lhs->number]) { + cost[r->lhs->number] = c + r->cost; + rule[r->lhs->number] = r; + closure(cost, rule, r->lhs, c + r->cost); + } +} + +/* emitleaf - emit state code for a leaf */ +static void emitleaf(Term p, int ntnumber) { + int i; + Rule r; + static int *cost; + static Rule *rule; + + if (cost == NULL) { + cost = alloc((ntnumber + 1)*sizeof *cost); + rule = alloc((ntnumber + 1)*sizeof *rule); + } + for (i = 0; i <= ntnumber; i++) { + cost[i] = maxcost; + rule[i] = NULL; + } + for (r = p->rules; r; r = r->next) + if (r->pattern->left == NULL && r->pattern->right == NULL) { + cost[r->lhs->number] = r->cost; + rule[r->lhs->number] = r; + closure(cost, rule, r->lhs, r->cost); + } + print("%2{\n%3static struct %Pstate z = { %d, 0, 0,\n%4{%10,\n", p->esn); + for (i = 1; i <= ntnumber; i++) + if (cost[i] < maxcost) + print("%5%d,%1/* %R */\n", cost[i], rule[i]); + else + print("%5%d,\n", cost[i]); + print("%4},{\n"); + for (i = 1; i <= ntnumber; i++) + if (rule[i]) + print("%5%d,%1/* %R */\n", rule[i]->packed, rule[i]); + else + print("%50,\n"); + print("%4}\n%3};\n%3return (STATE_TYPE)&z;\n%2}\n"); +} + +/* computents - fill in bp with burm_nts vector for tree t */ +static char *computents(Tree t, char *bp) { + if (t) { + Nonterm p = t->op; + if (p->kind == NONTERM) { + sprintf(bp, "%s_%s_NT, ", prefix, p->name); + bp += strlen(bp); + } else + bp = computents(t->right, computents(t->left, bp)); + } + return bp; +} + +/* emitnts - emit burm_nts ragged array */ +static void emitnts(Rule rules, int nrules) { + Rule r; + int i, j, *nts = alloc(nrules*sizeof *nts); + char **str = alloc(nrules*sizeof *str); + + for (i = 0, r = rules; r; r = r->link) { + char buf[1024]; + *computents(r->pattern, buf) = 0; + for (j = 0; str[j] && strcmp(str[j], buf); j++) + ; + if (str[j] == NULL) { + print("static short %Pnts_%d[] = { %s0 };\n", j, buf); + str[j] = strcpy(alloc(strlen(buf) + 1), buf); + } + nts[i++] = j; + } + print("\nshort *%Pnts[] = {\n"); + for (i = j = 0, r = rules; r; r = r->link) { + for ( ; j < r->ern; j++) + print("%10,%1/* %d */\n", j); + print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++); + } + print("};\n\n"); +} + +/* emitrecord - emit code that tests for a winning match of rule r */ +static void emitrecord(char *pre, Rule r, int cost) { + print("%sif (", pre); + if (Tflag) + print("%Ptrace(%Pnp, %d, c + %d, p->cost[%P%S_NT]), ", + r->ern, cost, r->lhs); + print("c + %d < p->cost[%P%S_NT]) {\n" +"%s%1p->cost[%P%S_NT] = c + %d;\n%s%1p->rule.%P%S = %d;\n", + cost, r->lhs, pre, r->lhs, cost, pre, r->lhs, + r->packed); + if (r->lhs->chain) + print("%s%1%Pclosure_%S(p, c + %d);\n", pre, r->lhs, cost); + print("%s}\n", pre); +} + +/* emitrule - emit decoding vectors and burm_rule */ +static void emitrule(Nonterm nts) { + Nonterm p; + + for (p = nts; p; p = p->link) { + Rule r; + print("static short %Pdecode_%S[] = {\n%10,\n", p); + for (r = p->rules; r; r = r->decode) + print("%1%d,\n", r->ern); + print("};\n\n"); + } + print("int %Prule(STATE_TYPE state, int goalnt) {\n" +"%1%Passert(goalnt >= 1 && goalnt <= %d, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n" +"%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber); + for (p = nts; p; p = p->link) + print("%1case %P%S_NT:" +"%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p); + print("%1default:\n%2%Passert(0, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n%1}\n%1return 0;\n}\n\n"); +} + +/* emitstate - emit state function */ +static void emitstate(Term terms, Nonterm start, int ntnumber) { + int i; + Term p; + + print("STATE_TYPE %Pstate(int op, STATE_TYPE left, STATE_TYPE right) {\n%1int c;\n" +"%1struct %Pstate *p, *l = (struct %Pstate *)left,\n" +"%2*r = (struct %Pstate *)right;\n\n%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1"); + if (!Tflag) + print("if (%Parity[op] > 0) "); + print("{\n%2p = ALLOC(sizeof *p);\n" +"%2%Passert(p, PANIC(\"ALLOC returned NULL in %Pstate\\n\"));\n" +"%2p->op = op;\n%2p->left = l;\n%2p->right = r;\n%2p->rule.%P%S = 0;\n", start); + for (i = 1; i <= ntnumber; i++) + print("%2p->cost[%d] =\n", i); + print("%3%d;\n%1}\n%1switch (op) {\n", maxcost); + for (p = terms; p; p = p->link) + emitcase(p, ntnumber); + print("%1default:\n" +"%2%Passert(0, PANIC(\"Bad operator %%d in %Pstate\\n\", op));\n%1}\n" +"%1return (STATE_TYPE)p;\n}\n\n"); +} + +/* emitstring - emit array of rules and costs */ +static void emitstring(Rule rules) { + Rule r; + int k; + + print("short %Pcost[][4] = {\n"); + for (k = 0, r = rules; r; r = r->link) { + for ( ; k < r->ern; k++) + print("%1{ 0 },%1/* %d */\n", k); + print("%1{ %d },%1/* %d = %R */\n", r->cost, k++, r); + } + print("};\n\nchar *%Pstring[] = {\n"); + for (k = 0, r = rules; r; r = r->link) { + for ( ; k < r->ern; k++) + print("%1/* %d */%10,\n", k); + print("%1/* %d */%1\"%R\",\n", k++, r); + } + print("};\n\n"); +} + +/* emitstruct - emit the definition of the state structure */ +static void emitstruct(Nonterm nts, int ntnumber) { + print("struct %Pstate {\n%1int op;\n%1struct %Pstate *left, *right;\n" +"%1short cost[%d];\n%1struct {\n", ntnumber + 1); + for ( ; nts; nts = nts->link) { + int n = 1, m = nts->lhscount; + while (m >>= 1) + n++; + print("%2unsigned %P%S:%d;\n", nts, n); + } + print("%1} rule;\n};\n\n"); +} + +/* emitterms - emit terminal data structures */ +static void emitterms(Term terms) { + Term p; + int k; + + print("char %Parity[] = {\n"); + for (k = 0, p = terms; p; p = p->link) { + for ( ; k < p->esn; k++) + print("%10,%1/* %d */\n", k); + print("%1%d,%1/* %d=%S */\n", p->arity < 0 ? 0 : p->arity, k++, p); + } + print("};\n\n"); + if (Iflag) { + print("char *%Popname[] = {\n"); + for (k = 0, p = terms; p; p = p->link) { + for ( ; k < p->esn; k++) + print("%1/* %d */%10,\n", k); + print("%1/* %d */%1\"%S\",\n", k++, p); + } + print("};\n\n"); + } +} + +/* emittest - emit clause for testing a match */ +static void emittest(Tree t, char *v, char *suffix) { + Term p = t->op; + + if (p->kind == TERM) { + print("%3%s->op == %d%s/* %S */\n", v, p->esn, + t->nterms > 1 ? " && " : suffix, p); + if (t->left) + emittest(t->left, stringf("%s->left", v), + t->right && t->right->nterms ? " && " : suffix); + if (t->right) + emittest(t->right, stringf("%s->right", v), suffix); + } +} diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h new file mode 100644 index 000000000..e55d5a8f9 --- /dev/null +++ b/util/mcgg/iburg.h @@ -0,0 +1,65 @@ +#ifndef BURG_INCLUDED +#define BURG_INCLUDED + +/* $Id$ */ +/* iburg.c: */ +extern void *alloc(int nbytes); + +typedef enum { TERM=1, NONTERM } Kind; +typedef struct rule *Rule; +typedef struct term *Term; +struct term { /* terminals: */ + char *name; /* terminal name */ + Kind kind; /* TERM */ + int esn; /* external symbol number */ + int arity; /* operator arity */ + Term link; /* next terminal in esn order */ + Rule rules; /* rules whose pattern starts with term */ +}; + +typedef struct nonterm *Nonterm; +struct nonterm { /* non-terminals: */ + char *name; /* non-terminal name */ + Kind kind; /* NONTERM */ + int number; /* identifying number */ + int lhscount; /* # times nt appears in a rule lhs */ + int reached; /* 1 iff reached from start non-terminal */ + Rule rules; /* rules w/non-terminal on lhs */ + Rule chain; /* chain rules w/non-terminal on rhs */ + Nonterm link; /* next terminal in number order */ +}; +extern Nonterm nonterm(char *id); +extern Term term(char *id, int esn); + +typedef struct tree *Tree; +struct tree { /* tree patterns: */ + void *op; /* a terminal or non-terminal */ + Tree left, right; /* operands */ + int nterms; /* number of terminal nodes in this tree */ +}; +extern Tree tree(char *op, Tree left, Tree right); + +struct rule { /* rules: */ + Nonterm lhs; /* lefthand side non-terminal */ + Tree pattern; /* rule pattern */ + int ern; /* external rule number */ + int packed; /* packed external rule number */ + int cost; /* associated cost */ + Rule link; /* next rule in ern order */ + Rule next; /* next rule with same pattern root */ + Rule chain; /* next chain rule with same rhs */ + Rule decode; /* next rule with same lhs */ + Rule kids; /* next rule with same burm_kids pattern */ +}; +extern Rule rule(char *id, Tree pattern, int ern, int cost); +extern int maxcost; /* maximum cost */ + +/* gram.y: */ +void yyerror(char *fmt, ...); +int yyparse(void); +void yywarn(char *fmt, ...); +extern int errcnt; +extern FILE *infp; +extern FILE *outfp; + +#endif diff --git a/util/mcgg/makefile b/util/mcgg/makefile new file mode 100644 index 000000000..bff5d9ab2 --- /dev/null +++ b/util/mcgg/makefile @@ -0,0 +1,23 @@ +# $Id$ +O=.o +E= +CFLAGS= +LDFLAGS= +YFLAGS= +OBJS=iburg$O gram$O +CUSTOM=custom.mk +include $(CUSTOM) + +iburg$E: $(OBJS); $(CC) -o $@ $(LDFLAGS) $(OBJS) + +$(OBJS): iburg.h + +test: iburg$E sample4.brg sample5.brg + ./iburg$E -I sample4.brg sample4.c; $(CC) -o test4$E sample4.c; ./test4$E + ./iburg$E -I sample5.brg sample5.c; $(CC) -o test5$E sample5.c; ./test5$E + +clean:: + rm -f *$O core sample*.c a.out test4$E test5$E + +clobber:: clean + rm -f y.tab.c gram.tab.c iburg$E diff --git a/util/mcgg/sample4.brg b/util/mcgg/sample4.brg new file mode 100644 index 000000000..0b5c6116a --- /dev/null +++ b/util/mcgg/sample4.brg @@ -0,0 +1,109 @@ +%{ +#include +#include +#include +enum { + ADDI=309, ADDRLP=295, ASGNI=53, + CNSTI=21, CVCI=85, I0I=661, INDIRC=67 +}; + +#define STATE_TYPE long +typedef struct tree { + int op; + struct tree *kids[2]; + int val; + struct { STATE_TYPE state; } x; +} *NODEPTR_TYPE, *Tree; +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define PANIC printf +#define STATE_LABEL(p) ((p)->x.state) + +int OP_LABEL(NODEPTR_TYPE p) { + switch (p->op) { + case CNSTI: if (p->val == 0) return 661 /* I0I */; + default: return p->op; + } +} + +static void burm_trace(NODEPTR_TYPE, int, int, int); +%} +%term ADDI=309 ADDRLP=295 ASGNI=53 +%term CNSTI=21 CVCI=85 I0I=661 INDIRC=67 +%% +stmt: ASGNI(disp,reg) = 4 (1); +stmt: reg = 5; +reg: ADDI(reg,rc) = 6 (1); +reg: CVCI(INDIRC(disp)) = 7 (1); +reg: I0I = 8; +reg: disp = 9 (1); +disp: ADDI(reg,con) = 10; +disp: ADDRLP = 11; +rc: con = 12; +rc: reg = 13; +con: CNSTI = 14; +con: I0I = 15; +%% + +static int trace; + +/* burm_trace - print trace message for matching p; decrement trace */ +static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { + if (trace < 0) + fprintf(stderr, "0x%p matched %s = %d with cost %d vs. %d\n", p, + burm_string[eruleno], eruleno, cost, bestcost); + else if (trace > 0 && cost < bestcost) { + --trace; + fprintf(stderr, "0x%p matched %s = %d with cost %d\n", p, + burm_string[eruleno], eruleno, cost); + } +} + +/* dumpCover - print the matched cover for p */ +static void dumpCover(Tree p, int goalnt, int indent) { + int eruleno = burm_rule(p->x.state, goalnt); + short *nts = burm_nts[eruleno]; + Tree kids[10]; + int i; + + for (i = 0; i < indent; i++) + fprintf(stderr, " "); + fprintf(stderr, "%s\n", burm_string[eruleno]); + burm_kids(p, eruleno, kids); + for (i = 0; nts[i]; i++) + dumpCover(kids[i], nts[i], indent + 1); +} + +static void gen(NODEPTR_TYPE p) { + if (burm_label(p) == 0) + fprintf(stderr, "no cover\n"); + else + dumpCover(p, 1, 0); +} + +static Tree tree(int op, Tree l, Tree r) { + Tree t = malloc(sizeof *t); + + t->op = op; + t->kids[0] = l; t->kids[1] = r; + t->val = 0; + t->x.state = 0; + return t; +} + +main(void) { + Tree t; + + if (getenv("Trace")) + trace = atoi(getenv("Trace")); + printf("i = c + 4;\n"); + t = tree(ASGNI, + tree(ADDRLP, 0, 0), + tree(ADDI, + tree(CVCI, tree(INDIRC, tree(ADDRLP, 0, 0), 0), 0), + (t = tree(CNSTI, 0, 0), t->val = 4, t) + ) + ); + gen(t); + return 0; +} diff --git a/util/mcgg/sample5.brg b/util/mcgg/sample5.brg new file mode 100644 index 000000000..a830d03c9 --- /dev/null +++ b/util/mcgg/sample5.brg @@ -0,0 +1,85 @@ +%{ +#include +#include +#include + +#define TRACE + +enum { MOVE=1, MEM=2, PLUS=3, NAME=4, CONST=6 }; + +#define STATE_TYPE void* +typedef struct tree { + int op; + struct tree *kids[2]; + STATE_TYPE state_label; +} *NODEPTR_TYPE; +#define OP_LABEL(p) ((p)->op) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->state_label) +#define PANIC printf + +static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { +#ifdef TRACE + extern char *burm_string[]; + + fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p, + burm_string[eruleno], cost, bestcost); +#endif +} +%} +%term MOVE=1 MEM=2 PLUS=3 NAME=4 CONST=6 +%% +stm: MOVE(MEM(loc),reg) = 1 (4); + +reg: PLUS(con,reg) = 2 (3); +reg: PLUS(reg,reg) = 3 (2); +reg: PLUS(MEM(loc),reg) = 4 (4); +reg: MEM(loc) = 5 (4); +reg: con = 6 (2); + +loc: reg = 7; +loc: NAME = 8; +loc: PLUS(NAME,reg) = 9; + +con: CONST = 10; +%% +static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { +#ifdef TRACE + int eruleno = burm_rule(STATE_LABEL(p), goalnt); + short *nts = burm_nts[eruleno]; + NODEPTR_TYPE kids[10]; + int i; + + for (i = 0; i < indent; i++) + fprintf(stderr, " "); + fprintf(stderr, "%s\n", burm_string[eruleno]); + burm_kids(p, eruleno, kids); + for (i = 0; nts[i]; i++) + dumpCover(kids[i], nts[i], indent + 1); +#endif +} + +static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) { + NODEPTR_TYPE p = malloc(sizeof *p); + + assert(p); + p->op = op; + p->kids[0] = l; p->kids[1] = r; + return p; +} + +main(void) { + NODEPTR_TYPE p; + + p = tree(MOVE, + tree(MEM, tree(NAME, 0, 0), 0), + tree(PLUS, + tree(MEM, tree(PLUS, + tree(NAME, 0, 0), + tree(MEM, tree(NAME, 0, 0), 0)), 0), + tree(CONST, 0, 0) ) ); + burm_label(p); + dumpCover(p, 1, 0); + return 0; +} From 03b7202e54cb36654b474dff51c997efd80f8047 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 20 Sep 2016 20:46:45 +0200 Subject: [PATCH 009/230] Strip out surplus files. Rewrite README. --- util/mcgg/LOG | 39 ------ util/mcgg/README | 1 + util/mcgg/custom.mk | 0 util/mcgg/iburg.1 | 285 ------------------------------------------ util/mcgg/makefile | 23 ---- util/mcgg/sample4.brg | 109 ---------------- util/mcgg/sample5.brg | 85 ------------- 7 files changed, 1 insertion(+), 541 deletions(-) delete mode 100644 util/mcgg/LOG delete mode 100644 util/mcgg/custom.mk delete mode 100644 util/mcgg/iburg.1 delete mode 100644 util/mcgg/makefile delete mode 100644 util/mcgg/sample4.brg delete mode 100644 util/mcgg/sample5.brg diff --git a/util/mcgg/LOG b/util/mcgg/LOG deleted file mode 100644 index 3556af7cc..000000000 --- a/util/mcgg/LOG +++ /dev/null @@ -1,39 +0,0 @@ -Tue Aug 12 10:03:34 PDT 1997 - -makefile: -Customized for use under NT. - -gram.y: -Fixed diagnostic formatting, handled cases when \n doesn't terminate -the input buffer; protected against versions of fgets that touch -buffer at EOF. - -sample4.brg: -Changed state value from int to long for 64-bit machines. - - -Tue May 7 14:20:11 PDT 1996 - -The distribution now includes the RCS files. -Specific changes are as follows; thanks to Francisco Arzu -(farzu@uvg.edu.gt) for these suggestions. - -gram.y: -Changed TERM to TERMINAL for bison. -Moved definition of yylineno for bison. -Changed hard-coded 32767 to maxcost, and checked -only costs against maxcost. -Replaced 0s in calls with NULL. - -iburg.1: -Document STATE_TYPE, -maxcost=ddd, and use of SHRT_MAX. - -iburg.c: -Implemented STATE_TYPE, default int. -Changed 32767 to maxcost, which is SHRT_MAX, SHRT_MAX/2 -(when sizeof(int)==sizeof(short)), or maxcost. Included limits.h. - - -Thu May 12 11:33:48 EDT 1994 - -initial release. diff --git a/util/mcgg/README b/util/mcgg/README index 6cffcb058..21c982457 100644 --- a/util/mcgg/README +++ b/util/mcgg/README @@ -9,3 +9,4 @@ all the mcgg extensions). iburg is licensed under the MIT open source license; see the LICENSE file. + diff --git a/util/mcgg/custom.mk b/util/mcgg/custom.mk deleted file mode 100644 index e69de29bb..000000000 diff --git a/util/mcgg/iburg.1 b/util/mcgg/iburg.1 deleted file mode 100644 index 582143bdb..000000000 --- a/util/mcgg/iburg.1 +++ /dev/null @@ -1,285 +0,0 @@ -.TH IBURG 1 "local \- 1/26/93" -.\" $Id$ -.SH NAME -iburg \- code generator generator -.SH SYNOPSIS -.B iburg -[ -.I option -]... -[ [ -.I input -] -.I output -] -.br -.SH DESCRIPTION -.PP -.I iburg -reads BURG specification from -.I input -and writes a pattern-matching code generator to -.IR output . -If -.I input -is `\-' or is omitted, -.I iburg -reads the standard input; -If -.I output -is `\-' or is omitted, -.I iburg -writes to the standard output. -.PP -.I iburg -accepts BURG specifications that conform to the following EBNF grammar. -Terminals are enclosed in single quotes, all other symbols are nonterminals, -{X} denotes zero or more instances of X, and [X] denotes an optional X. -.PP -.nf -.RS -.ft CW -spec: { dcl } `%%' { rule } [ `%%' ] - -dcl: `%start' nonterm - `%term' { identifier `=' integer } - -rule: nonterm `:' tree `=' integer [ cost ] `;' - -cost: `(' integer ')' - -tree: term `(' tree `,' tree `)' - term `(' tree `)' - term - nonterm -.RE -.fi -.PP -Specifications are structurally similar to -.IR yacc 's. -Text between -`\f(CW%{\fP' -and -`\f(CW%}\fP' -is called the configuration section; there may be several such segments. -All are concatenated and copied verbatim into the head of the generated -parser, which is called burm. -Text after the second -`\f(CW%%\fP', -if any, is also copied verbatim into -.IR burm , -at the end. -.PP -Specifications consist of declarations, a -`\f(CW%%\fP' -separator, and rules. -Input is line-oriented; each declaration and rule must appear on a separate line, -and declarations must begin in column 1. -Declarations declare terminals \(em the operators in subject -trees \(em and associate a unique, positive external symbol -number with each one. -Non-terminals are declared by their presence -on the left side of rules. The -\f(CW%start\fP -declaration optionally declares a non-terminal as the start symbol. -In the grammar above, -\f(CWterm\fP -and -\f(CWnonterm\fP -denote identifiers that are terminals and non-terminals, respectively. -.PP -Rules define tree patterns in a fully parenthesized prefix -form. Every non-terminal denotes a tree. -Each operator has a fixed -arity, which is inferred from the rules in which it is used. -A chain rule is a rule whose pattern is another non-terminal. -If no start symbol is declared, the non-terminal defined by the first rule is used. -.PP -Each rule has a unique, positive external rule number, which -comes after the pattern and is preceded by a -`\f(CW=\fP'. -External rule numbers are used to report the -matching rule to a user-supplied semantic action routine. -Rules end with an optional non-negative, integer cost; omitted costs -default to zero. -.PP -The display below shows a fragment of a BURG specification. -This example uses upper-case for terminals and lower-case for non-terminals. -.PP -.nf -.ft CW -%{ -enum { ADDI=309, ADDRLP=295, ASGNI=53, - CNSTI=21, CVCI=85, I0I=661, INDIRC=67 }; - -typedef struct tree { - int op; - struct tree *kids[2]; - int val; - struct { int state; } x; -} *NODEPTR_TYPE, *Tree; -#define LEFT_CHILD(p) ((p)->kids[0]) -#define RIGHT_CHILD(p) ((p)->kids[1]) -#define PANIC printf -#define STATE_LABEL(p) ((p)->x.state) - -int OP_LABEL(NODEPTR_TYPE p) { - switch (p->op) { - case CNSTI: if (p->val == 0) return 661 /* I0I */; - default: return p->op; - } -} -%} -%term ADDI=309 ADDRLP=295 ASGNI=53 -%term CNSTI=21 CVCI=85 I0I=661 INDIRC=67 -%% -stmt: ASGNI(disp,reg) = 4 (1); -stmt: reg = 5; -reg: ADDI(reg,rc) = 6 (1); -reg: CVCI(INDIRC(disp)) = 7 (1); -reg: I0I = 8; -reg: disp = 9 (1); -disp: ADDI(reg,con) = 10; -disp: ADDRLP = 11; -rc: con = 12; -rc: reg = 13; -con: CNSTI = 14; -con: I0I = 15; -%% -.fi -.PP -The configuration section configures -\f(CWburm\fP -for the trees being parsed and the client's environment. -As shown, this section must define -\f(CWNODEPTR_TYPE\fP -to be a visible typedef symbol for a pointer to a -node in the subject tree. -\f(CWburm\fP -invokes -\f(CWOP_LABEL(p)\fP, -\f(CWLEFT\_CHILD(p)\fP, and -\f(CWRIGHT\_CHILD(p)\fP -to read the operator and children from the node pointed to by \f(CWp\fP. -It invokes -\f(CWPANIC\fP -when it detects an error. -If the configuration section defines these operations as macros, they are implemented in-line; -otherwise, they must be implemented as functions. -.PP -By default, -\f(CWburm\fP -computes and stores a single integral state in each node of the subject tree. -The configuration section must define a macro -\f(CWSTATE_LABEL(p)\fP -to access the state field of the node pointed to -by \f(CWp\fP. It must be large enough to hold a pointer, and -a macro is required because it is used as an lvalue. -The configuration section may define the macro -\f(CWSTATE_TYPE\fP -to specify a different type for state values; if -\f(CWSTATE_TYPE\fP -is not defined, int is used. -.PP -The configuration section may also define -\f(CWALLOC(n)\fP -for allocating -\f(CWn\fP -bytes. -If -\f(CWALLOC\fP -is not defined, -.IR malloc (3) -is used. -.SH OPTIONS -.TP -.BI \-p \ prefix -.br -.ns -.TP -.BI \-p prefix -Use -.I prefix -as the disambiquating prefix for exported names and visible fields. -The default is `\f(CWburm\fP'. -.TP -.BI \-maxcost= ddd -Use the integral value -.I ddd -as the maximum cost. -The default is \f(CWSHRT_MAX\fR -when ints are bigger than shorts, and -\f(CWSHRT_MAX\fP/2 when ints and shorts are the same size. -.TP -.B \-I -Emit code for the following data values and functions. -.sp -.nf -.ft CW - char burm_arity[]; - char *burm_opname[]; - char *burm_ntname[]; - char *burm_string[]; - short burm_cost[][4]; - int burm_op_label(NODEPTR_TYPE p); - NODEPTR_TYPE burm_child(NODEPTR_TYPE p, int index); - STATE_TYPE burm_state_label(NODEPTR_TYPE p); -.sp -.fi -.ft R -\f(CWburm_arity\fP and -\f(CWburm_opname\fP -are indexed by external symbol numbers and gives their arities. -\f(CWburm_ntname\fP -is indexed by a non-terminal number and gives its string name. -\f(CWburm_string\fP -and -\f(CWburm_cost\fP -are indexed by an external rule number and give the string -representation and cost of each rule. -The functions encapsulate the similarly named macros. -.TP -.B \-T -Arrange for -.sp -.nf -.ft CW - void burm_trace(NODEPTR_TYPE p, int eruleno, - int cost, int bestcost); -.sp -.fi -.ft R -to be called at each successful match. -\f(CWp\fP -identifies the node and -\f(CWeruleno\fP -identifies the matching rule; -\f(CWeruleno\fP -is an index into \f(CWburm_string\fP. -\f(CWcost\fP -is the cost of the match and -\f(CWbestcost\fP -is the cost of the best previous match. The current match -wins only if -\f(CWcost\fP -is less than \f(CWbestcost\fP. -SHRT_MAX represents the infinite cost of no previous match. -\f(CWburm_trace\fP must be declared in the configuration section. -.SH "SEE ALSO" -C. W. Fraser, R. R. Henry and T. A. Proebsting, -`BURG \(em Fast optimal instruction selection and tree parsing,' -.I -SIGPLAN Notices -.BR 27 , -4 (Apr. 1992), 68-76. -.PP -C. W. Fraser, D. R. Hanson and T. A. Proebsting, -`Engineering a simple, efficient code generator generator,' -.I -ACM Letters on Programming Languages and Systems -.BR 1 , -3 (Sep. 1992), 213-226. -.br -.SH BUGS -Mail bug reports along with the shortest input -that exposes them to drh@drhanson.net. diff --git a/util/mcgg/makefile b/util/mcgg/makefile deleted file mode 100644 index bff5d9ab2..000000000 --- a/util/mcgg/makefile +++ /dev/null @@ -1,23 +0,0 @@ -# $Id$ -O=.o -E= -CFLAGS= -LDFLAGS= -YFLAGS= -OBJS=iburg$O gram$O -CUSTOM=custom.mk -include $(CUSTOM) - -iburg$E: $(OBJS); $(CC) -o $@ $(LDFLAGS) $(OBJS) - -$(OBJS): iburg.h - -test: iburg$E sample4.brg sample5.brg - ./iburg$E -I sample4.brg sample4.c; $(CC) -o test4$E sample4.c; ./test4$E - ./iburg$E -I sample5.brg sample5.c; $(CC) -o test5$E sample5.c; ./test5$E - -clean:: - rm -f *$O core sample*.c a.out test4$E test5$E - -clobber:: clean - rm -f y.tab.c gram.tab.c iburg$E diff --git a/util/mcgg/sample4.brg b/util/mcgg/sample4.brg deleted file mode 100644 index 0b5c6116a..000000000 --- a/util/mcgg/sample4.brg +++ /dev/null @@ -1,109 +0,0 @@ -%{ -#include -#include -#include -enum { - ADDI=309, ADDRLP=295, ASGNI=53, - CNSTI=21, CVCI=85, I0I=661, INDIRC=67 -}; - -#define STATE_TYPE long -typedef struct tree { - int op; - struct tree *kids[2]; - int val; - struct { STATE_TYPE state; } x; -} *NODEPTR_TYPE, *Tree; -#define LEFT_CHILD(p) ((p)->kids[0]) -#define RIGHT_CHILD(p) ((p)->kids[1]) -#define PANIC printf -#define STATE_LABEL(p) ((p)->x.state) - -int OP_LABEL(NODEPTR_TYPE p) { - switch (p->op) { - case CNSTI: if (p->val == 0) return 661 /* I0I */; - default: return p->op; - } -} - -static void burm_trace(NODEPTR_TYPE, int, int, int); -%} -%term ADDI=309 ADDRLP=295 ASGNI=53 -%term CNSTI=21 CVCI=85 I0I=661 INDIRC=67 -%% -stmt: ASGNI(disp,reg) = 4 (1); -stmt: reg = 5; -reg: ADDI(reg,rc) = 6 (1); -reg: CVCI(INDIRC(disp)) = 7 (1); -reg: I0I = 8; -reg: disp = 9 (1); -disp: ADDI(reg,con) = 10; -disp: ADDRLP = 11; -rc: con = 12; -rc: reg = 13; -con: CNSTI = 14; -con: I0I = 15; -%% - -static int trace; - -/* burm_trace - print trace message for matching p; decrement trace */ -static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { - if (trace < 0) - fprintf(stderr, "0x%p matched %s = %d with cost %d vs. %d\n", p, - burm_string[eruleno], eruleno, cost, bestcost); - else if (trace > 0 && cost < bestcost) { - --trace; - fprintf(stderr, "0x%p matched %s = %d with cost %d\n", p, - burm_string[eruleno], eruleno, cost); - } -} - -/* dumpCover - print the matched cover for p */ -static void dumpCover(Tree p, int goalnt, int indent) { - int eruleno = burm_rule(p->x.state, goalnt); - short *nts = burm_nts[eruleno]; - Tree kids[10]; - int i; - - for (i = 0; i < indent; i++) - fprintf(stderr, " "); - fprintf(stderr, "%s\n", burm_string[eruleno]); - burm_kids(p, eruleno, kids); - for (i = 0; nts[i]; i++) - dumpCover(kids[i], nts[i], indent + 1); -} - -static void gen(NODEPTR_TYPE p) { - if (burm_label(p) == 0) - fprintf(stderr, "no cover\n"); - else - dumpCover(p, 1, 0); -} - -static Tree tree(int op, Tree l, Tree r) { - Tree t = malloc(sizeof *t); - - t->op = op; - t->kids[0] = l; t->kids[1] = r; - t->val = 0; - t->x.state = 0; - return t; -} - -main(void) { - Tree t; - - if (getenv("Trace")) - trace = atoi(getenv("Trace")); - printf("i = c + 4;\n"); - t = tree(ASGNI, - tree(ADDRLP, 0, 0), - tree(ADDI, - tree(CVCI, tree(INDIRC, tree(ADDRLP, 0, 0), 0), 0), - (t = tree(CNSTI, 0, 0), t->val = 4, t) - ) - ); - gen(t); - return 0; -} diff --git a/util/mcgg/sample5.brg b/util/mcgg/sample5.brg deleted file mode 100644 index a830d03c9..000000000 --- a/util/mcgg/sample5.brg +++ /dev/null @@ -1,85 +0,0 @@ -%{ -#include -#include -#include - -#define TRACE - -enum { MOVE=1, MEM=2, PLUS=3, NAME=4, CONST=6 }; - -#define STATE_TYPE void* -typedef struct tree { - int op; - struct tree *kids[2]; - STATE_TYPE state_label; -} *NODEPTR_TYPE; -#define OP_LABEL(p) ((p)->op) -#define LEFT_CHILD(p) ((p)->kids[0]) -#define RIGHT_CHILD(p) ((p)->kids[1]) -#define STATE_LABEL(p) ((p)->state_label) -#define PANIC printf - -static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { -#ifdef TRACE - extern char *burm_string[]; - - fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p, - burm_string[eruleno], cost, bestcost); -#endif -} -%} -%term MOVE=1 MEM=2 PLUS=3 NAME=4 CONST=6 -%% -stm: MOVE(MEM(loc),reg) = 1 (4); - -reg: PLUS(con,reg) = 2 (3); -reg: PLUS(reg,reg) = 3 (2); -reg: PLUS(MEM(loc),reg) = 4 (4); -reg: MEM(loc) = 5 (4); -reg: con = 6 (2); - -loc: reg = 7; -loc: NAME = 8; -loc: PLUS(NAME,reg) = 9; - -con: CONST = 10; -%% -static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { -#ifdef TRACE - int eruleno = burm_rule(STATE_LABEL(p), goalnt); - short *nts = burm_nts[eruleno]; - NODEPTR_TYPE kids[10]; - int i; - - for (i = 0; i < indent; i++) - fprintf(stderr, " "); - fprintf(stderr, "%s\n", burm_string[eruleno]); - burm_kids(p, eruleno, kids); - for (i = 0; nts[i]; i++) - dumpCover(kids[i], nts[i], indent + 1); -#endif -} - -static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) { - NODEPTR_TYPE p = malloc(sizeof *p); - - assert(p); - p->op = op; - p->kids[0] = l; p->kids[1] = r; - return p; -} - -main(void) { - NODEPTR_TYPE p; - - p = tree(MOVE, - tree(MEM, tree(NAME, 0, 0), 0), - tree(PLUS, - tree(MEM, tree(PLUS, - tree(NAME, 0, 0), - tree(MEM, tree(NAME, 0, 0), 0)), 0), - tree(CONST, 0, 0) ) ); - burm_label(p); - dumpCover(p, 1, 0); - return 0; -} From 2183c6c6229431356c310b395d2b58fe73dd5346 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 20 Sep 2016 21:00:16 +0200 Subject: [PATCH 010/230] Run through clang-format. --- util/mcgg/iburg.c | 543 ++++++++++++++++++++++++++++------------------ util/mcgg/iburg.h | 100 +++++---- 2 files changed, 383 insertions(+), 260 deletions(-) diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 18e80ad60..13c187d3b 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -11,7 +11,7 @@ static char rcsid[] = "$Id$"; int maxcost = SHRT_MAX; -static char *prefix = "burm"; +static char* prefix = "burm"; static int Iflag = 0, Tflag = 0; static int ntnumber = 0; static Nonterm start = 0; @@ -20,11 +20,11 @@ static Nonterm nts; static Rule rules; static int nrules; -static char *stringf(char *fmt, ...); -static void print(char *fmt, ...); +static char* stringf(char* fmt, ...); +static void print(char* fmt, ...); static void ckreach(Nonterm p); static void emitclosure(Nonterm nts); -static void emitcost(Tree t, char *v); +static void emitcost(Tree t, char* v); static void emitdefs(Nonterm nts, int ntnumber); static void emitfuncs(void); static void emitheader(void); @@ -32,20 +32,21 @@ static void emitkids(Rule rules, int nrules); static void emitlabel(Nonterm start); static void emitleaf(Term p, int ntnumber); static void emitnts(Rule rules, int nrules); -static void emitrecord(char *pre, Rule r, int cost); +static void emitrecord(char* pre, Rule r, int cost); static void emitrule(Nonterm nts); static void emitstate(Term terms, Nonterm start, int ntnumber); static void emitstring(Rule rules); static void emitstruct(Nonterm nts, int ntnumber); static void emitterms(Term terms); -static void emittest(Tree t, char *v, char *suffix); +static void emittest(Tree t, char* v, char* suffix); -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) +{ int c, i; Nonterm p; - - if (sizeof (short) == sizeof (int)) - maxcost = SHRT_MAX/2; + + if (sizeof(short) == sizeof(int)) + maxcost = SHRT_MAX / 2; for (i = 1; i < argc; i++) if (strcmp(argv[i], "-I") == 0) Iflag = 1; @@ -57,21 +58,28 @@ int main(int argc, char *argv[]) { prefix = &argv[i][2]; else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc) prefix = argv[++i]; - else if (*argv[i] == '-' && argv[i][1]) { + else if (*argv[i] == '-' && argv[i][1]) + { yyerror("usage: %s [-T | -I | -p prefix | -maxcost=ddd ]... [ [ input ] output \n", - argv[0]); + argv[0]); exit(1); - } else if (infp == NULL) { + } + else if (infp == NULL) + { if (strcmp(argv[i], "-") == 0) infp = stdin; - else if ((infp = fopen(argv[i], "r")) == NULL) { + else if ((infp = fopen(argv[i], "r")) == NULL) + { yyerror("%s: can't read `%s'\n", argv[0], argv[i]); exit(1); } - } else if (outfp == NULL) { + } + else if (outfp == NULL) + { if (strcmp(argv[i], "-") == 0) outfp = stdout; - if ((outfp = fopen(argv[i], "w")) == NULL) { + if ((outfp = fopen(argv[i], "w")) == NULL) + { yyerror("%s: can't write `%s'\n", argv[0], argv[i]); exit(1); } @@ -110,10 +118,12 @@ int main(int argc, char *argv[]) { } /* alloc - allocate nbytes or issue fatal error */ -void *alloc(int nbytes) { - void *p = calloc(1, nbytes); +void* alloc(int nbytes) +{ + void* p = calloc(1, nbytes); - if (p == NULL) { + if (p == NULL) + { yyerror("out of memory\n"); exit(1); } @@ -121,49 +131,55 @@ void *alloc(int nbytes) { } /* stringf - format and save a string */ -static char *stringf(char *fmt, ...) { +static char* stringf(char* fmt, ...) +{ va_list ap; - char *s, buf[512]; + char* s, buf[512]; va_start(ap, fmt); vsprintf(buf, fmt, ap); va_end(ap); return strcpy(alloc(strlen(buf) + 1), buf); -} +} -struct entry { - union { - char *name; +struct entry +{ + union + { + char* name; struct term t; struct nonterm nt; } sym; - struct entry *link; -} *table[211]; -#define HASHSIZE (sizeof table/sizeof table[0]) + struct entry* link; +} * table[211]; +#define HASHSIZE (sizeof table / sizeof table[0]) /* hash - return hash number for str */ -static unsigned hash(char *str) { +static unsigned hash(char* str) +{ unsigned h = 0; while (*str) - h = (h<<1) + *str++; + h = (h << 1) + *str++; return h; } /* lookup - lookup symbol name */ -static void *lookup(char *name) { - struct entry *p = table[hash(name)%HASHSIZE]; +static void* lookup(char* name) +{ + struct entry* p = table[hash(name) % HASHSIZE]; - for ( ; p; p = p->link) + for (; p; p = p->link) if (strcmp(name, p->sym.name) == 0) return &p->sym; return 0; } /* install - install symbol name */ -static void *install(char *name) { - struct entry *p = alloc(sizeof *p); - int i = hash(name)%HASHSIZE; +static void* install(char* name) +{ + struct entry* p = alloc(sizeof *p); + int i = hash(name) % HASHSIZE; p->sym.name = name; p->link = table[i]; @@ -172,8 +188,9 @@ static void *install(char *name) { } /* nonterm - create a new terminal id, if necessary */ -Nonterm nonterm(char *id) { - Nonterm p = lookup(id), *q = &nts; +Nonterm nonterm(char* id) +{ + Nonterm p = lookup(id), * q = &nts; if (p && p->kind == NONTERM) return p; @@ -193,8 +210,9 @@ Nonterm nonterm(char *id) { } /* term - create a new terminal id with external symbol number esn */ -Term term(char *id, int esn) { - Term p = lookup(id), *q = &terms; +Term term(char* id, int esn) +{ + Term p = lookup(id), * q = &terms; if (p) yyerror("redefinition of terminal `%s'\n", id); @@ -207,14 +225,15 @@ Term term(char *id, int esn) { q = &(*q)->link; if (*q && (*q)->esn == p->esn) yyerror("duplicate external symbol number `%s=%d'\n", - p->name, p->esn); + p->name, p->esn); p->link = *q; *q = p; return p; } /* tree - create & initialize a tree node with the given fields */ -Tree tree(char *id, Tree left, Tree right) { +Tree tree(char* id, Tree left, Tree right) +{ Tree t = alloc(sizeof *t); Term p = lookup(id); int arity = 0; @@ -223,12 +242,15 @@ Tree tree(char *id, Tree left, Tree right) { arity = 2; else if (left) arity = 1; - if (p == NULL && arity > 0) { + if (p == NULL && arity > 0) + { yyerror("undefined terminal `%s'\n", id); p = term(id, -1); - } else if (p == NULL && arity == 0) + } + else if (p == NULL && arity == 0) p = (Term)nonterm(id); - else if (p && p->kind == NONTERM && arity > 0) { + else if (p && p->kind == NONTERM && arity > 0) + { yyerror("`%s' is a non-terminal\n", id); p = term(id, -1); } @@ -246,7 +268,8 @@ Tree tree(char *id, Tree left, Tree right) { } /* rule - create & initialize a rule with the given fields */ -Rule rule(char *id, Tree pattern, int ern, int cost) { +Rule rule(char* id, Tree pattern, int ern, int cost) +{ Rule r = alloc(sizeof *r), *q; Term p = pattern->op; @@ -259,13 +282,16 @@ Rule rule(char *id, Tree pattern, int ern, int cost) { r->pattern = pattern; r->ern = ern; r->cost = cost; - if (p->kind == TERM) { + if (p->kind == TERM) + { r->next = p->rules; p->rules = r; - } else if (pattern->left == NULL && pattern->right == NULL) { + } + else if (pattern->left == NULL && pattern->right == NULL) + { Nonterm p = pattern->op; r->chain = p->chain; - p->chain = r; + p->chain = r; } for (q = &rules; *q && (*q)->ern < r->ern; q = &(*q)->link) ; @@ -277,38 +303,57 @@ Rule rule(char *id, Tree pattern, int ern, int cost) { } /* print - formatted output */ -static void print(char *fmt, ...) { +static void print(char* fmt, ...) +{ va_list ap; va_start(ap, fmt); - for ( ; *fmt; fmt++) + for (; *fmt; fmt++) if (*fmt == '%') - switch (*++fmt) { - case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break; - case 's': fputs(va_arg(ap, char *), outfp); break; - case 'P': fprintf(outfp, "%s_", prefix); break; - case 'T': { - Tree t = va_arg(ap, Tree); - print("%S", t->op); - if (t->left && t->right) - print("(%T,%T)", t->left, t->right); - else if (t->left) - print("(%T)", t->left); - break; + switch (*++fmt) + { + case 'd': + fprintf(outfp, "%d", va_arg(ap, int)); + break; + case 's': + fputs(va_arg(ap, char*), outfp); + break; + case 'P': + fprintf(outfp, "%s_", prefix); + break; + case 'T': + { + Tree t = va_arg(ap, Tree); + print("%S", t->op); + if (t->left && t->right) + print("(%T,%T)", t->left, t->right); + else if (t->left) + print("(%T)", t->left); + break; } - case 'R': { - Rule r = va_arg(ap, Rule); - print("%S: %T", r->lhs, r->pattern); - break; + case 'R': + { + Rule r = va_arg(ap, Rule); + print("%S: %T", r->lhs, r->pattern); + break; } - case 'S': fputs(va_arg(ap, Term)->name, outfp); break; - case '1': case '2': case '3': case '4': case '5': { - int n = *fmt - '0'; - while (n-- > 0) - putc('\t', outfp); - break; + case 'S': + fputs(va_arg(ap, Term)->name, outfp); + break; + case '1': + case '2': + case '3': + case '4': + case '5': + { + int n = *fmt - '0'; + while (n-- > 0) + putc('\t', outfp); + break; } - default: putc(*fmt, outfp); break; + default: + putc(*fmt, outfp); + break; } else putc(*fmt, outfp); @@ -316,7 +361,8 @@ static void print(char *fmt, ...) { } /* reach - mark all non-terminals in tree t as reachable */ -static void reach(Tree t) { +static void reach(Tree t) +{ Nonterm p = t->op; if (p->kind == NONTERM) @@ -329,57 +375,75 @@ static void reach(Tree t) { } /* ckreach - mark all non-terminals reachable from p */ -static void ckreach(Nonterm p) { +static void ckreach(Nonterm p) +{ Rule r; - p->reached = 1; + p->reached = 1; for (r = p->rules; r; r = r->decode) reach(r->pattern); } /* emitcase - emit one case in function state */ -static void emitcase(Term p, int ntnumber) { +static void emitcase(Term p, int ntnumber) +{ Rule r; print("%1case %d: /* %S */\n", p->esn, p); - switch (p->arity) { - case 0: case -1: - if (!Tflag) { - emitleaf(p, ntnumber); - return; - } - break; - case 1: print("%2assert(l);\n"); break; - case 2: print("%2assert(l && r);\n"); break; - default: assert(0); - } - for (r = p->rules; r; r = r->next) { - switch (p->arity) { - case 0: case -1: - print("%2{%1/* %R */\n%3c = ", r); + switch (p->arity) + { + case 0: + case -1: + if (!Tflag) + { + emitleaf(p, ntnumber); + return; + } break; case 1: - if (r->pattern->nterms > 1) { - print("%2if (%1/* %R */\n", r); - emittest(r->pattern->left, "l", " "); - print("%2) {\n%3c = "); - } else - print("%2{%1/* %R */\n%3c = ", r); - emitcost(r->pattern->left, "l"); + print("%2assert(l);\n"); break; case 2: - if (r->pattern->nterms > 1) { - print("%2if (%1/* %R */\n", r); - emittest(r->pattern->left, "l", - r->pattern->right->nterms ? " && " : " "); - emittest(r->pattern->right, "r", " "); - print("%2) {\n%3c = "); - } else - print("%2{%1/* %R */\n%3c = ", r); - emitcost(r->pattern->left, "l"); - emitcost(r->pattern->right, "r"); + print("%2assert(l && r);\n"); break; - default: assert(0); + default: + assert(0); + } + for (r = p->rules; r; r = r->next) + { + switch (p->arity) + { + case 0: + case -1: + print("%2{%1/* %R */\n%3c = ", r); + break; + case 1: + if (r->pattern->nterms > 1) + { + print("%2if (%1/* %R */\n", r); + emittest(r->pattern->left, "l", " "); + print("%2) {\n%3c = "); + } + else + print("%2{%1/* %R */\n%3c = ", r); + emitcost(r->pattern->left, "l"); + break; + case 2: + if (r->pattern->nterms > 1) + { + print("%2if (%1/* %R */\n", r); + emittest(r->pattern->left, "l", + r->pattern->right->nterms ? " && " : " "); + emittest(r->pattern->right, "r", " "); + print("%2) {\n%3c = "); + } + else + print("%2{%1/* %R */\n%3c = ", r); + emitcost(r->pattern->left, "l"); + emitcost(r->pattern->right, "r"); + break; + default: + assert(0); } print("%d;\n", r->cost); emitrecord("\t\t\t", r, 0); @@ -389,7 +453,8 @@ static void emitcase(Term p, int ntnumber) { } /* emitclosure - emit the closure functions */ -static void emitclosure(Nonterm nts) { +static void emitclosure(Nonterm nts) +{ Nonterm p; for (p = nts; p; p = p->link) @@ -397,7 +462,8 @@ static void emitclosure(Nonterm nts) { print("static void %Pclosure_%S(struct %Pstate *, int);\n", p); print("\n"); for (p = nts; p; p = p->link) - if (p->chain) { + if (p->chain) + { Rule r; print("static void %Pclosure_%S(struct %Pstate *p, int c) {\n", p); for (r = p->chain; r; r = r->chain) @@ -407,26 +473,31 @@ static void emitclosure(Nonterm nts) { } /* emitcost - emit cost computation for tree t */ -static void emitcost(Tree t, char *v) { +static void emitcost(Tree t, char* v) +{ Nonterm p = t->op; - if (p->kind == TERM) { + if (p->kind == TERM) + { if (t->left) - emitcost(t->left, stringf("%s->left", v)); + emitcost(t->left, stringf("%s->left", v)); if (t->right) emitcost(t->right, stringf("%s->right", v)); - } else + } + else print("%s->cost[%P%S_NT] + ", v, p); } /* emitdefs - emit non-terminal defines and data structures */ -static void emitdefs(Nonterm nts, int ntnumber) { +static void emitdefs(Nonterm nts, int ntnumber) +{ Nonterm p; for (p = nts; p; p = p->link) print("#define %P%S_NT %d\n", p, p->number); print("int %Pmax_nt = %d;\n\n", ntnumber); - if (Iflag) { + if (Iflag) + { print("char *%Pntname[] = {\n%10,\n"); for (p = nts; p; p = p->link) print("%1\"%S\",\n", p); @@ -435,38 +506,44 @@ static void emitdefs(Nonterm nts, int ntnumber) { } /* emitfuncs - emit functions to access node fields */ -static void emitfuncs(void) { +static void emitfuncs(void) +{ print("int %Pop_label(NODEPTR_TYPE p) {\n" -"%1%Passert(p, PANIC(\"NULL tree in %Pop_label\\n\"));\n" -"%1return OP_LABEL(p);\n}\n\n"); + "%1%Passert(p, PANIC(\"NULL tree in %Pop_label\\n\"));\n" + "%1return OP_LABEL(p);\n}\n\n"); print("STATE_TYPE %Pstate_label(NODEPTR_TYPE p) {\n" -"%1%Passert(p, PANIC(\"NULL tree in %Pstate_label\\n\"));\n" -"%1return STATE_LABEL(p);\n}\n\n"); + "%1%Passert(p, PANIC(\"NULL tree in %Pstate_label\\n\"));\n" + "%1return STATE_LABEL(p);\n}\n\n"); print("NODEPTR_TYPE %Pchild(NODEPTR_TYPE p, int index) {\n" -"%1%Passert(p, PANIC(\"NULL tree in %Pchild\\n\"));\n" -"%1switch (index) {\n%1case 0:%1return LEFT_CHILD(p);\n" -"%1case 1:%1return RIGHT_CHILD(p);\n%1}\n" -"%1%Passert(0, PANIC(\"Bad index %%d in %Pchild\\n\", index));\n%1return 0;\n}\n\n"); + "%1%Passert(p, PANIC(\"NULL tree in %Pchild\\n\"));\n" + "%1switch (index) {\n%1case 0:%1return LEFT_CHILD(p);\n" + "%1case 1:%1return RIGHT_CHILD(p);\n%1}\n" + "%1%Passert(0, PANIC(\"Bad index %%d in %Pchild\\n\", index));\n%1return 0;\n}\n\n"); } /* emitheader - emit initial definitions */ -static void emitheader(void) { +static void emitheader(void) +{ print("#include \n#include \n"); print("#ifndef STATE_TYPE\n#define STATE_TYPE int\n#endif\n"); print("#ifndef ALLOC\n#define ALLOC(n) malloc(n)\n#endif\n" -"#ifndef %Passert\n#define %Passert(x,y) if (!(x)) { y; abort(); }\n#endif\n\n"); + "#ifndef %Passert\n#define %Passert(x,y) if (!(x)) { y; abort(); }\n#endif\n\n"); if (Tflag) print("static NODEPTR_TYPE %Pnp;\n\n"); } /* computekids - compute paths to kids in tree t */ -static char *computekids(Tree t, char *v, char *bp, int *ip) { +static char* computekids(Tree t, char* v, char* bp, int* ip) +{ Term p = t->op; - if (p->kind == NONTERM) { + if (p->kind == NONTERM) + { sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v); bp += strlen(bp); - } else if (p->arity > 0) { + } + else if (p->arity > 0) + { bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip); if (p->arity == 2) bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip); @@ -475,14 +552,16 @@ static char *computekids(Tree t, char *v, char *bp, int *ip) { } /* emitkids - emit burm_kids */ -static void emitkids(Rule rules, int nrules) { +static void emitkids(Rule rules, int nrules) +{ int i; - Rule r, *rc = alloc((nrules + 1)*sizeof *rc); - char **str = alloc((nrules + 1)*sizeof *str); + Rule r, * rc = alloc((nrules + 1) * sizeof *rc); + char** str = alloc((nrules + 1) * sizeof *str); - for (i = 0, r = rules; r; r = r->link) { + for (i = 0, r = rules; r; r = r->link) + { int j = 0; - char buf[1024], *bp = buf; + char buf[1024], * bp = buf; *computekids(r->pattern, "p", bp, &j) = 0; for (j = 0; str[j] && strcmp(str[j], buf); j++) ; @@ -492,11 +571,12 @@ static void emitkids(Rule rules, int nrules) { rc[j] = r; } print("NODEPTR_TYPE *%Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n" -"%1%Passert(p, PANIC(\"NULL tree in %Pkids\\n\"));\n" -"%1%Passert(kids, PANIC(\"NULL kids in %Pkids\\n\"));\n" -"%1switch (eruleno) {\n"); - for (i = 0; r = rc[i]; i++) { - for ( ; r; r = r->kids) + "%1%Passert(p, PANIC(\"NULL tree in %Pkids\\n\"));\n" + "%1%Passert(kids, PANIC(\"NULL kids in %Pkids\\n\"));\n" + "%1switch (eruleno) {\n"); + for (i = 0; r = rc[i]; i++) + { + for (; r; r = r->kids) print("%1case %d: /* %R */\n", r->ern, r); print("%s%2break;\n", str[i]); } @@ -504,37 +584,41 @@ static void emitkids(Rule rules, int nrules) { } /* emitlabel - emit the labelling functions */ -static void emitlabel(Nonterm start) { +static void emitlabel(Nonterm start) +{ print("static void %Plabel1(NODEPTR_TYPE p) {\n" -"%1%Passert(p, PANIC(\"NULL tree in %Plabel\\n\"));\n" -"%1switch (%Parity[OP_LABEL(p)]) {\n" -"%1case 0:\n"); + "%1%Passert(p, PANIC(\"NULL tree in %Plabel\\n\"));\n" + "%1switch (%Parity[OP_LABEL(p)]) {\n" + "%1case 0:\n"); if (Tflag) print("%2%Pnp = p;\n"); print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p), 0, 0);\n%2break;\n" -"%1case 1:\n%2%Plabel1(LEFT_CHILD(p));\n"); + "%1case 1:\n%2%Plabel1(LEFT_CHILD(p));\n"); if (Tflag) print("%2%Pnp = p;\n"); print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p),\n" -"%3STATE_LABEL(LEFT_CHILD(p)), 0);\n%2break;\n" -"%1case 2:\n%2%Plabel1(LEFT_CHILD(p));\n%2%Plabel1(RIGHT_CHILD(p));\n"); + "%3STATE_LABEL(LEFT_CHILD(p)), 0);\n%2break;\n" + "%1case 2:\n%2%Plabel1(LEFT_CHILD(p));\n%2%Plabel1(RIGHT_CHILD(p));\n"); if (Tflag) print("%2%Pnp = p;\n"); print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p),\n" -"%3STATE_LABEL(LEFT_CHILD(p)),\n%3STATE_LABEL(RIGHT_CHILD(p)));\n%2break;\n" -"%1}\n}\n\n"); + "%3STATE_LABEL(LEFT_CHILD(p)),\n%3STATE_LABEL(RIGHT_CHILD(p)));\n%2break;\n" + "%1}\n}\n\n"); print( -"STATE_TYPE %Plabel(NODEPTR_TYPE p) {\n%1%Plabel1(p);\n" -"%1return ((struct %Pstate *)STATE_LABEL(p))->rule.%P%S ? STATE_LABEL(p) : 0;\n" -"}\n\n", start); + "STATE_TYPE %Plabel(NODEPTR_TYPE p) {\n%1%Plabel1(p);\n" + "%1return ((struct %Pstate *)STATE_LABEL(p))->rule.%P%S ? STATE_LABEL(p) : 0;\n" + "}\n\n", + start); } /* closure - fill in cost & rule with results of chain rules w/p as rhs */ -static void closure(int cost[], Rule rule[], Nonterm p, int c) { +static void closure(int cost[], Rule rule[], Nonterm p, int c) +{ Rule r; for (r = p->chain; r; r = r->chain) - if (c + r->cost < cost[r->lhs->number]) { + if (c + r->cost < cost[r->lhs->number]) + { cost[r->lhs->number] = c + r->cost; rule[r->lhs->number] = r; closure(cost, rule, r->lhs, c + r->cost); @@ -542,22 +626,26 @@ static void closure(int cost[], Rule rule[], Nonterm p, int c) { } /* emitleaf - emit state code for a leaf */ -static void emitleaf(Term p, int ntnumber) { +static void emitleaf(Term p, int ntnumber) +{ int i; Rule r; - static int *cost; - static Rule *rule; + static int* cost; + static Rule* rule; - if (cost == NULL) { - cost = alloc((ntnumber + 1)*sizeof *cost); - rule = alloc((ntnumber + 1)*sizeof *rule); + if (cost == NULL) + { + cost = alloc((ntnumber + 1) * sizeof *cost); + rule = alloc((ntnumber + 1) * sizeof *rule); } - for (i = 0; i <= ntnumber; i++) { + for (i = 0; i <= ntnumber; i++) + { cost[i] = maxcost; rule[i] = NULL; } for (r = p->rules; r; r = r->next) - if (r->pattern->left == NULL && r->pattern->right == NULL) { + if (r->pattern->left == NULL && r->pattern->right == NULL) + { cost[r->lhs->number] = r->cost; rule[r->lhs->number] = r; closure(cost, rule, r->lhs, r->cost); @@ -578,38 +666,46 @@ static void emitleaf(Term p, int ntnumber) { } /* computents - fill in bp with burm_nts vector for tree t */ -static char *computents(Tree t, char *bp) { - if (t) { +static char* computents(Tree t, char* bp) +{ + if (t) + { Nonterm p = t->op; - if (p->kind == NONTERM) { + if (p->kind == NONTERM) + { sprintf(bp, "%s_%s_NT, ", prefix, p->name); bp += strlen(bp); - } else - bp = computents(t->right, computents(t->left, bp)); + } + else + bp = computents(t->right, computents(t->left, bp)); } return bp; } /* emitnts - emit burm_nts ragged array */ -static void emitnts(Rule rules, int nrules) { +static void emitnts(Rule rules, int nrules) +{ Rule r; - int i, j, *nts = alloc(nrules*sizeof *nts); - char **str = alloc(nrules*sizeof *str); + int i, j, * nts = alloc(nrules * sizeof *nts); + char** str = alloc(nrules * sizeof *str); - for (i = 0, r = rules; r; r = r->link) { + for (i = 0, r = rules; r; r = r->link) + { char buf[1024]; *computents(r->pattern, buf) = 0; for (j = 0; str[j] && strcmp(str[j], buf); j++) ; - if (str[j] == NULL) { + if (str[j] == NULL) + { print("static short %Pnts_%d[] = { %s0 };\n", j, buf); str[j] = strcpy(alloc(strlen(buf) + 1), buf); } nts[i++] = j; } print("\nshort *%Pnts[] = {\n"); - for (i = j = 0, r = rules; r; r = r->link) { - for ( ; j < r->ern; j++) + for (i = j = 0, r = rules; r; r = r->link) + { + for (; j < r->ern; j++) print("%10,%1/* %d */\n", j); print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++); } @@ -617,25 +713,28 @@ static void emitnts(Rule rules, int nrules) { } /* emitrecord - emit code that tests for a winning match of rule r */ -static void emitrecord(char *pre, Rule r, int cost) { +static void emitrecord(char* pre, Rule r, int cost) +{ print("%sif (", pre); if (Tflag) print("%Ptrace(%Pnp, %d, c + %d, p->cost[%P%S_NT]), ", - r->ern, cost, r->lhs); + r->ern, cost, r->lhs); print("c + %d < p->cost[%P%S_NT]) {\n" -"%s%1p->cost[%P%S_NT] = c + %d;\n%s%1p->rule.%P%S = %d;\n", - cost, r->lhs, pre, r->lhs, cost, pre, r->lhs, - r->packed); + "%s%1p->cost[%P%S_NT] = c + %d;\n%s%1p->rule.%P%S = %d;\n", + cost, r->lhs, pre, r->lhs, cost, pre, r->lhs, + r->packed); if (r->lhs->chain) print("%s%1%Pclosure_%S(p, c + %d);\n", pre, r->lhs, cost); print("%s}\n", pre); } /* emitrule - emit decoding vectors and burm_rule */ -static void emitrule(Nonterm nts) { +static void emitrule(Nonterm nts) +{ Nonterm p; - for (p = nts; p; p = p->link) { + for (p = nts; p; p = p->link) + { Rule r; print("static short %Pdecode_%S[] = {\n%10,\n", p); for (r = p->rules; r; r = r->decode) @@ -643,51 +742,58 @@ static void emitrule(Nonterm nts) { print("};\n\n"); } print("int %Prule(STATE_TYPE state, int goalnt) {\n" -"%1%Passert(goalnt >= 1 && goalnt <= %d, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n" -"%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber); + "%1%Passert(goalnt >= 1 && goalnt <= %d, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n" + "%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", + ntnumber); for (p = nts; p; p = p->link) print("%1case %P%S_NT:" -"%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p); + "%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", + p, p, p); print("%1default:\n%2%Passert(0, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n%1}\n%1return 0;\n}\n\n"); } /* emitstate - emit state function */ -static void emitstate(Term terms, Nonterm start, int ntnumber) { +static void emitstate(Term terms, Nonterm start, int ntnumber) +{ int i; Term p; print("STATE_TYPE %Pstate(int op, STATE_TYPE left, STATE_TYPE right) {\n%1int c;\n" -"%1struct %Pstate *p, *l = (struct %Pstate *)left,\n" -"%2*r = (struct %Pstate *)right;\n\n%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1"); + "%1struct %Pstate *p, *l = (struct %Pstate *)left,\n" + "%2*r = (struct %Pstate *)right;\n\n%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1"); if (!Tflag) print("if (%Parity[op] > 0) "); print("{\n%2p = ALLOC(sizeof *p);\n" -"%2%Passert(p, PANIC(\"ALLOC returned NULL in %Pstate\\n\"));\n" -"%2p->op = op;\n%2p->left = l;\n%2p->right = r;\n%2p->rule.%P%S = 0;\n", start); + "%2%Passert(p, PANIC(\"ALLOC returned NULL in %Pstate\\n\"));\n" + "%2p->op = op;\n%2p->left = l;\n%2p->right = r;\n%2p->rule.%P%S = 0;\n", + start); for (i = 1; i <= ntnumber; i++) print("%2p->cost[%d] =\n", i); print("%3%d;\n%1}\n%1switch (op) {\n", maxcost); for (p = terms; p; p = p->link) emitcase(p, ntnumber); print("%1default:\n" -"%2%Passert(0, PANIC(\"Bad operator %%d in %Pstate\\n\", op));\n%1}\n" -"%1return (STATE_TYPE)p;\n}\n\n"); + "%2%Passert(0, PANIC(\"Bad operator %%d in %Pstate\\n\", op));\n%1}\n" + "%1return (STATE_TYPE)p;\n}\n\n"); } /* emitstring - emit array of rules and costs */ -static void emitstring(Rule rules) { +static void emitstring(Rule rules) +{ Rule r; int k; print("short %Pcost[][4] = {\n"); - for (k = 0, r = rules; r; r = r->link) { - for ( ; k < r->ern; k++) + for (k = 0, r = rules; r; r = r->link) + { + for (; k < r->ern; k++) print("%1{ 0 },%1/* %d */\n", k); print("%1{ %d },%1/* %d = %R */\n", r->cost, k++, r); } print("};\n\nchar *%Pstring[] = {\n"); - for (k = 0, r = rules; r; r = r->link) { - for ( ; k < r->ern; k++) + for (k = 0, r = rules; r; r = r->link) + { + for (; k < r->ern; k++) print("%1/* %d */%10,\n", k); print("%1/* %d */%1\"%R\",\n", k++, r); } @@ -695,34 +801,41 @@ static void emitstring(Rule rules) { } /* emitstruct - emit the definition of the state structure */ -static void emitstruct(Nonterm nts, int ntnumber) { +static void emitstruct(Nonterm nts, int ntnumber) +{ print("struct %Pstate {\n%1int op;\n%1struct %Pstate *left, *right;\n" -"%1short cost[%d];\n%1struct {\n", ntnumber + 1); - for ( ; nts; nts = nts->link) { + "%1short cost[%d];\n%1struct {\n", + ntnumber + 1); + for (; nts; nts = nts->link) + { int n = 1, m = nts->lhscount; while (m >>= 1) - n++; + n++; print("%2unsigned %P%S:%d;\n", nts, n); } print("%1} rule;\n};\n\n"); } /* emitterms - emit terminal data structures */ -static void emitterms(Term terms) { +static void emitterms(Term terms) +{ Term p; int k; print("char %Parity[] = {\n"); - for (k = 0, p = terms; p; p = p->link) { - for ( ; k < p->esn; k++) + for (k = 0, p = terms; p; p = p->link) + { + for (; k < p->esn; k++) print("%10,%1/* %d */\n", k); print("%1%d,%1/* %d=%S */\n", p->arity < 0 ? 0 : p->arity, k++, p); } print("};\n\n"); - if (Iflag) { + if (Iflag) + { print("char *%Popname[] = {\n"); - for (k = 0, p = terms; p; p = p->link) { - for ( ; k < p->esn; k++) + for (k = 0, p = terms; p; p = p->link) + { + for (; k < p->esn; k++) print("%1/* %d */%10,\n", k); print("%1/* %d */%1\"%S\",\n", k++, p); } @@ -731,15 +844,17 @@ static void emitterms(Term terms) { } /* emittest - emit clause for testing a match */ -static void emittest(Tree t, char *v, char *suffix) { +static void emittest(Tree t, char* v, char* suffix) +{ Term p = t->op; - if (p->kind == TERM) { + if (p->kind == TERM) + { print("%3%s->op == %d%s/* %S */\n", v, p->esn, - t->nterms > 1 ? " && " : suffix, p); + t->nterms > 1 ? " && " : suffix, p); if (t->left) - emittest(t->left, stringf("%s->left", v), - t->right && t->right->nterms ? " && " : suffix); + emittest(t->left, stringf("%s->left", v), + t->right && t->right->nterms ? " && " : suffix); if (t->right) emittest(t->right, stringf("%s->right", v), suffix); } diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index e55d5a8f9..cd3663dad 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -3,63 +3,71 @@ /* $Id$ */ /* iburg.c: */ -extern void *alloc(int nbytes); +extern void* alloc(int nbytes); -typedef enum { TERM=1, NONTERM } Kind; -typedef struct rule *Rule; -typedef struct term *Term; -struct term { /* terminals: */ - char *name; /* terminal name */ - Kind kind; /* TERM */ - int esn; /* external symbol number */ - int arity; /* operator arity */ - Term link; /* next terminal in esn order */ - Rule rules; /* rules whose pattern starts with term */ +typedef enum +{ + TERM = 1, + NONTERM +} Kind; +typedef struct rule* Rule; +typedef struct term* Term; +struct term +{ /* terminals: */ + char* name; /* terminal name */ + Kind kind; /* TERM */ + int esn; /* external symbol number */ + int arity; /* operator arity */ + Term link; /* next terminal in esn order */ + Rule rules; /* rules whose pattern starts with term */ }; -typedef struct nonterm *Nonterm; -struct nonterm { /* non-terminals: */ - char *name; /* non-terminal name */ - Kind kind; /* NONTERM */ - int number; /* identifying number */ - int lhscount; /* # times nt appears in a rule lhs */ - int reached; /* 1 iff reached from start non-terminal */ - Rule rules; /* rules w/non-terminal on lhs */ - Rule chain; /* chain rules w/non-terminal on rhs */ - Nonterm link; /* next terminal in number order */ +typedef struct nonterm* Nonterm; +struct nonterm +{ /* non-terminals: */ + char* name; /* non-terminal name */ + Kind kind; /* NONTERM */ + int number; /* identifying number */ + int lhscount; /* # times nt appears in a rule lhs */ + int reached; /* 1 iff reached from start non-terminal */ + Rule rules; /* rules w/non-terminal on lhs */ + Rule chain; /* chain rules w/non-terminal on rhs */ + Nonterm link; /* next terminal in number order */ }; -extern Nonterm nonterm(char *id); -extern Term term(char *id, int esn); +extern Nonterm nonterm(char* id); +extern Term term(char* id, int esn); -typedef struct tree *Tree; -struct tree { /* tree patterns: */ - void *op; /* a terminal or non-terminal */ - Tree left, right; /* operands */ - int nterms; /* number of terminal nodes in this tree */ +typedef struct tree* Tree; +struct tree +{ /* tree patterns: */ + void* op; /* a terminal or non-terminal */ + Tree left, right; /* operands */ + int nterms; /* number of terminal nodes in this tree */ }; -extern Tree tree(char *op, Tree left, Tree right); +extern Tree tree(char* op, Tree left, Tree right); -struct rule { /* rules: */ - Nonterm lhs; /* lefthand side non-terminal */ - Tree pattern; /* rule pattern */ - int ern; /* external rule number */ - int packed; /* packed external rule number */ - int cost; /* associated cost */ - Rule link; /* next rule in ern order */ - Rule next; /* next rule with same pattern root */ - Rule chain; /* next chain rule with same rhs */ - Rule decode; /* next rule with same lhs */ - Rule kids; /* next rule with same burm_kids pattern */ +struct rule +{ /* rules: */ + Nonterm lhs; /* lefthand side non-terminal */ + Tree pattern; /* rule pattern */ + int ern; /* external rule number */ + int packed; /* packed external rule number */ + int cost; /* associated cost */ + Rule link; /* next rule in ern order */ + Rule next; /* next rule with same pattern root */ + Rule chain; /* next chain rule with same rhs */ + Rule decode; /* next rule with same lhs */ + Rule kids; /* next rule with same burm_kids pattern */ }; -extern Rule rule(char *id, Tree pattern, int ern, int cost); -extern int maxcost; /* maximum cost */ +extern Rule rule(char* id, Tree pattern, int ern, int cost); +extern int maxcost; /* maximum cost */ /* gram.y: */ -void yyerror(char *fmt, ...); +void yyerror(char* fmt, ...); int yyparse(void); -void yywarn(char *fmt, ...); +void yywarn(char* fmt, ...); extern int errcnt; -extern FILE *infp; -extern FILE *outfp; +extern FILE* infp; +extern FILE* outfp; #endif From 4546dd5f2251524f3df717018a97973ce0e13199 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 21 Sep 2016 00:43:10 +0200 Subject: [PATCH 011/230] Massive grammar overhaul and refactor. Hacked in support for predicates, where instructions can be turned on and off based on their parameters. New lexer using a lexer. Now quite a lot of the way towards being a real instruction selector. --- mach/proto/mcg/build.lua | 1 + util/mcgg/build.lua | 25 ++++ util/mcgg/gram.y | 186 ++++++++++++------------------ util/mcgg/iburg.c | 165 ++++++++++++++++++-------- util/mcgg/iburg.h | 39 +++++-- util/mcgg/mcgg_generated_footer.h | 43 +++++++ util/mcgg/scan.l | 69 +++++++++++ 7 files changed, 360 insertions(+), 168 deletions(-) create mode 100644 util/mcgg/build.lua create mode 100644 util/mcgg/mcgg_generated_footer.h create mode 100644 util/mcgg/scan.l diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index c94d44ece..46394d510 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -27,6 +27,7 @@ cprogram { "modules/src/read_em+lib_kv", "modules/src/system+lib", "./*.h", + "util/mcgg+mcgg", }, vars = { ["+cflags"] = { diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua new file mode 100644 index 000000000..d0022baa9 --- /dev/null +++ b/util/mcgg/build.lua @@ -0,0 +1,25 @@ +include("first/yacc.lua") + +flex { + name = "flex", + srcs = { "./*.l" }, +} + +yacc { + name = "yacc", + srcs = { "./*.y" }, +} + +cprogram { + name = "mcgg", + srcs = { + "./*.c", + matching(filenamesof("+flex"), "%.c$"), + matching(filenamesof("+yacc"), "%.c$") + }, + deps = { + "./*.h", + "+yacc" + } +} + diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 965c9e9df..ea0abbc75 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -3,65 +3,105 @@ #include #include #include "iburg.h" + +#define YYDEBUG 1 + static char rcsid[] = "$Id$"; -static int yylineno = 0; +static int nextesn = 0; +static int nextern = 0; + %} %union { int n; - char *string; + char* string; Tree tree; + Stringlist stringlist; } %term TERMINAL %term START %term PPERCENT -%token ID -%token INT -%type lhs -%type tree -%type cost +%term PATTERNS +%term PAT +%term WHEN +%term EMIT +%term COST + +%token ID +%token CFRAGMENT +%token INT + +%type lhs +%type rhs +%type cost +%type when +%type stringlist %% -spec : decls PPERCENT rules { yylineno = 0; } - | decls { yylineno = 0; } +spec + : decls PPERCENT patterns + | decls ; decls : /* lambda */ | decls decl ; -decl : TERMINAL blist '\n' - | START lhs '\n' { - if (nonterm($2)->number != 1) - yyerror("redeclaration of the start symbol\n"); - } - | '\n' - | error '\n' { yyerrok; } +decl + : TERMINAL blist ';' + | START lhs ';' + { + if (nonterm($2)->number != 1) + yyerror("redeclaration of the start symbol\n"); + } + | ';' + | error ';' { yyerrok; } ; -blist : /* lambda */ - | blist ID '=' INT { term($2, $4); } +blist + : /* nothing */ + | blist ID { term($2, nextesn++); } + ; + +patterns + : /* nothing */ + | patterns pattern ';' + | patterns ';' + | patterns error ';' { yyerrok; } ; -rules : /* lambda */ - | rules lhs ':' tree '=' INT cost ';' '\n' { rule($2, $4, $6, $7); } - | rules '\n' - | rules error '\n' { yyerrok; } +pattern + : lhs '=' rhs when cost { rule($1, $3, nextern++, $4, $5); } + ; + +lhs + : ID { $$ = $1; nonterm($$); } ; -lhs : ID { nonterm($$ = $1); } +rhs + : ID { $$ = tree($1, NULL, NULL); } + | ID '(' rhs ')' { $$ = tree($1, $3, NULL); } + | ID '(' rhs ',' rhs ')' { $$ = tree($1, $3, $5); } ; -tree : ID { $$ = tree($1, NULL, NULL); } - | ID '(' tree ')' { $$ = tree($1, $3, NULL); } - | ID '(' tree ',' tree ')' { $$ = tree($1, $3, $5); } - ; +when + : /* nothing */ { $$ = NULL; } + | WHEN stringlist { $$ = $2; } + ; -cost : /* lambda */ { $$ = 0; } - | '(' INT ')' { if ($2 > maxcost) { - yyerror("%d exceeds maximum cost of %d\n", $2, maxcost); - $$ = maxcost; - } else - $$ = $2; } +stringlist + : /* nothing */ { $$ = NULL; } + | CFRAGMENT stringlist { $$ = pushstring($1, $2); } + ; + +cost + : /* lambda */ { $$ = 0; } + | COST INT { + if ($2 > maxcost) { + yyerror("%d exceeds maximum cost of %d\n", $2, maxcost); + $$ = maxcost; + } else + $$ = $2; + } ; %% #include @@ -73,32 +113,6 @@ FILE *outfp = NULL; static char buf[BUFSIZ], *bp = buf; static int ppercent = 0; -static int get(void) { - if (*bp == 0) { - bp = buf; - *bp = 0; - if (fgets(buf, sizeof buf, infp) == NULL) - return EOF; - yylineno++; - while (buf[0] == '%' && buf[1] == '{' && (buf[2] == '\n' || buf[2] == '\r')) { - for (;;) { - if (fgets(buf, sizeof buf, infp) == NULL) { - yywarn("unterminated %{...%}\n"); - return EOF; - } - yylineno++; - if (strcmp(buf, "%}\n") == 0 || strcmp(buf, "%}\r\n") == 0) - break; - fputs(buf, outfp); - } - if (fgets(buf, sizeof buf, infp) == NULL) - return EOF; - yylineno++; - } - } - return *bp++; -} - void yyerror(char *fmt, ...) { va_list ap; @@ -111,58 +125,6 @@ void yyerror(char *fmt, ...) { errcnt++; } -int yylex(void) { - int c; - - while ((c = get()) != EOF) { - switch (c) { - case ' ': case '\f': case '\t': case '\r': - continue; - case '\n': - case '(': case ')': case ',': - case ';': case '=': case ':': - return c; - } - if (c == '%' && *bp == '%') { - bp++; - return ppercent++ ? 0 : PPERCENT; - } else if (c == '%' && strncmp(bp, "term", 4) == 0 - && isspace(bp[4])) { - bp += 4; - return TERMINAL; - } else if (c == '%' && strncmp(bp, "start", 5) == 0 - && isspace(bp[5])) { - bp += 5; - return START; - } else if (isdigit(c)) { - int n = 0; - do { - int d = c - '0'; - if (n > (INT_MAX - d)/10) - yyerror("integer greater than %d\n", INT_MAX); - else - n = 10*n + d; - c = get(); - } while (c != EOF && isdigit(c)); - bp--; - yylval.n = n; - return INT; - } else if (isalpha(c)) { - char *p = bp - 1; - while (isalpha(*bp) || isdigit(*bp) || *bp == '_') - bp++; - yylval.string = alloc(bp - p + 1); - strncpy(yylval.string, p, bp - p); - yylval.string[bp - p] = 0; - return ID; - } else if (isprint(c)) - yyerror("invalid character `%c'\n", c); - else - yyerror("invalid character `\\%03o'\n", (unsigned char)c); - } - return 0; -} - void yywarn(char *fmt, ...) { va_list ap; @@ -172,3 +134,5 @@ void yywarn(char *fmt, ...) { fprintf(stderr, "warning: "); vfprintf(stderr, fmt, ap); } + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 13c187d3b..833d3e0d4 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -20,7 +20,6 @@ static Nonterm nts; static Rule rules; static int nrules; -static char* stringf(char* fmt, ...); static void print(char* fmt, ...); static void ckreach(Nonterm p); static void emitclosure(Nonterm nts); @@ -34,6 +33,8 @@ static void emitleaf(Term p, int ntnumber); static void emitnts(Rule rules, int nrules); static void emitrecord(char* pre, Rule r, int cost); static void emitrule(Nonterm nts); +static void emitpredicatedefinitions(Rule rules); +static void emitpredicatecall(Rule rule); static void emitstate(Term terms, Nonterm start, int ntnumber); static void emitstring(Rule rules); static void emitstruct(Nonterm nts, int ntnumber); @@ -45,6 +46,11 @@ int main(int argc, char* argv[]) int c, i; Nonterm p; + #if 0 + extern int yydebug; + yydebug = 1; + #endif + if (sizeof(short) == sizeof(int)) maxcost = SHRT_MAX / 2; for (i = 1; i < argc; i++) @@ -88,7 +94,10 @@ int main(int argc, char* argv[]) infp = stdin; if (outfp == NULL) outfp = stdout; + + yyin = infp; yyparse(); + if (start) ckreach(start); for (p = nts; p; p = p->link) @@ -103,6 +112,7 @@ int main(int argc, char* argv[]) emitstring(rules); emitrule(nts); emitclosure(nts); + emitpredicatedefinitions(rules); if (start) emitstate(terms, start, ntnumber); print("#ifdef STATE_LABEL\n"); @@ -111,35 +121,30 @@ int main(int argc, char* argv[]) emitkids(rules, nrules); emitfuncs(); print("#endif\n"); - if (!feof(infp)) - while ((c = getc(infp)) != EOF) - putc(c, outfp); + print("#include \"mcgg_generated_footer.h\"\n"); return errcnt > 0; } -/* alloc - allocate nbytes or issue fatal error */ -void* alloc(int nbytes) -{ - void* p = calloc(1, nbytes); - - if (p == NULL) - { - yyerror("out of memory\n"); - exit(1); - } - return p; -} - /* stringf - format and save a string */ -static char* stringf(char* fmt, ...) +char* stringf(char* fmt, ...) { - va_list ap; - char* s, buf[512]; + int n; + char* p; + va_list ap; - va_start(ap, fmt); - vsprintf(buf, fmt, ap); - va_end(ap); - return strcpy(alloc(strlen(buf) + 1), buf); + va_start(ap, fmt); + n = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + p = malloc(n); + if (!p) + return NULL; + + va_start(ap, fmt); + vsnprintf(p, n, fmt, ap); + va_end(ap); + + return p; } struct entry @@ -178,7 +183,7 @@ static void* lookup(char* name) /* install - install symbol name */ static void* install(char* name) { - struct entry* p = alloc(sizeof *p); + struct entry* p = calloc(1, sizeof *p); int i = hash(name) % HASHSIZE; p->sym.name = name; @@ -228,13 +233,16 @@ Term term(char* id, int esn) p->name, p->esn); p->link = *q; *q = p; + + if (esn != -1) + print("enum { %s = %d };\n", id, esn); return p; } /* tree - create & initialize a tree node with the given fields */ Tree tree(char* id, Tree left, Tree right) { - Tree t = alloc(sizeof *t); + Tree t = calloc(1, sizeof *t); Term p = lookup(id); int arity = 0; @@ -268,12 +276,17 @@ Tree tree(char* id, Tree left, Tree right) } /* rule - create & initialize a rule with the given fields */ -Rule rule(char* id, Tree pattern, int ern, int cost) +Rule rule(char* id, Tree pattern, int ern, Stringlist when, int cost) { - Rule r = alloc(sizeof *r), *q; + Rule r = calloc(1, sizeof *r); + Rule *q; Term p = pattern->op; + if (when && (p->arity == 0)) + yyerror("can't have a when clause on leaf nodes"); + nrules++; + r->when = when; r->lhs = nonterm(id); r->packed = ++r->lhs->lhscount; for (q = &r->lhs->rules; *q; q = &(*q)->decode) @@ -302,6 +315,14 @@ Rule rule(char* id, Tree pattern, int ern, int cost) return r; } +Stringlist pushstring(const char* data, Stringlist list) +{ + Stringlist sl = calloc(1, sizeof *sl); + sl->payload = data; + sl->next = list; + return sl; +} + /* print - formatted output */ static void print(char* fmt, ...) { @@ -360,6 +381,11 @@ static void print(char* fmt, ...) va_end(ap); } +void printlineno(void) +{ + print("#line %d\n", yylineno); +} + /* reach - mark all non-terminals in tree t as reachable */ static void reach(Tree t) { @@ -415,17 +441,26 @@ static void emitcase(Term p, int ntnumber) { case 0: case -1: - print("%2{%1/* %R */\n%3c = ", r); + print("%2if ("); + emitpredicatecall(r); + print(")\n%2{%1/* %R */\n%3c = ", r); break; case 1: if (r->pattern->nterms > 1) { print("%2if (%1/* %R */\n", r); emittest(r->pattern->left, "l", " "); + print("%3&& "); + emitpredicatecall(r); + print("\n"); print("%2) {\n%3c = "); } else - print("%2{%1/* %R */\n%3c = ", r); + { + print("%2if ("); + emitpredicatecall(r); + print(")\n%2{%1/* %R */\n%3c = ", r); + } emitcost(r->pattern->left, "l"); break; case 2: @@ -435,10 +470,17 @@ static void emitcase(Term p, int ntnumber) emittest(r->pattern->left, "l", r->pattern->right->nterms ? " && " : " "); emittest(r->pattern->right, "r", " "); + print("%3&& "); + emitpredicatecall(r); + print("\n"); print("%2) {\n%3c = "); } else - print("%2{%1/* %R */\n%3c = ", r); + { + print("%2if ("); + emitpredicatecall(r); + print(")\n%2{%1/* %R */\n%3c = ", r); + } emitcost(r->pattern->left, "l"); emitcost(r->pattern->right, "r"); break; @@ -555,8 +597,8 @@ static char* computekids(Tree t, char* v, char* bp, int* ip) static void emitkids(Rule rules, int nrules) { int i; - Rule r, * rc = alloc((nrules + 1) * sizeof *rc); - char** str = alloc((nrules + 1) * sizeof *str); + Rule r, * rc = calloc(nrules+1, sizeof *rc); + char** str = calloc(nrules+1, sizeof *str); for (i = 0, r = rules; r; r = r->link) { @@ -566,7 +608,7 @@ static void emitkids(Rule rules, int nrules) for (j = 0; str[j] && strcmp(str[j], buf); j++) ; if (str[j] == NULL) - str[j] = strcpy(alloc(strlen(buf) + 1), buf); + str[j] = strdup(buf); r->kids = rc[j]; rc[j] = r; } @@ -592,16 +634,16 @@ static void emitlabel(Nonterm start) "%1case 0:\n"); if (Tflag) print("%2%Pnp = p;\n"); - print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p), 0, 0);\n%2break;\n" + print("%2STATE_LABEL(p) = %Pstate(p, 0, 0);\n%2break;\n" "%1case 1:\n%2%Plabel1(LEFT_CHILD(p));\n"); if (Tflag) print("%2%Pnp = p;\n"); - print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p),\n" + print("%2STATE_LABEL(p) = %Pstate(p,\n" "%3STATE_LABEL(LEFT_CHILD(p)), 0);\n%2break;\n" "%1case 2:\n%2%Plabel1(LEFT_CHILD(p));\n%2%Plabel1(RIGHT_CHILD(p));\n"); if (Tflag) print("%2%Pnp = p;\n"); - print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p),\n" + print("%2STATE_LABEL(p) = %Pstate(p,\n" "%3STATE_LABEL(LEFT_CHILD(p)),\n%3STATE_LABEL(RIGHT_CHILD(p)));\n%2break;\n" "%1}\n}\n\n"); print( @@ -635,8 +677,8 @@ static void emitleaf(Term p, int ntnumber) if (cost == NULL) { - cost = alloc((ntnumber + 1) * sizeof *cost); - rule = alloc((ntnumber + 1) * sizeof *rule); + cost = calloc(ntnumber+1, sizeof *cost); + rule = calloc(ntnumber+1, sizeof *rule); } for (i = 0; i <= ntnumber; i++) { @@ -686,8 +728,8 @@ static char* computents(Tree t, char* bp) static void emitnts(Rule rules, int nrules) { Rule r; - int i, j, * nts = alloc(nrules * sizeof *nts); - char** str = alloc(nrules * sizeof *str); + int i, j, * nts = calloc(nrules, sizeof *nts); + char** str = calloc(nrules, sizeof *str); for (i = 0, r = rules; r; r = r->link) { @@ -698,7 +740,7 @@ static void emitnts(Rule rules, int nrules) if (str[j] == NULL) { print("static short %Pnts_%d[] = { %s0 };\n", j, buf); - str[j] = strcpy(alloc(strlen(buf) + 1), buf); + str[j] = strdup(buf); } nts[i++] = j; } @@ -752,15 +794,48 @@ static void emitrule(Nonterm nts) print("%1default:\n%2%Passert(0, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n%1}\n%1return 0;\n}\n\n"); } +/* emitpredicates - emit predicates for rules */ +static void emitpredicatedefinitions(Rule r) +{ + while (r) + { + Stringlist s = r->when; + if (s) + { + print("static int %Ppredicate_%d(NODEPTR_TYPE n) {\n", r->ern); + while (s) + { + print("%s", s->payload); + s = s->next; + } + print("\n}\n\n"); + } + r = r->link; + } +} + +/* emitpredicatecall - emit a call to a predicate */ +static void emitpredicatecall(Rule r) +{ + if (r->when) + print("%Ppredicate_%d(node)", r->ern); + else + print("1"); +} + /* emitstate - emit state function */ static void emitstate(Term terms, Nonterm start, int ntnumber) { int i; Term p; - print("STATE_TYPE %Pstate(int op, STATE_TYPE left, STATE_TYPE right) {\n%1int c;\n" - "%1struct %Pstate *p, *l = (struct %Pstate *)left,\n" - "%2*r = (struct %Pstate *)right;\n\n%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1"); + print("STATE_TYPE %Pstate(NODEPTR_TYPE node, STATE_TYPE left, STATE_TYPE right) {\n%1int c;\n" + "%1int op = OP_LABEL(node);\n" + "%1struct %Pstate* p;\n" + "%1struct %Pstate* l = (struct %Pstate *)left;\n" + "%1struct %Pstate* r = (struct %Pstate *)right;\n" + "\n" + "%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1"); if (!Tflag) print("if (%Parity[op] > 0) "); print("{\n%2p = ALLOC(sizeof *p);\n" diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index cd3663dad..6b5f9affc 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -3,7 +3,14 @@ /* $Id$ */ /* iburg.c: */ -extern void* alloc(int nbytes); +extern char* stringf(char* fmt, ...); + +typedef struct stringlist* Stringlist; +struct stringlist { + const char* payload; + Stringlist next; +}; +extern Stringlist pushstring(const char* data, Stringlist list); typedef enum { @@ -48,18 +55,19 @@ extern Tree tree(char* op, Tree left, Tree right); struct rule { /* rules: */ - Nonterm lhs; /* lefthand side non-terminal */ - Tree pattern; /* rule pattern */ - int ern; /* external rule number */ - int packed; /* packed external rule number */ - int cost; /* associated cost */ - Rule link; /* next rule in ern order */ - Rule next; /* next rule with same pattern root */ - Rule chain; /* next chain rule with same rhs */ - Rule decode; /* next rule with same lhs */ - Rule kids; /* next rule with same burm_kids pattern */ + Nonterm lhs; /* lefthand side non-terminal */ + Tree pattern; /* rule pattern */ + int ern; /* external rule number */ + int packed; /* packed external rule number */ + int cost; /* associated cost */ + Rule link; /* next rule in ern order */ + Rule next; /* next rule with same pattern root */ + Rule chain; /* next chain rule with same rhs */ + Rule decode; /* next rule with same lhs */ + Rule kids; /* next rule with same burm_kids pattern */ + Stringlist when; /* C predicate string */ }; -extern Rule rule(char* id, Tree pattern, int ern, int cost); +extern Rule rule(char* id, Tree pattern, int ern, Stringlist when, int cost); extern int maxcost; /* maximum cost */ /* gram.y: */ @@ -70,4 +78,11 @@ extern int errcnt; extern FILE* infp; extern FILE* outfp; +/* Stupid flex imports --- why mo header file? */ + +extern FILE* yyin; +extern int yylineno; + +extern void printlineno(void); + #endif diff --git a/util/mcgg/mcgg_generated_footer.h b/util/mcgg/mcgg_generated_footer.h new file mode 100644 index 000000000..7b9bbdb46 --- /dev/null +++ b/util/mcgg/mcgg_generated_footer.h @@ -0,0 +1,43 @@ +static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { +#ifdef TRACE + int eruleno = burm_rule(STATE_LABEL(p), goalnt); + short *nts = burm_nts[eruleno]; + NODEPTR_TYPE kids[10]; + int i; + + for (i = 0; i < indent; i++) + fprintf(stderr, " "); + fprintf(stderr, "%s\n", burm_string[eruleno]); + burm_kids(p, eruleno, kids); + for (i = 0; nts[i]; i++) + dumpCover(kids[i], nts[i], indent + 1); +#endif +} + +static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) { + NODEPTR_TYPE p = malloc(sizeof *p); + + assert(p); + p->op = op; + p->kids[0] = l; p->kids[1] = r; + return p; +} + +int main(void) { + NODEPTR_TYPE p; + + p = tree(STORE, + tree(LABEL, 0, 0), + tree(ADD, + tree(LOAD, + tree(LABEL, 0, 0), + 0 + ), + tree(CONST, 0, 0) + ) + ); + burm_label(p); + dumpCover(p, 1, 0); + return 0; +} + diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l new file mode 100644 index 000000000..3a067685b --- /dev/null +++ b/util/mcgg/scan.l @@ -0,0 +1,69 @@ +%{ +#include "iburg.h" +#include "y.tab.h" + +static int braces = 0; + +%} +%option warn +%option nodefault +%option noyywrap +%option yylineno + +%x CSTRING +%x ECHO + +%% + +"%{" { printlineno(); BEGIN(ECHO); } + +"%}" BEGIN(INITIAL); +[%\n] fputc(yytext[0], outfp); +[^%\n]* fputs(yytext, outfp); + +"{" { + yylval.string = stringf("#line %d\n", yylineno); + braces = 1; + BEGIN(CSTRING); + return CFRAGMENT; + } + +"{" { + braces++; + yylval.string = strdup(yytext); + return CFRAGMENT; + } + +"}" { + braces--; + if (braces == 0) + BEGIN(INITIAL); + else + { + yylval.string = strdup(yytext); + return CFRAGMENT; + } + } + +[^{}]+ { + yylval.string = strdup(yytext); + return CFRAGMENT; + } + +"%%" return PPERCENT; +"%term" return TERMINAL; +"%start" return START; + +"PATTERNS" return PATTERNS; +"pat" return PAT; +"when" return WHEN; +"emit" return EMIT; +"cost" return COST; + +[A-Za-z_][A-Za-z0-9_]* { yylval.string = strdup(yytext); return ID; } +[0-9]+ { yylval.n = atoi(yytext); return INT; } +[ \t\r\n]* ; +. return yytext[0]; + +%% +/* vim: set sw=4 ts=4 expandtab : */ From 6a74cb2e11af90cef447cbe4278f93276f5a67a5 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 22 Sep 2016 00:15:48 +0200 Subject: [PATCH 012/230] Tracing cleanup. Simplified the IR code. Some more opcodes. --- mach/proto/mcg/basicblock.c | 4 ++ mach/proto/mcg/build.lua | 3 +- mach/proto/mcg/compile.c | 41 ++++++++++++ mach/proto/mcg/ir.c | 57 ++++++++-------- mach/proto/mcg/ir.dat | 17 +++-- mach/proto/mcg/ir.h | 21 +++--- mach/proto/mcg/ircodes.sh | 34 ++++++++-- mach/proto/mcg/main.c | 24 +++++++ mach/proto/mcg/mcg.h | 8 ++- mach/proto/mcg/parse_em.c | 1 + mach/proto/mcg/treebuilder.c | 125 ++++++++++++++++++----------------- 11 files changed, 221 insertions(+), 114 deletions(-) create mode 100644 mach/proto/mcg/compile.c diff --git a/mach/proto/mcg/basicblock.c b/mach/proto/mcg/basicblock.c index 0ac2a5567..e44f553ee 100644 --- a/mach/proto/mcg/basicblock.c +++ b/mach/proto/mcg/basicblock.c @@ -39,4 +39,8 @@ void bb_alias(struct basicblock* block, const char* name) p->block = block; } +void bb_print(char k, struct basicblock* block) +{ +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index 46394d510..d1b2a3f49 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -24,7 +24,8 @@ cprogram { "modules/src/em_code+lib_k", "modules/src/em_data+lib", "modules/src/idf+lib", - "modules/src/read_em+lib_kv", + "modules/src/read_em+lib_ev", + "modules/src/string+lib", "modules/src/system+lib", "./*.h", "util/mcgg+mcgg", diff --git a/mach/proto/mcg/compile.c b/mach/proto/mcg/compile.c new file mode 100644 index 000000000..d8ae7e3ea --- /dev/null +++ b/mach/proto/mcg/compile.c @@ -0,0 +1,41 @@ +#include "mcg.h" + +static void print_blocks(char k, struct procedure* proc) +{ + int i; + + tracef(k, "%c: procedure %s\n", k, proc->name); + for (int i=0; iblocks_count; i++) + { + struct basicblock* bb = proc->blocks[i]; + int j; + + tracef(k, "%c: block %s\n", k, bb->name); + + for (int j=0; jinblocks_count; j++) + { + struct basicblock* obb = bb->inblocks[j]; + tracef(k, "%c: %s ->\n", k, obb->name); + } + + for (int j=0; jirs_count; j++) + ir_print(k, bb->irs[j]); + + for (int j=0; joutblocks_count; j++) + { + struct basicblock* obb = bb->outblocks[j]; + tracef(k, "%c: -> %s\n", k, obb->name); + } + + } +} + +void compile(struct procedure* proc) +{ + int i; + + print_blocks('1', proc); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index 814171586..34fed739a 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -35,18 +35,16 @@ struct ir* new_labelir(const char* label) return ir; } -struct ir* new_wordir(arith value) +struct ir* new_constir(int size, arith value) { - struct ir* ir = new_ir0(IR_ICONST, EM_wordsize); + struct ir* ir = new_ir0(IR_CONST, size); ir->u.ivalue = value; return ir; } -struct ir* new_regir(int reg) +struct ir* new_wordir(arith value) { - struct ir* ir = new_ir0(IR_REG, EM_pointersize); - ir->u.rvalue = reg; - return ir; + return new_constir(EM_wordsize, value); } struct ir* new_bbir(struct basicblock* bb) @@ -61,51 +59,50 @@ struct ir* new_anyir(int size) return new_ir0(IR_ANY, size); } -struct ir* new_phiir(int size) +struct ir* new_localir(int offset) { - return new_ir0(IR_PHI, size); + struct ir* ir = new_ir0(IR_LOCAL, EM_pointersize); + ir->u.ivalue = offset; + return ir; } -void ir_print(const struct ir* ir) +void ir_print(char k, const struct ir* ir) { - if (ir->left) - ir_print(ir->left); - if (ir->right) - ir_print(ir->right); + if (ir->left && !ir->left->is_sequence) + ir_print(k, ir->left); + if (ir->right && !ir->right->is_sequence) + ir_print(k, ir->right); - printf("\t; %c ", - ir->is_sequence ? 'S' : ' '); - printf("$%d = ", ir->id); - printf("%s%d(", - ir_names[ir->opcode], - ir->size); + tracef(k, "%c: %c ", k, ir->is_sequence ? 'S' : ' '); + tracef(k, "$%d = ", ir->id); + tracef(k, "%s", ir_names[ir->opcode]); + if (ir->size) + tracef(k, "%d", ir->size); + tracef(k, "("); switch (ir->opcode) { - case IR_ICONST: - printf("%d", ir->u.ivalue); + case IR_CONST: + case IR_LOCAL: + tracef(k, "%d", ir->u.ivalue); break; case IR_LABEL: - printf("%s", ir->u.lvalue); - break; - - case IR_REG: - printf("%d", ir->u.rvalue); + tracef(k, "%s", ir->u.lvalue); break; case IR_BLOCK: - printf("%s", ir->u.bvalue->name); + tracef(k, "%s", ir->u.bvalue->name); break; default: if (ir->left) - printf("$%d", ir->left->id); + tracef(k, "$%d", ir->left->id); if (ir->right) - printf(", $%d", ir->right->id); + tracef(k, ", $%d", ir->right->id); } - printf(")\n"); + tracef(k, ")\n"); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat index 4de21c007..033897384 100644 --- a/mach/proto/mcg/ir.dat +++ b/mach/proto/mcg/ir.dat @@ -1,11 +1,11 @@ # Simple terminals -ICONST +CONST REG LABEL BLOCK PAIR ANY -PHI +LOCAL # Magic stack operations PUSH @@ -22,11 +22,17 @@ MUL DIV MOD NEG -NOT + +ADDF +SUBF +MULF +DIVF +NEGF AND OR EOR +NOT # Conversions CII1 @@ -55,6 +61,7 @@ CJUMP RET # Special -SETREG -GETREG +STACKADJUST +GETRET +SETRET diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 6574ecb80..10e171bb2 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -1,8 +1,6 @@ #ifndef IR_H #define IR_H -#include "ircodes.h" - enum { IRR_LB = -1, @@ -11,6 +9,14 @@ enum IRR_RR = -4, }; +enum +{ + IRS_1, + IRS_2, + IRS_4, + IRS_8 +}; + struct ir { int id; @@ -23,9 +29,6 @@ struct ir int rvalue; const char* lvalue; struct basicblock* bvalue; - struct { - ARRAY(struct ir, srcs); - } phivalue; } u; bool is_sequence : 1; }; @@ -39,13 +42,15 @@ extern struct ir* new_ir2(int opcode, int size, struct ir* c1, struct ir* c2); extern struct ir* new_labelir(const char* label); -extern struct ir* new_regir(int reg); extern struct ir* new_wordir(arith value); +extern struct ir* new_constir(int size, arith value); extern struct ir* new_bbir(struct basicblock* bb); extern struct ir* new_anyir(int size); -extern struct ir* new_phiir(int size); +extern struct ir* new_localir(int offset); -extern void ir_print(const struct ir* ir); +extern void ir_print(char k, const struct ir* ir); + +#include "ircodes.h" #endif diff --git a/mach/proto/mcg/ircodes.sh b/mach/proto/mcg/ircodes.sh index 8f88b8bf4..f1219c50e 100755 --- a/mach/proto/mcg/ircodes.sh +++ b/mach/proto/mcg/ircodes.sh @@ -4,11 +4,33 @@ in=$1 header=$2 source=$3 -echo "enum {" > $header -sed -n 's/^[A-Z].*$/IR_&,/p' < $in >> $header -echo "};" >> $header +awk -f - $in >$header << "EOF" + BEGIN { + print "enum {" + } -echo "const char* ir_names[] = {" > $source -sed -n 's/^[A-Z].*$/"&",/p' < $in >> $source -echo "};" >> $source + /^[^#]+/ { + print "\tIR_" $1 "," + } + + END { + print "};" + } +EOF + +awk -f - $in >$source << "EOF" + BEGIN { + print "#include \"mcg.h\"" + print "#include \"ir.h\"" + print "const char* ir_names[] = {" + } + + /^[^#]+/ { + printf("\t\"%s\",\n", $1) + } + + END { + print "};" + } +EOF diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index a89b5a7d9..61f0bd52e 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -33,6 +33,30 @@ const char* aprintf(const char* fmt, ...) return p; } +bool tracing(char k) +{ + switch (k) + { + case 'E': return true; + case '0': return true; + case '1': return true; + case '2': return true; + default: return true; + } +} + +void tracef(char k, const char* fmt, ...) +{ + va_list ap; + + if (tracing(k)) + { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + } +} + int main(int argc, char* argv[]) { symbol_init(); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 997ae5340..5de8be0c2 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -77,17 +77,18 @@ struct basicblock { const char* name; ARRAY(struct insn, insns); + ARRAY(struct ir, allirs); ARRAY(struct ir, irs); ARRAY(struct basicblock, inblocks); ARRAY(struct basicblock, outblocks); - ARRAY(struct ir, outs); - ARRAY(struct ir, ins); bool is_root : 1; bool is_terminated : 1; }; extern void fatal(const char* s, ...); extern const char* aprintf(const char* fmt, ...); +extern void tracef(char k, const char* fmt, ...); +extern bool tracing(char k); extern void parse_em(void); @@ -105,12 +106,15 @@ extern void data_bss(arith size, int init); extern void bb_init(void); extern struct basicblock* bb_get(const char* name); extern void bb_alias(struct basicblock* block, const char* name); +extern void bb_print(char k, struct basicblock* block); extern void tb_filestart(void); extern void tb_fileend(void); extern void tb_procedure(struct procedure* proc); extern void tb_regvar(arith offset, int size, int type, int priority); +extern void compile(struct procedure* proc); + #endif /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index a1c9889f7..e6d39f9f5 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -289,6 +289,7 @@ static void parse_pseu(void) case ps_end: /* procedure end */ tb_procedure(current_proc); + compile(current_proc); current_proc = NULL; code_bb = NULL; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 5b014ec5e..82d7b14ec 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -6,7 +6,7 @@ static struct basicblock* current_bb; static int stackptr; static struct ir* stack[64]; -static struct ir* convert(struct ir* src, int destsize, int opcode); +static struct ir* convert(struct ir* src, int destsize, int opcodebase); static struct ir* appendir(struct ir* ir); static void reset_stack(void) @@ -37,8 +37,10 @@ static struct ir* pop(int size) if (size < EM_wordsize) size = EM_wordsize; return - new_ir0( - IR_POP, size + appendir( + new_ir0( + IR_POP, size + ) ); } else @@ -60,13 +62,25 @@ static void print_stack(void) { int i; - printf("\t; stack:"); + tracef('E', "E: stack:"); for (i=0; iid, ir->size); + tracef('E', " $%d.%d", ir->id, ir->size); } - printf(" (top)\n"); + tracef('E', " (top)\n"); +} + +static void appendallirs(struct ir* ir) +{ + if (CONTAINS(current_bb->allirs, ir)) + fatal("ir reachable from more than one place"); + + APPEND(current_bb->allirs, ir); + if (ir->left && !ir->left->is_sequence) + appendallirs(ir->left); + if (ir->right && !ir->right->is_sequence) + appendallirs(ir->right); } static struct ir* appendir(struct ir* ir) @@ -76,8 +90,9 @@ static struct ir* appendir(struct ir* ir) assert(current_bb != NULL); ir->is_sequence = true; APPEND(current_bb->irs, ir); + appendallirs(ir); - ir_print(ir); + ir_print('0', ir); return ir; } @@ -112,16 +127,6 @@ void tb_regvar(arith offset, int size, int type, int priority) /* ignored */ } -static struct ir* address_of_local(int index) -{ - return - new_ir2( - IR_ADD, EM_pointersize, - new_regir((index < 0) ? IRR_LB : IRR_AB), - new_wordir(index) - ); -} - static struct ir* address_of_external(const char* label, arith offset) { if (offset != 0) @@ -162,7 +167,7 @@ static struct ir* tristate_compare(int size, int opcode) return new_ir2( - opcode, size, + opcode, EM_wordsize, left, right ); } @@ -173,8 +178,8 @@ static void simple_convert(int opcode) struct ir* srcsize = pop(EM_wordsize); struct ir* value; - assert(srcsize->opcode == IR_ICONST); - assert(destsize->opcode == IR_ICONST); + assert(srcsize->opcode == IR_CONST); + assert(destsize->opcode == IR_CONST); value = pop(srcsize->u.ivalue); push( @@ -241,7 +246,7 @@ static void simple_branch2(int opcode, int size, new_ir2( IR_CJUMP, 0, new_ir2( - irop, size, + irop, size, left, right ), new_ir2( @@ -336,11 +341,17 @@ static void insn_ivalue(int opcode, arith value) case op_xor: simple_alu2(opcode, value, IR_EOR); break; case op_com: simple_alu1(opcode, value, IR_NOT); break; + case op_adf: simple_alu2(opcode, value, IR_ADDF); break; + case op_sbf: simple_alu2(opcode, value, IR_SUBF); break; + case op_mlf: simple_alu2(opcode, value, IR_MULF); break; + case op_dvf: simple_alu2(opcode, value, IR_DIVF); break; + case op_ngf: simple_alu1(opcode, value, IR_NEGF); break; + case op_lol: push( new_ir1( IR_LOAD, EM_wordsize, - address_of_local(value) + new_localir(value) ) ); break; @@ -349,7 +360,7 @@ static void insn_ivalue(int opcode, arith value) appendir( new_ir2( IR_STORE, EM_wordsize, - address_of_local(value), + new_localir(value), pop(EM_wordsize) ) ); @@ -357,7 +368,7 @@ static void insn_ivalue(int opcode, arith value) case op_lal: push( - address_of_local(value) + new_localir(value) ); break; @@ -476,17 +487,21 @@ static void insn_ivalue(int opcode, arith value) break; default: - appendir( - new_ir2( - IR_SETREG, EM_pointersize, - new_regir(IRR_SP), - new_ir2( - IR_ADD, EM_pointersize, - new_regir(IRR_SP), + while ((value > 0) && (stackptr > 0)) + { + struct ir* ir = pop(stack[stackptr-1]->size); + value -= ir->size; + } + + if (value != 0) + { + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, new_wordir(value) ) - ) - ); + ); + } break; } break; @@ -497,10 +512,10 @@ static void insn_ivalue(int opcode, arith value) if (value > 0) { struct ir* retval = pop(value); + materialise_stack(); appendir( - new_ir2( - IR_SETREG, value, - new_regir(IRR_RR), + new_ir1( + IR_SETRET, value, retval ) ); @@ -518,9 +533,8 @@ static void insn_ivalue(int opcode, arith value) { push( appendir( - new_ir1( - IR_GETREG, value, - new_regir(IRR_RR) + new_ir0( + IR_GETRET, value ) ) ); @@ -630,13 +644,7 @@ static void generate_tree(struct basicblock* bb) { int i; - printf("; BLOCK %s\n", bb->name); - if (bb->inblocks_count > 0) - { - printf("; Entered from:\n"); - for (i=0; iinblocks_count; i++) - printf("; %s\n", bb->inblocks[i]->name); - } + tracef('0', "0: block %s\n", bb->name); current_bb = bb; reset_stack(); @@ -644,30 +652,30 @@ static void generate_tree(struct basicblock* bb) for (i=0; iinsns_count; i++) { struct insn* insn = bb->insns[i]; - printf("\t; EM: %s ", em_mnem[insn->opcode - sp_fmnem]); + tracef('E', "E: read %s ", em_mnem[insn->opcode - sp_fmnem]); switch (insn->paramtype) { case PARAM_NONE: - printf("\n"); + tracef('E', "\n"); insn_simple(insn->opcode); break; case PARAM_IVALUE: - printf("value=%d\n", insn->u.ivalue); + tracef('E', "value=%d\n", insn->u.ivalue); insn_ivalue(insn->opcode, insn->u.ivalue); break; case PARAM_LVALUE: - printf("label=%s offset=%d\n", + tracef('E', "label=%s offset=%d\n", insn->u.lvalue.label, insn->u.lvalue.offset); insn_lvalue(insn->opcode, insn->u.lvalue.label, insn->u.lvalue.offset); break; case PARAM_BVALUE: - printf("true=%s", insn->u.bvalue.left->name); + tracef('E', "true=%s", insn->u.bvalue.left->name); if (insn->u.bvalue.right) - printf(" false=%s", insn->u.bvalue.right->name); - printf("\n"); + tracef('E', " false=%s", insn->u.bvalue.right->name); + tracef('E', "\n"); insn_bvalue(insn->opcode, insn->u.bvalue.left, insn->u.bvalue.right); break; @@ -675,18 +683,11 @@ static void generate_tree(struct basicblock* bb) assert(0); } - print_stack(); + if (tracing('E')) + print_stack(); } assert(stackptr == 0); - - if (bb->outblocks_count > 0) - { - printf("; Exiting to:\n"); - for (i=0; ioutblocks_count; i++) - printf("; %s\n", bb->outblocks[i]->name); - } - printf("\n"); } void tb_procedure(struct procedure* current_proc) From 9077baa85027f2b860a28894021251ad7a617e03 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 22 Sep 2016 23:19:29 +0200 Subject: [PATCH 013/230] Add a bodged in algorithm for converting basic block communication from stacked variables to SSA. Also add dead block removal and block splicing. IR code is much better now. --- mach/proto/mcg/array.c | 19 +++++++ mach/proto/mcg/array.h | 4 ++ mach/proto/mcg/compile.c | 95 +++++++++++++++++++++++++++++++--- mach/proto/mcg/ir.c | 65 +++++++++++++++++++---- mach/proto/mcg/ir.dat | 6 ++- mach/proto/mcg/ir.h | 9 +++- mach/proto/mcg/main.c | 4 +- mach/proto/mcg/mcg.h | 5 +- mach/proto/mcg/parse_em.c | 27 ++++++---- mach/proto/mcg/sse.c | 99 ++++++++++++++++++++++++++++++++++++ mach/proto/mcg/treebuilder.c | 13 ----- 11 files changed, 299 insertions(+), 47 deletions(-) create mode 100644 mach/proto/mcg/sse.c diff --git a/mach/proto/mcg/array.c b/mach/proto/mcg/array.c index 1b72352b0..a375bafb5 100644 --- a/mach/proto/mcg/array.c +++ b/mach/proto/mcg/array.c @@ -35,5 +35,24 @@ void array_appendu(void*** array, int* count, int* max, void* value) array_append(array, count, max, value); } +void array_remove(void** array, int* count, void* value) +{ + int i; + + for (i=0; i<*count; i++) + { + if (array[i] == value) + { + while (i < (*count-1)) + { + array[i] = array[i+1]; + i++; + } + (*count)--; + return; + } + } +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/array.h b/mach/proto/mcg/array.h index 4d9badb29..d2f56123a 100644 --- a/mach/proto/mcg/array.h +++ b/mach/proto/mcg/array.h @@ -15,9 +15,13 @@ #define APPENDU(ARRAY, VALUE) \ array_appendu((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE) +#define REMOVE(ARRAY, VALUE) \ + array_remove((void**) ARRAY, &ARRAY##_count, VALUE) + extern void array_append(void*** array, int* count, int* max, void* value); extern bool array_contains(void** array, int count, void* value); extern void array_appendu(void*** array, int* count, int* max, void* value); +extern void array_remove(void** array, int* count, void* value); #endif diff --git a/mach/proto/mcg/compile.c b/mach/proto/mcg/compile.c index d8ae7e3ea..8d147a61a 100644 --- a/mach/proto/mcg/compile.c +++ b/mach/proto/mcg/compile.c @@ -10,31 +10,110 @@ static void print_blocks(char k, struct procedure* proc) struct basicblock* bb = proc->blocks[i]; int j; - tracef(k, "%c: block %s\n", k, bb->name); + tracef(k, "%c:\n", k); + tracef(k, "%c: BLOCK: %s\n", k, bb->name); + tracef(k, "%c: from:", k); for (int j=0; jinblocks_count; j++) { struct basicblock* obb = bb->inblocks[j]; - tracef(k, "%c: %s ->\n", k, obb->name); + tracef(k, " %s", obb->name); } + tracef(k, "\n"); + tracef(k, "%c: to:", k); + for (int j=0; joutblocks_count; j++) + { + struct basicblock* obb = bb->outblocks[j]; + tracef(k, " %s", obb->name); + } + tracef(k, "\n"); for (int j=0; jirs_count; j++) ir_print(k, bb->irs[j]); - for (int j=0; joutblocks_count; j++) - { - struct basicblock* obb = bb->outblocks[j]; - tracef(k, "%c: -> %s\n", k, obb->name); - } - } } +static void remove_dead_blocks(struct procedure* proc) +{ + int i, j; + +again: + /* Starts at 1 because we don't want to remove the root block! */ + for (i=1; iblocks_count; i++) + { + struct basicblock* bb = proc->blocks[i]; + + if (bb->inblocks_count == 0) + { + /* Nobody uses this block; disconnect it from its output + * blocks. */ + for (j=0; joutblocks_count; j++) + REMOVE(bb->outblocks[j]->inblocks, bb); + + REMOVE(proc->blocks, bb); + goto again; + } + } +} + +static void splice_adjacent_blocks(struct procedure* proc) +{ + int i, j; + +again: + for (i=0; iblocks_count; i++) + { + struct basicblock* bb = proc->blocks[i]; + if (bb->outblocks_count == 1) + { + struct basicblock* outbb = bb->outblocks[0]; + if (outbb->inblocks_count == 1) + { + struct ir* lastir = bb->irs[bb->irs_count-1]; + + if ((lastir->opcode == IR_JUMP) + && (lastir->left->opcode == IR_BLOCK) + && (lastir->left->u.bvalue == outbb)) + { + /* Remove jump instruction. */ + + bb->irs_count--; + + REMOVE(bb->outblocks, outbb); + REMOVE(outbb->inblocks, bb); + + for (j=0; jirs_count; j++) + APPEND(bb->irs, outbb->irs[j]); + for (j=0; joutblocks_count; j++) + { + APPENDU(bb->outblocks, outbb->outblocks[j]); + APPENDU(outbb->outblocks[j]->inblocks, bb); + REMOVE(outbb->outblocks[j]->inblocks, outbb); + } + + REMOVE(proc->blocks, outbb); + goto again; + } + } + } + } +} + void compile(struct procedure* proc) { int i; print_blocks('1', proc); + + remove_dead_blocks(proc); + + for (i=0; iblocks_count; i++) + sse_convert_block_parameters(proc->blocks[i]); + + splice_adjacent_blocks(proc); + + print_blocks('2', proc); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index 34fed739a..c707a6bbc 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -66,15 +66,30 @@ struct ir* new_localir(int offset) return ir; } -void ir_print(char k, const struct ir* ir) +struct ir* ir_find(struct ir* ir, int opcode) { - if (ir->left && !ir->left->is_sequence) - ir_print(k, ir->left); - if (ir->right && !ir->right->is_sequence) - ir_print(k, ir->right); + if (ir->opcode == opcode) + return ir; - tracef(k, "%c: %c ", k, ir->is_sequence ? 'S' : ' '); - tracef(k, "$%d = ", ir->id); + if (ir->left && !ir->left->is_sequence) + { + struct ir* irr = ir_find(ir->left, opcode); + if (irr) + return irr; + } + + if (ir->right && !ir->right->is_sequence) + { + struct ir* irr = ir_find(ir->right, opcode); + if (irr) + return irr; + } + + return NULL; +} + +static void print_expr(char k, const struct ir* ir) +{ tracef(k, "%s", ir_names[ir->opcode]); if (ir->size) tracef(k, "%d", ir->size); @@ -95,14 +110,44 @@ void ir_print(char k, const struct ir* ir) tracef(k, "%s", ir->u.bvalue->name); break; + case IR_PHI: + { + int i; + + for (i=0; iu.phivalue.imports_count; i++) + { + if (i > 0) + tracef(k, ", "); + tracef(k, "$%d", ir->u.phivalue.imports[i]->id); + } + } + default: if (ir->left) - tracef(k, "$%d", ir->left->id); + { + if (ir->left->is_sequence) + tracef(k, "$%d", ir->left->id); + else + print_expr(k, ir->left); + } if (ir->right) - tracef(k, ", $%d", ir->right->id); + { + tracef(k, ", "); + if (ir->right->is_sequence) + tracef(k, "$%d", ir->right->id); + else + print_expr(k, ir->right); + } } - tracef(k, ")\n"); + tracef(k, ")"); +} + +void ir_print(char k, const struct ir* ir) +{ + tracef(k, "%c: $%d = ", k, ir->id); + print_expr(k, ir); + tracef(k, "\n"); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat index 033897384..36787525c 100644 --- a/mach/proto/mcg/ir.dat +++ b/mach/proto/mcg/ir.dat @@ -6,10 +6,12 @@ BLOCK PAIR ANY LOCAL +PHI # Magic stack operations PUSH POP +SET # Memory operations LOAD @@ -54,8 +56,10 @@ IFEQ IFLT IFLE -# Flow control +# Procedures CALL + +# Flow control --- these never return JUMP CJUMP RET diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 10e171bb2..0e8e2c422 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -24,11 +24,16 @@ struct ir int size; struct ir* left; struct ir* right; - union { + union + { arith ivalue; int rvalue; const char* lvalue; struct basicblock* bvalue; + struct + { + ARRAY(struct ir, imports); + } phivalue; } u; bool is_sequence : 1; }; @@ -48,6 +53,8 @@ extern struct ir* new_bbir(struct basicblock* bb); extern struct ir* new_anyir(int size); extern struct ir* new_localir(int offset); +extern struct ir* ir_find(struct ir* ir, int opcode); + extern void ir_print(char k, const struct ir* ir); #include "ircodes.h" diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 61f0bd52e..d6cc586ec 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -37,8 +37,8 @@ bool tracing(char k) { switch (k) { - case 'E': return true; - case '0': return true; + case 'E': return false; + case '0': return false; case '1': return true; case '2': return true; default: return true; diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 5de8be0c2..bcc6ff4b6 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -77,10 +77,11 @@ struct basicblock { const char* name; ARRAY(struct insn, insns); - ARRAY(struct ir, allirs); ARRAY(struct ir, irs); ARRAY(struct basicblock, inblocks); ARRAY(struct basicblock, outblocks); + ARRAY(struct ir, inparams); + ARRAY(struct ir, outparams); bool is_root : 1; bool is_terminated : 1; }; @@ -113,6 +114,8 @@ extern void tb_fileend(void); extern void tb_procedure(struct procedure* proc); extern void tb_regvar(arith offset, int size, int type, int priority); +extern void sse_convert_block_parameters(struct basicblock* bb); + extern void compile(struct procedure* proc); #endif diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index e6d39f9f5..162e53915 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -98,6 +98,7 @@ static void queue_insn_value(int opcode, arith value) { case op_csa: case op_csb: + case op_ret: terminate_block(); break; } @@ -138,6 +139,16 @@ static void queue_insn_block(int opcode, struct basicblock* left, struct basicbl terminate_block(); } +static void change_basicblock(struct basicblock* newbb) +{ + APPENDU(current_proc->blocks, newbb); + + if (code_bb && !code_bb->is_terminated) + queue_insn_block(op_bra, newbb, NULL); + + code_bb = newbb; +} + static void queue_insn_ilabel(int opcode, int label) { const char* name = ilabel_to_str(insn.em_ilb); @@ -155,8 +166,12 @@ static void queue_insn_ilabel(int opcode, int label) case op_zle: case op_zgt: case op_zge: - queue_insn_block(insn.em_opcode, left, bb_get(NULL)); + { + struct basicblock* bb = bb_get(NULL); + queue_insn_block(insn.em_opcode, left, bb); + change_basicblock(bb); break; + } default: fatal("parse_em: unhandled conditional '%s'", @@ -164,16 +179,6 @@ static void queue_insn_ilabel(int opcode, int label) } } -static void change_basicblock(struct basicblock* newbb) -{ - APPENDU(current_proc->blocks, newbb); - - if (code_bb && !code_bb->is_terminated) - queue_insn_block(op_bra, newbb, NULL); - - code_bb = newbb; -} - static void queue_ilabel(arith label) { change_basicblock(bb_get(ilabel_to_str(label))); diff --git a/mach/proto/mcg/sse.c b/mach/proto/mcg/sse.c new file mode 100644 index 000000000..3c57a3f8b --- /dev/null +++ b/mach/proto/mcg/sse.c @@ -0,0 +1,99 @@ +#include "mcg.h" + +static struct ir* get_last_push(struct basicblock* bb) +{ + int i; + + for (i=bb->irs_count-1; i>=0; i--) + { + struct ir* ir = bb->irs[i]; + + if (ir->opcode == IR_PUSH) + return ir; + if (ir_find(ir, IR_POP)) + return NULL; + } + + return NULL; +} + +static struct ir* get_first_pop(struct basicblock* bb) +{ + int i; + + for (i=0; iirs_count; i++) + { + struct ir* irr; + struct ir* ir = bb->irs[i]; + + if (ir->opcode == IR_PUSH) + return NULL; + + irr = ir_find(ir, IR_POP); + if (irr) + return irr; + } + + return NULL; +} + +void sse_convert_block_parameters(struct basicblock* bb) +{ + int i, j; + struct ir* ir; + + for (;;) + { + struct ir* lastpush = get_last_push(bb); + if (!lastpush) + return; + + /* Abort unless *every* success block of this one starts with a pop + * of the same size... */ + + for (i=0; ioutblocks_count; i++) + { + struct basicblock* outbb = bb->outblocks[i]; + + ir = get_first_pop(outbb); + if (!ir || (ir->size != lastpush->size)) + return; + + /* Also abort unless *every* predecessor block of the one we've + * just found *also* ends in a push of the same size. */ + + for (j=0; jinblocks_count; j++) + { + struct basicblock* inbb = outbb->inblocks[i]; + + ir = get_last_push(inbb); + if (!ir || (ir->size != lastpush->size)) + return; + } + } + + /* Okay, now we can wire them all up. */ + + for (i=0; ioutblocks_count; i++) + { + struct basicblock* outbb = bb->outblocks[i]; + struct ir* phi = get_first_pop(outbb); + phi->opcode = IR_PHI; + + /* Also abort unless *every* predecessor block of the one we've + * just found *also* ends in a push of the same size. */ + + for (j=0; jinblocks_count; j++) + { + struct basicblock* inbb = outbb->inblocks[j]; + + ir = get_last_push(inbb); + *ir = *ir->left; + ir->is_sequence = true; + APPEND(phi->u.phivalue.imports, ir); + } + } + } +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 82d7b14ec..3928dc727 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -71,18 +71,6 @@ static void print_stack(void) tracef('E', " (top)\n"); } -static void appendallirs(struct ir* ir) -{ - if (CONTAINS(current_bb->allirs, ir)) - fatal("ir reachable from more than one place"); - - APPEND(current_bb->allirs, ir); - if (ir->left && !ir->left->is_sequence) - appendallirs(ir->left); - if (ir->right && !ir->right->is_sequence) - appendallirs(ir->right); -} - static struct ir* appendir(struct ir* ir) { int i; @@ -90,7 +78,6 @@ static struct ir* appendir(struct ir* ir) assert(current_bb != NULL); ir->is_sequence = true; APPEND(current_bb->irs, ir); - appendallirs(ir); ir_print('0', ir); return ir; From f8bbf9e87d37dbfac29705679381446c08d7dce1 Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 23 Sep 2016 21:07:16 +0200 Subject: [PATCH 014/230] Each pass now lives in its own source file; much cleaner. --- mach/proto/mcg/compile.c | 75 +------------------ mach/proto/mcg/mcg.h | 4 +- .../mcg/{sse.c => pass_convertstackops.c} | 10 ++- mach/proto/mcg/pass_deadblocks.c | 27 +++++++ mach/proto/mcg/pass_spliceadjacentblocks.c | 47 ++++++++++++ 5 files changed, 89 insertions(+), 74 deletions(-) rename mach/proto/mcg/{sse.c => pass_convertstackops.c} (92%) create mode 100644 mach/proto/mcg/pass_deadblocks.c create mode 100644 mach/proto/mcg/pass_spliceadjacentblocks.c diff --git a/mach/proto/mcg/compile.c b/mach/proto/mcg/compile.c index 8d147a61a..e9fb86be2 100644 --- a/mach/proto/mcg/compile.c +++ b/mach/proto/mcg/compile.c @@ -34,84 +34,15 @@ static void print_blocks(char k, struct procedure* proc) } } -static void remove_dead_blocks(struct procedure* proc) -{ - int i, j; - -again: - /* Starts at 1 because we don't want to remove the root block! */ - for (i=1; iblocks_count; i++) - { - struct basicblock* bb = proc->blocks[i]; - - if (bb->inblocks_count == 0) - { - /* Nobody uses this block; disconnect it from its output - * blocks. */ - for (j=0; joutblocks_count; j++) - REMOVE(bb->outblocks[j]->inblocks, bb); - - REMOVE(proc->blocks, bb); - goto again; - } - } -} - -static void splice_adjacent_blocks(struct procedure* proc) -{ - int i, j; - -again: - for (i=0; iblocks_count; i++) - { - struct basicblock* bb = proc->blocks[i]; - if (bb->outblocks_count == 1) - { - struct basicblock* outbb = bb->outblocks[0]; - if (outbb->inblocks_count == 1) - { - struct ir* lastir = bb->irs[bb->irs_count-1]; - - if ((lastir->opcode == IR_JUMP) - && (lastir->left->opcode == IR_BLOCK) - && (lastir->left->u.bvalue == outbb)) - { - /* Remove jump instruction. */ - - bb->irs_count--; - - REMOVE(bb->outblocks, outbb); - REMOVE(outbb->inblocks, bb); - - for (j=0; jirs_count; j++) - APPEND(bb->irs, outbb->irs[j]); - for (j=0; joutblocks_count; j++) - { - APPENDU(bb->outblocks, outbb->outblocks[j]); - APPENDU(outbb->outblocks[j]->inblocks, bb); - REMOVE(outbb->outblocks[j]->inblocks, outbb); - } - - REMOVE(proc->blocks, outbb); - goto again; - } - } - } - } -} - void compile(struct procedure* proc) { int i; print_blocks('1', proc); - remove_dead_blocks(proc); - - for (i=0; iblocks_count; i++) - sse_convert_block_parameters(proc->blocks[i]); - - splice_adjacent_blocks(proc); + pass_remove_dead_blocks(proc); + pass_convert_stack_ops(proc); + pass_splice_adjacent_blocks(proc); print_blocks('2', proc); } diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index bcc6ff4b6..1f66ef249 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -114,7 +114,9 @@ extern void tb_fileend(void); extern void tb_procedure(struct procedure* proc); extern void tb_regvar(arith offset, int size, int type, int priority); -extern void sse_convert_block_parameters(struct basicblock* bb); +extern void pass_convert_stack_ops(struct procedure* proc); +extern void pass_remove_dead_blocks(struct procedure* proc); +extern void pass_splice_adjacent_blocks(struct procedure* proc); extern void compile(struct procedure* proc); diff --git a/mach/proto/mcg/sse.c b/mach/proto/mcg/pass_convertstackops.c similarity index 92% rename from mach/proto/mcg/sse.c rename to mach/proto/mcg/pass_convertstackops.c index 3c57a3f8b..6ee90bda9 100644 --- a/mach/proto/mcg/sse.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -37,7 +37,7 @@ static struct ir* get_first_pop(struct basicblock* bb) return NULL; } -void sse_convert_block_parameters(struct basicblock* bb) +static void convert_block(struct basicblock* bb) { int i, j; struct ir* ir; @@ -96,4 +96,12 @@ void sse_convert_block_parameters(struct basicblock* bb) } } +void pass_convert_stack_ops(struct procedure* proc) +{ + int i; + + for (i=0; iblocks_count; i++) + convert_block(proc->blocks[i]); +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_deadblocks.c b/mach/proto/mcg/pass_deadblocks.c new file mode 100644 index 000000000..94c8735cc --- /dev/null +++ b/mach/proto/mcg/pass_deadblocks.c @@ -0,0 +1,27 @@ +#include "mcg.h" + +void pass_remove_dead_blocks(struct procedure* proc) +{ + int i, j; + +again: + /* Starts at 1 because we don't want to remove the root block! */ + for (i=1; iblocks_count; i++) + { + struct basicblock* bb = proc->blocks[i]; + + if (bb->inblocks_count == 0) + { + /* Nobody uses this block; disconnect it from its output + * blocks. */ + for (j=0; joutblocks_count; j++) + REMOVE(bb->outblocks[j]->inblocks, bb); + + REMOVE(proc->blocks, bb); + goto again; + } + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/pass_spliceadjacentblocks.c b/mach/proto/mcg/pass_spliceadjacentblocks.c new file mode 100644 index 000000000..7f6a69b98 --- /dev/null +++ b/mach/proto/mcg/pass_spliceadjacentblocks.c @@ -0,0 +1,47 @@ +#include "mcg.h" + +void pass_splice_adjacent_blocks(struct procedure* proc) +{ + int i, j; + +again: + for (i=0; iblocks_count; i++) + { + struct basicblock* bb = proc->blocks[i]; + if (bb->outblocks_count == 1) + { + struct basicblock* outbb = bb->outblocks[0]; + if (outbb->inblocks_count == 1) + { + struct ir* lastir = bb->irs[bb->irs_count-1]; + + if ((lastir->opcode == IR_JUMP) + && (lastir->left->opcode == IR_BLOCK) + && (lastir->left->u.bvalue == outbb)) + { + /* Remove jump instruction. */ + + bb->irs_count--; + + REMOVE(bb->outblocks, outbb); + REMOVE(outbb->inblocks, bb); + + for (j=0; jirs_count; j++) + APPEND(bb->irs, outbb->irs[j]); + for (j=0; joutblocks_count; j++) + { + APPENDU(bb->outblocks, outbb->outblocks[j]); + APPENDU(outbb->outblocks[j]->inblocks, bb); + REMOVE(outbb->outblocks[j]->inblocks, outbb); + } + + REMOVE(proc->blocks, outbb); + goto again; + } + } + } + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + From ed67d427c9cceaa8c77d9fbc838651d8fee3aa59 Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 23 Sep 2016 23:59:15 +0200 Subject: [PATCH 015/230] Replaced the block splicer with a trivial block eliminator (which rewrites jumps to blocks which contain only a jump). Don't bother storing the bb graph in the ir nodes; we can find it on demand by walking the tree instead --- slower, but much easier to understand and more robust. Added a terrible map library. --- mach/proto/mcg/array.h | 5 + mach/proto/mcg/compile.c | 18 +--- mach/proto/mcg/ir.c | 33 +++---- mach/proto/mcg/ir.h | 12 +-- mach/proto/mcg/ircodes.sh | 2 +- mach/proto/mcg/main.c | 2 +- mach/proto/mcg/map.c | 58 ++++++++++++ mach/proto/mcg/map.h | 26 ++++++ mach/proto/mcg/mcg.h | 8 +- mach/proto/mcg/parse_em.c | 16 ++-- mach/proto/mcg/pass_convertstackops.c | 98 ++++++++++++++------ mach/proto/mcg/pass_deadblocks.c | 27 ------ mach/proto/mcg/pass_eliminatetrivialblocks.c | 41 ++++++++ mach/proto/mcg/pass_removedeadblocks.c | 40 ++++++++ mach/proto/mcg/pass_spliceadjacentblocks.c | 47 ---------- mach/proto/mcg/treebuilder.c | 14 +-- 16 files changed, 276 insertions(+), 171 deletions(-) create mode 100644 mach/proto/mcg/map.c create mode 100644 mach/proto/mcg/map.h delete mode 100644 mach/proto/mcg/pass_deadblocks.c create mode 100644 mach/proto/mcg/pass_eliminatetrivialblocks.c create mode 100644 mach/proto/mcg/pass_removedeadblocks.c delete mode 100644 mach/proto/mcg/pass_spliceadjacentblocks.c diff --git a/mach/proto/mcg/array.h b/mach/proto/mcg/array.h index d2f56123a..b3c9a03e5 100644 --- a/mach/proto/mcg/array.h +++ b/mach/proto/mcg/array.h @@ -6,6 +6,11 @@ int NAME##_count; \ int NAME##_max +#define STATICARRAY(TYPE, NAME) \ + static TYPE** NAME; \ + static int NAME##_count; \ + static int NAME##_max + #define APPEND(ARRAY, VALUE) \ array_append((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE) diff --git a/mach/proto/mcg/compile.c b/mach/proto/mcg/compile.c index e9fb86be2..c6fea43d6 100644 --- a/mach/proto/mcg/compile.c +++ b/mach/proto/mcg/compile.c @@ -13,24 +13,8 @@ static void print_blocks(char k, struct procedure* proc) tracef(k, "%c:\n", k); tracef(k, "%c: BLOCK: %s\n", k, bb->name); - tracef(k, "%c: from:", k); - for (int j=0; jinblocks_count; j++) - { - struct basicblock* obb = bb->inblocks[j]; - tracef(k, " %s", obb->name); - } - tracef(k, "\n"); - tracef(k, "%c: to:", k); - for (int j=0; joutblocks_count; j++) - { - struct basicblock* obb = bb->outblocks[j]; - tracef(k, " %s", obb->name); - } - tracef(k, "\n"); - for (int j=0; jirs_count; j++) ir_print(k, bb->irs[j]); - } } @@ -40,9 +24,9 @@ void compile(struct procedure* proc) print_blocks('1', proc); + pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); pass_convert_stack_ops(proc); - pass_splice_adjacent_blocks(proc); print_blocks('2', proc); } diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index c707a6bbc..f0c495f7e 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -66,21 +66,21 @@ struct ir* new_localir(int offset) return ir; } -struct ir* ir_find(struct ir* ir, int opcode) +struct ir* ir_walk(struct ir* ir, ir_walker_t* cb, void* user) { - if (ir->opcode == opcode) + if (cb(ir, user)) return ir; if (ir->left && !ir->left->is_sequence) { - struct ir* irr = ir_find(ir->left, opcode); + struct ir* irr = ir_walk(ir->left, cb, user); if (irr) return irr; } if (ir->right && !ir->right->is_sequence) { - struct ir* irr = ir_find(ir->right, opcode); + struct ir* irr = ir_walk(ir->right, cb, user); if (irr) return irr; } @@ -88,6 +88,19 @@ struct ir* ir_find(struct ir* ir, int opcode) return NULL; } +static bool finder_cb(struct ir* ir, void* user) +{ + int opcode = *(int*)user; + if (ir->opcode == opcode) + return true; + return false; +} + +struct ir* ir_find(struct ir* ir, int opcode) +{ + return ir_walk(ir, finder_cb, &opcode); +} + static void print_expr(char k, const struct ir* ir) { tracef(k, "%s", ir_names[ir->opcode]); @@ -110,18 +123,6 @@ static void print_expr(char k, const struct ir* ir) tracef(k, "%s", ir->u.bvalue->name); break; - case IR_PHI: - { - int i; - - for (i=0; iu.phivalue.imports_count; i++) - { - if (i > 0) - tracef(k, ", "); - tracef(k, "$%d", ir->u.phivalue.imports[i]->id); - } - } - default: if (ir->left) { diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 0e8e2c422..795b6dd6d 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -1,6 +1,8 @@ #ifndef IR_H #define IR_H +#include "ircodes.h" + enum { IRR_LB = -1, @@ -20,7 +22,7 @@ enum struct ir { int id; - int opcode; + enum ir_opcode opcode; int size; struct ir* left; struct ir* right; @@ -30,10 +32,6 @@ struct ir int rvalue; const char* lvalue; struct basicblock* bvalue; - struct - { - ARRAY(struct ir, imports); - } phivalue; } u; bool is_sequence : 1; }; @@ -53,11 +51,11 @@ extern struct ir* new_bbir(struct basicblock* bb); extern struct ir* new_anyir(int size); extern struct ir* new_localir(int offset); +typedef bool ir_walker_t(struct ir* node, void* user); +extern struct ir* ir_walk(struct ir* ir, ir_walker_t* callback, void* user); extern struct ir* ir_find(struct ir* ir, int opcode); extern void ir_print(char k, const struct ir* ir); -#include "ircodes.h" - #endif diff --git a/mach/proto/mcg/ircodes.sh b/mach/proto/mcg/ircodes.sh index f1219c50e..3fdf1982d 100755 --- a/mach/proto/mcg/ircodes.sh +++ b/mach/proto/mcg/ircodes.sh @@ -6,7 +6,7 @@ source=$3 awk -f - $in >$header << "EOF" BEGIN { - print "enum {" + print "enum ir_opcode {" } /^[^#]+/ { diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index d6cc586ec..6c9a28006 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -39,7 +39,7 @@ bool tracing(char k) { case 'E': return false; case '0': return false; - case '1': return true; + case '1': return false; case '2': return true; default: return true; } diff --git a/mach/proto/mcg/map.c b/mach/proto/mcg/map.c new file mode 100644 index 000000000..228cf8bcc --- /dev/null +++ b/mach/proto/mcg/map.c @@ -0,0 +1,58 @@ +#include "mcg.h" + +static void extend(struct map_node** map, int* count, int* max) +{ + if (*count == *max) + { + int newmax = (*max == 0) ? 8 : (*max * 2); + struct map_node* newmap = realloc(*map, newmax * sizeof(struct map_node)); + if (!newmap) + fatal("memory allocation failure"); + + *max = newmax; + *map = newmap; + } +} + +void map_set(struct map_node** map, int* count, int* max, void* left, void* right) +{ + int i; + struct map_node* node; + + for (i=0; i<*count; i++) + { + node = &(*map)[i]; + if (node->left == left) + { + node->right = right; + return; + } + } + + extend(map, count, max); + node = &(*map)[*count]; + node->left = left; + node->right = right; + (*count)++; +} + +void map_add(struct map_node** map, int* count, int* max, void* left, void* right) +{ + int i; + struct map_node* node; + + for (i=0; i<*count; i++) + { + node = &(*map)[i]; + if ((node->left == left) && (node->right == right)) + return; + } + + extend(map, count, max); + node = &(*map)[*count]; + node->left = left; + node->right = right; + (*count)++; +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/map.h b/mach/proto/mcg/map.h new file mode 100644 index 000000000..bf9d9e8e3 --- /dev/null +++ b/mach/proto/mcg/map.h @@ -0,0 +1,26 @@ +#ifndef MAP_H +#define MAP_H + +struct map_node +{ + void* left; + void* right; +}; + +#define _MAP(MODIFIER, NAME) \ + MODIFIER struct map_node* NAME; \ + MODIFIER int NAME##_count; \ + MODIFIER int NAME##_max + +#define MAP(NAME) _MAP(, NAME) +#define STATICMAP(NAME) _MAP(static, NAME) + +#define MAP_SET(MAP, LEFT, RIGHT) \ + map_set(&MAP, &MAP##_count, &MAP##_max, LEFT, RIGHT) + +extern void map_set(struct map_node** map, int* count, int* max, void* left, void* right); +extern void map_add(struct map_node** map, int* count, int* max, void* left, void* right); + +#endif + + diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 1f66ef249..a7b8d6835 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -17,6 +17,7 @@ #include "em_flag.h" #include "em_ptyp.h" #include "array.h" +#include "map.h" #include "ir.h" extern char em_pseu[][4]; @@ -78,10 +79,7 @@ struct basicblock const char* name; ARRAY(struct insn, insns); ARRAY(struct ir, irs); - ARRAY(struct basicblock, inblocks); - ARRAY(struct basicblock, outblocks); - ARRAY(struct ir, inparams); - ARRAY(struct ir, outparams); + bool is_fake : 1; bool is_root : 1; bool is_terminated : 1; }; @@ -116,7 +114,7 @@ extern void tb_regvar(arith offset, int size, int type, int priority); extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); -extern void pass_splice_adjacent_blocks(struct procedure* proc); +extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void compile(struct procedure* proc); diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 162e53915..7daecfecd 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -128,14 +128,6 @@ static void queue_insn_block(int opcode, struct basicblock* left, struct basicbl insn->u.bvalue.right = right; APPEND(code_bb->insns, insn); - APPENDU(code_bb->outblocks, left); - APPENDU(left->inblocks, code_bb); - if (right) - { - APPENDU(code_bb->outblocks, right); - APPENDU(right->inblocks, code_bb); - } - terminate_block(); } @@ -256,7 +248,12 @@ static void parse_pseu(void) */ if (data_bb) - APPENDU(data_bb->outblocks, bb_get(label)); + { + struct insn* insn = new_insn(op_bra); + insn->paramtype = PARAM_BVALUE; + insn->u.bvalue.left = bb_get(label); + APPEND(data_bb->insns, insn); + } data_offset(label, 0, ro); break; @@ -361,6 +358,7 @@ void parse_em(void) const char* label = dlabel_to_str(insn.em_dlb); data_label(label); data_bb = bb_get(label); + data_bb->is_fake = true; break; } diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index 6ee90bda9..77cdf39d9 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -1,5 +1,9 @@ #include "mcg.h" +STATICMAP(graph); +STATICARRAY(struct ir, pops); +STATICARRAY(struct ir, pushes); + static struct ir* get_last_push(struct basicblock* bb) { int i; @@ -37,61 +41,93 @@ static struct ir* get_first_pop(struct basicblock* bb) return NULL; } -static void convert_block(struct basicblock* bb) +static bool collect_outputs_cb(struct ir* ir, void* user) +{ + struct basicblock* caller = user; + + if (ir->opcode == IR_BLOCK) + MAP_SET(graph, caller, ir->u.bvalue); + return false; +} + +static void make_bb_graph(struct procedure* proc) +{ + int i, j; + + graph_count = 0; + for (i=0; iblocks_count; i++) + { + struct basicblock* bb = proc->blocks[i]; + for (j=0; jirs_count; j++) + ir_walk(bb->irs[j], collect_outputs_cb, bb); + } +} + +static void convert_block(struct procedure* proc, struct basicblock* bb) { int i, j; struct ir* ir; + pushes_count = pops_count = 0; for (;;) { struct ir* lastpush = get_last_push(bb); if (!lastpush) return; - /* Abort unless *every* success block of this one starts with a pop + /* Abort unless *every* successor block of this one starts with a pop * of the same size... */ - for (i=0; ioutblocks_count; i++) + for (i=0; ioutblocks[i]; - - ir = get_first_pop(outbb); - if (!ir || (ir->size != lastpush->size)) - return; - - /* Also abort unless *every* predecessor block of the one we've - * just found *also* ends in a push of the same size. */ - - for (j=0; jinblocks_count; j++) + if (graph[i].left == bb) { - struct basicblock* inbb = outbb->inblocks[i]; + struct basicblock* outbb = graph[i].right; - ir = get_last_push(inbb); + ir = get_first_pop(outbb); if (!ir || (ir->size != lastpush->size)) return; + APPENDU(pops, ir); + + /* Also abort unless *every* predecessor block of the one we've + * just found *also* ends in a push of the same size. */ + + for (j=0; jsize != lastpush->size)) + return; + APPENDU(pushes, ir); + } + } } } /* Okay, now we can wire them all up. */ - for (i=0; ioutblocks_count; i++) + for (i=0; ioutblocks[i]; - struct ir* phi = get_first_pop(outbb); - phi->opcode = IR_PHI; + struct ir* ir = pushes[i]; + assert(ir->is_sequence); + *ir = *ir->left; + ir->is_sequence = true; + } - /* Also abort unless *every* predecessor block of the one we've - * just found *also* ends in a push of the same size. */ + for (i=0; isize, pushir); - for (j=0; jinblocks_count; j++) - { - struct basicblock* inbb = outbb->inblocks[j]; + for (j=1; jsize, phi, pushes[j]); - ir = get_last_push(inbb); - *ir = *ir->left; - ir->is_sequence = true; - APPEND(phi->u.phivalue.imports, ir); - } + phi->is_sequence = ir->is_sequence; + *ir = *phi; } } } @@ -100,8 +136,10 @@ void pass_convert_stack_ops(struct procedure* proc) { int i; + make_bb_graph(proc); + for (i=0; iblocks_count; i++) - convert_block(proc->blocks[i]); + convert_block(proc, proc->blocks[i]); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_deadblocks.c b/mach/proto/mcg/pass_deadblocks.c deleted file mode 100644 index 94c8735cc..000000000 --- a/mach/proto/mcg/pass_deadblocks.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "mcg.h" - -void pass_remove_dead_blocks(struct procedure* proc) -{ - int i, j; - -again: - /* Starts at 1 because we don't want to remove the root block! */ - for (i=1; iblocks_count; i++) - { - struct basicblock* bb = proc->blocks[i]; - - if (bb->inblocks_count == 0) - { - /* Nobody uses this block; disconnect it from its output - * blocks. */ - for (j=0; joutblocks_count; j++) - REMOVE(bb->outblocks[j]->inblocks, bb); - - REMOVE(proc->blocks, bb); - goto again; - } - } -} - -/* vim: set sw=4 ts=4 expandtab : */ - diff --git a/mach/proto/mcg/pass_eliminatetrivialblocks.c b/mach/proto/mcg/pass_eliminatetrivialblocks.c new file mode 100644 index 000000000..96c8e080d --- /dev/null +++ b/mach/proto/mcg/pass_eliminatetrivialblocks.c @@ -0,0 +1,41 @@ +#include "mcg.h" + +static bool rewrite_jumps_cb(struct ir* ir, void* user) +{ + if (ir->opcode == IR_BLOCK) + { + struct basicblock* bb = ir->u.bvalue; + if ((bb->irs_count > 0) + && (bb->irs[0]->opcode == IR_JUMP) + && (bb->irs[0]->left->opcode == IR_BLOCK)) + { + ir->u.bvalue = bb->irs[0]->left->u.bvalue; + } + } + + return false; +} + +static void rewrite_jumps(struct basicblock* bb) +{ + int i; + + for (i=0; iirs_count; i++) + { + struct ir* ir = bb->irs[i]; + ir_walk(ir, rewrite_jumps_cb, NULL); + } +} + +void pass_eliminate_trivial_blocks(struct procedure* proc) +{ + int i; + + for (i=0; iblocks_count; i++) + { + struct basicblock* bb = proc->blocks[i]; + rewrite_jumps(bb); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_removedeadblocks.c b/mach/proto/mcg/pass_removedeadblocks.c new file mode 100644 index 000000000..af2d54d70 --- /dev/null +++ b/mach/proto/mcg/pass_removedeadblocks.c @@ -0,0 +1,40 @@ +#include "mcg.h" + +STATICARRAY(struct basicblock, used); + +static void walk_blocks(struct basicblock* bb); + +static bool walk_blocks_cb(struct ir* ir, void* user) +{ + if (ir->opcode == IR_BLOCK) + walk_blocks(ir->u.bvalue); + return false; +} + +static void walk_blocks(struct basicblock* bb) +{ + int i; + + if (!CONTAINS(used, bb)) + { + APPENDU(used, bb); + + for (i=0; iirs_count; i++) + ir_walk(bb->irs[i], walk_blocks_cb, NULL); + } +} + +void pass_remove_dead_blocks(struct procedure* proc) +{ + int i, j; + + used_count = 0; + walk_blocks(proc->blocks[0]); + + proc->blocks_count = 0; + for (i=0; iblocks, used[i]); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/pass_spliceadjacentblocks.c b/mach/proto/mcg/pass_spliceadjacentblocks.c deleted file mode 100644 index 7f6a69b98..000000000 --- a/mach/proto/mcg/pass_spliceadjacentblocks.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "mcg.h" - -void pass_splice_adjacent_blocks(struct procedure* proc) -{ - int i, j; - -again: - for (i=0; iblocks_count; i++) - { - struct basicblock* bb = proc->blocks[i]; - if (bb->outblocks_count == 1) - { - struct basicblock* outbb = bb->outblocks[0]; - if (outbb->inblocks_count == 1) - { - struct ir* lastir = bb->irs[bb->irs_count-1]; - - if ((lastir->opcode == IR_JUMP) - && (lastir->left->opcode == IR_BLOCK) - && (lastir->left->u.bvalue == outbb)) - { - /* Remove jump instruction. */ - - bb->irs_count--; - - REMOVE(bb->outblocks, outbb); - REMOVE(outbb->inblocks, bb); - - for (j=0; jirs_count; j++) - APPEND(bb->irs, outbb->irs[j]); - for (j=0; joutblocks_count; j++) - { - APPENDU(bb->outblocks, outbb->outblocks[j]); - APPENDU(outbb->outblocks[j]->inblocks, bb); - REMOVE(outbb->outblocks[j]->inblocks, outbb); - } - - REMOVE(proc->blocks, outbb); - goto again; - } - } - } - } -} - -/* vim: set sw=4 ts=4 expandtab : */ - diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 3928dc727..39d529f3d 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -531,8 +531,6 @@ static void insn_ivalue(int opcode, arith value) case op_csa: case op_csb: { - struct basicblock* data_bb; - int i; const char* helper = aprintf(".%s%d", (opcode == op_csa) ? "csa" : "csb", value); @@ -542,16 +540,10 @@ static void insn_ivalue(int opcode, arith value) fatal("csa/csb are only supported if they refer " "directly to a descriptor block"); - /* Splice the outgoing bbs in the data block into our own. */ + /* Turn the label reference into a block. */ - data_bb = bb_get(descriptor->u.lvalue); - for (i=0; ioutblocks_count; i++) - { - struct basicblock* bb = data_bb->outblocks[i]; - printf("\t; may jump to %s\n", bb->name); - APPENDU(current_bb->outblocks, bb); - APPENDU(bb->inblocks, current_bb); - } + descriptor->opcode = IR_BLOCK; + descriptor->u.bvalue = bb_get(descriptor->u.lvalue); push(descriptor); materialise_stack(); From bb9aa030a56ed69db30ed29bc08f09d8fc255482 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 01:04:00 +0200 Subject: [PATCH 016/230] Procedure compilation now happens after the entire EM file has been read in (so that we can look inside data blocks which might be defined in the future... sigh, csa and csb). csa and csb no longer generate invalid IR. --- mach/proto/mcg/main.c | 18 +++++++++- mach/proto/mcg/mcg.h | 6 +++- mach/proto/mcg/parse_em.c | 30 +++++++++++----- mach/proto/mcg/pass_eliminatetrivialblocks.c | 3 +- mach/proto/mcg/{compile.c => procedure.c} | 6 ++-- mach/proto/mcg/symbol.c | 22 ++++++++++++ mach/proto/mcg/treebuilder.c | 38 ++++++++++++++++---- 7 files changed, 103 insertions(+), 20 deletions(-) rename mach/proto/mcg/{compile.c => procedure.c} (79%) diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 6c9a28006..5be59e639 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -39,7 +39,7 @@ bool tracing(char k) { case 'E': return false; case '0': return false; - case '1': return false; + case '1': return true; case '2': return true; default: return true; } @@ -57,6 +57,13 @@ void tracef(char k, const char* fmt, ...) } } +static bool find_procedures_cb(struct symbol* symbol, void* user) +{ + if (symbol->proc) + procedure_compile(symbol->proc); + return false; +} + int main(int argc, char* argv[]) { symbol_init(); @@ -64,8 +71,17 @@ int main(int argc, char* argv[]) if (!EM_open(argv[1])) fatal("Couldn't open input file: %s", EM_error); + /* Reads in the EM, outputs the data sections, parses any code and + * generates IR trees. */ + parse_em(); + /* For every procedure, go ahead and do the compilation proper. We do this + * now so that we know that all the data has been read correctly and our + * symbol table is complete (we may need to refer to it). */ + + symbol_walk(find_procedures_cb, NULL); + EM_close(); return 0; } diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index a7b8d6835..4fa1b1177 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -36,6 +36,7 @@ struct symbol { const char* name; int section; + struct procedure* proc; bool is_defined : 1; bool is_exported : 1; bool is_proc : 1; @@ -96,6 +97,9 @@ extern bool symbol_exists(const char* name); extern struct symbol* symbol_get(const char* name); extern void symbol_declare(const char* name, bool is_exported, bool is_proc); +typedef bool symbol_walker_t(struct symbol* symbol, void* user); +extern struct symbol* symbol_walk(symbol_walker_t* walker, void* user); + extern void data_label(const char* name); extern void data_int(arith data, size_t size, bool is_ro); extern void data_block(const uint8_t* data, size_t size, bool is_ro); @@ -116,7 +120,7 @@ extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); -extern void compile(struct procedure* proc); +extern void procedure_compile(struct procedure* proc); #endif diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 7daecfecd..699e6b4f4 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -280,6 +280,9 @@ static void parse_pseu(void) } case ps_pro: /* procedure start */ + { + struct symbol* symbol; + current_proc = calloc(sizeof(struct procedure), 1); current_proc->name = strdup(insn.em_pnam); current_proc->root_bb = bb_get(current_proc->name); @@ -287,11 +290,16 @@ static void parse_pseu(void) code_bb = current_proc->root_bb; code_bb->is_root = true; APPEND(current_proc->blocks, code_bb); + + symbol = symbol_get(current_proc->name); + symbol->section = SECTION_TEXT; + symbol->proc = current_proc; + symbol->is_proc = true; break; + } case ps_end: /* procedure end */ tb_procedure(current_proc); - compile(current_proc); current_proc = NULL; code_bb = NULL; @@ -336,6 +344,17 @@ static void parse_mes(void) fatal("malformed MES"); } +static void create_data_label(const char* label) +{ + data_label(label); + if (current_proc) + { + data_bb = bb_get(label); + data_bb->is_fake = true; + APPEND(current_proc->blocks, data_bb); + } +} + void parse_em(void) { EM_getinstr(&insn); @@ -354,16 +373,11 @@ void parse_em(void) break; case EM_DEFDLB: - { - const char* label = dlabel_to_str(insn.em_dlb); - data_label(label); - data_bb = bb_get(label); - data_bb->is_fake = true; + create_data_label(dlabel_to_str(insn.em_dlb)); break; - } case EM_DEFDNAM: - data_label(strdup(insn.em_dnam)); + create_data_label(strdup(insn.em_dnam)); break; case EM_STARTMES: diff --git a/mach/proto/mcg/pass_eliminatetrivialblocks.c b/mach/proto/mcg/pass_eliminatetrivialblocks.c index 96c8e080d..3b7280466 100644 --- a/mach/proto/mcg/pass_eliminatetrivialblocks.c +++ b/mach/proto/mcg/pass_eliminatetrivialblocks.c @@ -5,7 +5,8 @@ static bool rewrite_jumps_cb(struct ir* ir, void* user) if (ir->opcode == IR_BLOCK) { struct basicblock* bb = ir->u.bvalue; - if ((bb->irs_count > 0) + if (!bb->is_fake + && (bb->irs_count > 0) && (bb->irs[0]->opcode == IR_JUMP) && (bb->irs[0]->left->opcode == IR_BLOCK)) { diff --git a/mach/proto/mcg/compile.c b/mach/proto/mcg/procedure.c similarity index 79% rename from mach/proto/mcg/compile.c rename to mach/proto/mcg/procedure.c index c6fea43d6..8958a8b7e 100644 --- a/mach/proto/mcg/compile.c +++ b/mach/proto/mcg/procedure.c @@ -11,14 +11,16 @@ static void print_blocks(char k, struct procedure* proc) int j; tracef(k, "%c:\n", k); - tracef(k, "%c: BLOCK: %s\n", k, bb->name); + tracef(k, "%c: %sBLOCK: %s\n", k, + bb->is_fake ? "FAKE " : "", + bb->name); for (int j=0; jirs_count; j++) ir_print(k, bb->irs[j]); } } -void compile(struct procedure* proc) +void procedure_compile(struct procedure* proc) { int i; diff --git a/mach/proto/mcg/symbol.c b/mach/proto/mcg/symbol.c index 14ec4a97a..f8c2f52fb 100644 --- a/mach/proto/mcg/symbol.c +++ b/mach/proto/mcg/symbol.c @@ -1,7 +1,10 @@ #include "mcg.h" +typedef int idf_walker_t(struct idf* idf, void* user); + static void init_idf(); static struct idf* str2idf(char* tg, int cp); +static struct idf* walk_idf(idf_walker_t* cb, void* user); #define IDF_TYPE struct symbol #define IDF_NAME symbol @@ -39,3 +42,22 @@ void symbol_declare(const char* name, bool is_exported, bool is_proc) } } +struct symbol* symbol_walk(symbol_walker_t* cb, void* user) +{ + int i; + + for (i=0; isymbol; + if (cb(symbol, user)) + return &symbol; + idf = idf->id_next; + } + } + + return NULL; +} + diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 39d529f3d..ea699d720 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -281,6 +281,12 @@ static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock break; } + case op_lae: + push( + new_bbir(leftbb) + ); + break; + default: fatal("treebuilder: unknown bvalue instruction '%s'", em_mnem[opcode - sp_fmnem]); @@ -312,6 +318,27 @@ static void simple_alu2(int opcode, int size, int irop) ); } +static struct ir* extract_block_refs(struct basicblock* bb) +{ + struct ir* outir = NULL; + int i; + + for (i=0; iinsns_count; i++) + { + struct insn* insn = bb->insns[i]; + assert(insn->opcode == op_bra); + assert(insn->paramtype == PARAM_BVALUE); + + outir = new_ir2( + IR_PAIR, 0, + new_bbir(insn->u.bvalue.left), + outir + ); + } + + return outir; +} + static void insn_ivalue(int opcode, arith value) { switch (opcode) @@ -540,17 +567,13 @@ static void insn_ivalue(int opcode, arith value) fatal("csa/csb are only supported if they refer " "directly to a descriptor block"); - /* Turn the label reference into a block. */ - - descriptor->opcode = IR_BLOCK; - descriptor->u.bvalue = bb_get(descriptor->u.lvalue); - push(descriptor); materialise_stack(); appendir( - new_ir1( + new_ir2( IR_JUMP, 0, - new_labelir(helper) + new_labelir(helper), + extract_block_refs(bb_get(descriptor->u.lvalue)) ) ); break; @@ -675,6 +698,7 @@ void tb_procedure(struct procedure* current_proc) for (i=0; iblocks_count; i++) generate_tree(current_proc->blocks[i]); + } /* vim: set sw=4 ts=4 expandtab : */ From 6643d39b2c9c66836a2d343422b0cdc3de5e69fd Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 01:09:32 +0200 Subject: [PATCH 017/230] Fix some late-night typo bugs. --- mach/proto/mcg/symbol.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mach/proto/mcg/symbol.c b/mach/proto/mcg/symbol.c index f8c2f52fb..6012b91f3 100644 --- a/mach/proto/mcg/symbol.c +++ b/mach/proto/mcg/symbol.c @@ -1,10 +1,7 @@ #include "mcg.h" -typedef int idf_walker_t(struct idf* idf, void* user); - static void init_idf(); static struct idf* str2idf(char* tg, int cp); -static struct idf* walk_idf(idf_walker_t* cb, void* user); #define IDF_TYPE struct symbol #define IDF_NAME symbol @@ -53,7 +50,7 @@ struct symbol* symbol_walk(symbol_walker_t* cb, void* user) { struct symbol* symbol = &idf->symbol; if (cb(symbol, user)) - return &symbol; + return symbol; idf = idf->id_next; } } From 960259f0b054f4250279a5592ddffb58c50ed6b6 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 12:11:30 +0200 Subject: [PATCH 018/230] Add support for labelled tree nodes. --- util/mcgg/gram.y | 22 +++++++++++++++------- util/mcgg/iburg.c | 15 ++++++++------- util/mcgg/iburg.h | 13 +++++++------ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index ea0abbc75..84a899037 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -16,6 +16,7 @@ static int nextern = 0; char* string; Tree tree; Stringlist stringlist; + char* stringpair[2]; } %term TERMINAL %term START @@ -27,15 +28,17 @@ static int nextern = 0; %term EMIT %term COST +%token INT %token ID %token CFRAGMENT -%token INT -%type lhs -%type rhs %type cost -%type when +%type label +%type lhs %type stringlist +%type when +%type rhs +%type labelledid %% spec : decls PPERCENT patterns @@ -78,11 +81,16 @@ lhs ; rhs - : ID { $$ = tree($1, NULL, NULL); } - | ID '(' rhs ')' { $$ = tree($1, $3, NULL); } - | ID '(' rhs ',' rhs ')' { $$ = tree($1, $3, $5); } + : labelledid { $$ = tree($1[1], $1[0], NULL, NULL); } + | labelledid '(' rhs ')' { $$ = tree($1[1], $1[0], $3, NULL); } + | labelledid '(' rhs ',' rhs ')' { $$ = tree($1[1], $1[0], $3, $5); } ; +labelledid + : ID { $$[0] = NULL; $$[1] = $1; } + | ID ':' ID { $$[0] = $1; $$[1] = $3; } + ; + when : /* nothing */ { $$ = NULL; } | WHEN stringlist { $$ = $2; } diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 833d3e0d4..cae03e54d 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -151,7 +151,7 @@ struct entry { union { - char* name; + const char* name; struct term t; struct nonterm nt; } sym; @@ -160,7 +160,7 @@ struct entry #define HASHSIZE (sizeof table / sizeof table[0]) /* hash - return hash number for str */ -static unsigned hash(char* str) +static unsigned hash(const char* str) { unsigned h = 0; @@ -170,7 +170,7 @@ static unsigned hash(char* str) } /* lookup - lookup symbol name */ -static void* lookup(char* name) +static void* lookup(const char* name) { struct entry* p = table[hash(name) % HASHSIZE]; @@ -181,7 +181,7 @@ static void* lookup(char* name) } /* install - install symbol name */ -static void* install(char* name) +static void* install(const char* name) { struct entry* p = calloc(1, sizeof *p); int i = hash(name) % HASHSIZE; @@ -193,7 +193,7 @@ static void* install(char* name) } /* nonterm - create a new terminal id, if necessary */ -Nonterm nonterm(char* id) +Nonterm nonterm(const char* id) { Nonterm p = lookup(id), * q = &nts; @@ -215,7 +215,7 @@ Nonterm nonterm(char* id) } /* term - create a new terminal id with external symbol number esn */ -Term term(char* id, int esn) +Term term(const char* id, int esn) { Term p = lookup(id), * q = &terms; @@ -240,7 +240,7 @@ Term term(char* id, int esn) } /* tree - create & initialize a tree node with the given fields */ -Tree tree(char* id, Tree left, Tree right) +Tree tree(const char* id, const char* label, Tree left, Tree right) { Tree t = calloc(1, sizeof *t); Term p = lookup(id); @@ -267,6 +267,7 @@ Tree tree(char* id, Tree left, Tree right) if (p->kind == TERM && arity != p->arity) yyerror("inconsistent arity for terminal `%s'\n", id); t->op = p; + t->label = label; t->nterms = p->kind == TERM; if (t->left = left) t->nterms += left->nterms; diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 6b5f9affc..5c5334c79 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -41,17 +41,18 @@ struct nonterm Rule chain; /* chain rules w/non-terminal on rhs */ Nonterm link; /* next terminal in number order */ }; -extern Nonterm nonterm(char* id); -extern Term term(char* id, int esn); +extern Nonterm nonterm(const char* id); +extern Term term(const char* id, int esn); typedef struct tree* Tree; struct tree { /* tree patterns: */ - void* op; /* a terminal or non-terminal */ - Tree left, right; /* operands */ - int nterms; /* number of terminal nodes in this tree */ + void* op; /* a terminal or non-terminal */ + const char* label; /* user label for this node */ + Tree left, right; /* operands */ + int nterms; /* number of terminal nodes in this tree */ }; -extern Tree tree(char* op, Tree left, Tree right); +extern Tree tree(const char* op, const char* label, Tree left, Tree right); struct rule { /* rules: */ From d96ceea08a643420daf7f7b4a9bcec89c88f463e Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 13:08:17 +0200 Subject: [PATCH 019/230] Lots of exploratory new grammar for instruction definitions and string and fragment emission (none of which is hooked up to anything yet). --- util/mcgg/gram.y | 74 +++++++++++++++++++++++-------- util/mcgg/mcgg_generated_footer.h | 7 ++- util/mcgg/scan.l | 5 ++- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 84a899037..5f100c7d2 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -23,17 +23,19 @@ static int nextern = 0; %term PPERCENT %term PATTERNS -%term PAT %term WHEN %term EMIT +%term FRAGMENT %term COST +%term INS +%term OUTS %token INT %token ID %token CFRAGMENT +%token STRING %type cost -%type label %type lhs %type stringlist %type when @@ -69,15 +71,15 @@ patterns : /* nothing */ | patterns pattern ';' | patterns ';' - | patterns error ';' { yyerrok; } + | patterns error ';' { yyerrok; } ; pattern - : lhs '=' rhs when cost { rule($1, $3, nextern++, $4, $5); } + : lhs '=' rhs when ins outs emits cost { rule($1, $3, nextern++, $4, $8); } ; lhs - : ID { $$ = $1; nonterm($$); } + : ID { $$ = $1; nonterm($$); } ; rhs @@ -87,29 +89,63 @@ rhs ; labelledid - : ID { $$[0] = NULL; $$[1] = $1; } - | ID ':' ID { $$[0] = $1; $$[1] = $3; } + : ID { $$[0] = NULL; $$[1] = $1; } + | ID ':' ID { $$[0] = $1; $$[1] = $3; } ; when - : /* nothing */ { $$ = NULL; } - | WHEN stringlist { $$ = $2; } + : /* nothing */ { $$ = NULL; } + | WHEN stringlist { $$ = $2; } ; stringlist - : /* nothing */ { $$ = NULL; } - | CFRAGMENT stringlist { $$ = pushstring($1, $2); } + : /* nothing */ { $$ = NULL; } + | CFRAGMENT stringlist { $$ = pushstring($1, $2); } ; +ins + : /* nothing */ + | INS inslist + ; + +inslist + : inslist ',' in + | in + ; + +in + : ID ':' ID + ; + +outs + : /* nothing */ + | OUTS outslist + ; + +outslist + : outslist ',' out + | out + ; + +out + : ID ':' ID + ; + +emits + : /* nothing */ + | EMIT STRING + | FRAGMENT STRING + ; + cost - : /* lambda */ { $$ = 0; } - | COST INT { - if ($2 > maxcost) { - yyerror("%d exceeds maximum cost of %d\n", $2, maxcost); - $$ = maxcost; - } else - $$ = $2; - } + : /* lambda */ { $$ = 0; } + | COST INT { + if ($2 > maxcost) { + yyerror("%d exceeds maximum cost of %d\n", $2, maxcost); + $$ = maxcost; + } else + $$ = $2; + } ; %% #include diff --git a/util/mcgg/mcgg_generated_footer.h b/util/mcgg/mcgg_generated_footer.h index 7b9bbdb46..986ecd222 100644 --- a/util/mcgg/mcgg_generated_footer.h +++ b/util/mcgg/mcgg_generated_footer.h @@ -10,7 +10,12 @@ static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { fprintf(stderr, "%s\n", burm_string[eruleno]); burm_kids(p, eruleno, kids); for (i = 0; nts[i]; i++) - dumpCover(kids[i], nts[i], indent + 1); + { + if (kids[i]) + dumpCover(kids[i], nts[i], indent + 1); + else + fprintf(stderr, "failed!\n"); + } #endif } diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 3a067685b..ebcb9c107 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -55,11 +55,14 @@ static int braces = 0; "%start" return START; "PATTERNS" return PATTERNS; -"pat" return PAT; "when" return WHEN; +"ins" return INS; +"outs" return OUTS; "emit" return EMIT; +"fragment" return FRAGMENT; "cost" return COST; +\"[^"\n]*\" { yylval.string = strdup(yytext); return STRING; } [A-Za-z_][A-Za-z0-9_]* { yylval.string = strdup(yytext); return ID; } [0-9]+ { yylval.n = atoi(yytext); return INT; } [ \t\r\n]* ; From 434eafd35dd6610372cb5c8dafa7df9e91c6325d Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 13:33:59 +0200 Subject: [PATCH 020/230] Change the predicate stuff to use costs instead; now you can use when clauses on leaves. Remove an iburg premature optimisation (required for above). --- util/mcgg/iburg.c | 95 +++++++------------------------ util/mcgg/mcgg_generated_footer.h | 5 +- 2 files changed, 23 insertions(+), 77 deletions(-) diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index cae03e54d..9d5d3f0e7 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -24,6 +24,7 @@ static void print(char* fmt, ...); static void ckreach(Nonterm p); static void emitclosure(Nonterm nts); static void emitcost(Tree t, char* v); +static void emitcostcalc(Rule r); static void emitdefs(Nonterm nts, int ntnumber); static void emitfuncs(void); static void emitheader(void); @@ -34,7 +35,6 @@ static void emitnts(Rule rules, int nrules); static void emitrecord(char* pre, Rule r, int cost); static void emitrule(Nonterm nts); static void emitpredicatedefinitions(Rule rules); -static void emitpredicatecall(Rule rule); static void emitstate(Term terms, Nonterm start, int ntnumber); static void emitstring(Rule rules); static void emitstruct(Nonterm nts, int ntnumber); @@ -283,9 +283,6 @@ Rule rule(char* id, Tree pattern, int ern, Stringlist when, int cost) Rule *q; Term p = pattern->op; - if (when && (p->arity == 0)) - yyerror("can't have a when clause on leaf nodes"); - nrules++; r->when = when; r->lhs = nonterm(id); @@ -421,11 +418,6 @@ static void emitcase(Term p, int ntnumber) { case 0: case -1: - if (!Tflag) - { - emitleaf(p, ntnumber); - return; - } break; case 1: print("%2assert(l);\n"); @@ -442,26 +434,21 @@ static void emitcase(Term p, int ntnumber) { case 0: case -1: - print("%2if ("); - emitpredicatecall(r); - print(")\n%2{%1/* %R */\n%3c = ", r); + print("%2{%1/* %R */\n%3c = ", r); + emitcostcalc(r); break; case 1: if (r->pattern->nterms > 1) { print("%2if (%1/* %R */\n", r); emittest(r->pattern->left, "l", " "); - print("%3&& "); - emitpredicatecall(r); - print("\n"); print("%2) {\n%3c = "); } else { - print("%2if ("); - emitpredicatecall(r); - print(")\n%2{%1/* %R */\n%3c = ", r); + print("%2{%1/* %R */\n%3c = ", r); } + emitcostcalc(r); emitcost(r->pattern->left, "l"); break; case 2: @@ -471,17 +458,13 @@ static void emitcase(Term p, int ntnumber) emittest(r->pattern->left, "l", r->pattern->right->nterms ? " && " : " "); emittest(r->pattern->right, "r", " "); - print("%3&& "); - emitpredicatecall(r); - print("\n"); print("%2) {\n%3c = "); } else { - print("%2if ("); - emitpredicatecall(r); - print(")\n%2{%1/* %R */\n%3c = ", r); + print("%2{%1/* %R */\n%3c = ", r); } + emitcostcalc(r); emitcost(r->pattern->left, "l"); emitcost(r->pattern->right, "r"); break; @@ -668,46 +651,6 @@ static void closure(int cost[], Rule rule[], Nonterm p, int c) } } -/* emitleaf - emit state code for a leaf */ -static void emitleaf(Term p, int ntnumber) -{ - int i; - Rule r; - static int* cost; - static Rule* rule; - - if (cost == NULL) - { - cost = calloc(ntnumber+1, sizeof *cost); - rule = calloc(ntnumber+1, sizeof *rule); - } - for (i = 0; i <= ntnumber; i++) - { - cost[i] = maxcost; - rule[i] = NULL; - } - for (r = p->rules; r; r = r->next) - if (r->pattern->left == NULL && r->pattern->right == NULL) - { - cost[r->lhs->number] = r->cost; - rule[r->lhs->number] = r; - closure(cost, rule, r->lhs, r->cost); - } - print("%2{\n%3static struct %Pstate z = { %d, 0, 0,\n%4{%10,\n", p->esn); - for (i = 1; i <= ntnumber; i++) - if (cost[i] < maxcost) - print("%5%d,%1/* %R */\n", cost[i], rule[i]); - else - print("%5%d,\n", cost[i]); - print("%4},{\n"); - for (i = 1; i <= ntnumber; i++) - if (rule[i]) - print("%5%d,%1/* %R */\n", rule[i]->packed, rule[i]); - else - print("%50,\n"); - print("%4}\n%3};\n%3return (STATE_TYPE)&z;\n%2}\n"); -} - /* computents - fill in bp with burm_nts vector for tree t */ static char* computents(Tree t, char* bp) { @@ -815,13 +758,11 @@ static void emitpredicatedefinitions(Rule r) } } -/* emitpredicatecall - emit a call to a predicate */ -static void emitpredicatecall(Rule r) +/* emitcost - emit a cost calculation via a predicate */ +static void emitcostcalc(Rule r) { if (r->when) - print("%Ppredicate_%d(node)", r->ern); - else - print("1"); + print("!%Ppredicate_%d(node) ? %d : ", r->ern, maxcost); } /* emitstate - emit state function */ @@ -837,15 +778,17 @@ static void emitstate(Term terms, Nonterm start, int ntnumber) "%1struct %Pstate* r = (struct %Pstate *)right;\n" "\n" "%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1"); - if (!Tflag) - print("if (%Parity[op] > 0) "); - print("{\n%2p = ALLOC(sizeof *p);\n" - "%2%Passert(p, PANIC(\"ALLOC returned NULL in %Pstate\\n\"));\n" - "%2p->op = op;\n%2p->left = l;\n%2p->right = r;\n%2p->rule.%P%S = 0;\n", + print("%1p = ALLOC(sizeof *p);\n" + "%1%Passert(p, PANIC(\"ALLOC returned NULL in %Pstate\\n\"));\n" + "%1p->op = op;\n" + "%1p->left = l;\n" + "%1p->right = r;\n" + "%1p->rule.%P%S = 0;\n", start); for (i = 1; i <= ntnumber; i++) - print("%2p->cost[%d] =\n", i); - print("%3%d;\n%1}\n%1switch (op) {\n", maxcost); + print("%1p->cost[%d] =\n", i); + print("%2%d;\n" + "%1switch (op) {\n", maxcost); for (p = terms; p; p = p->link) emitcase(p, ntnumber); print("%1default:\n" diff --git a/util/mcgg/mcgg_generated_footer.h b/util/mcgg/mcgg_generated_footer.h index 986ecd222..820543956 100644 --- a/util/mcgg/mcgg_generated_footer.h +++ b/util/mcgg/mcgg_generated_footer.h @@ -32,7 +32,10 @@ int main(void) { NODEPTR_TYPE p; p = tree(STORE, - tree(LABEL, 0, 0), + tree(ADD, + tree(LABEL, 0, 0), + tree(CONST, 0, 0) + ), tree(ADD, tree(LOAD, tree(LABEL, 0, 0), From 13132128a1cbdcbb8479fd6df79b6d994867b2e9 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 16:59:49 +0200 Subject: [PATCH 021/230] Parameters are parsed with getopt. Simplify, constify. --- util/mcgg/iburg.c | 106 +++++++++++------------------- util/mcgg/mcgg_generated_footer.h | 2 +- 2 files changed, 40 insertions(+), 68 deletions(-) diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 9d5d3f0e7..8f305e751 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -9,10 +10,10 @@ static char rcsid[] = "$Id$"; -int maxcost = SHRT_MAX; +int maxcost = SHRT_MAX / 2; static char* prefix = "burm"; -static int Iflag = 0, Tflag = 0; +static int Tflag = 1; /* tracing */ static int ntnumber = 0; static Nonterm start = 0; static Term terms; @@ -51,49 +52,26 @@ int main(int argc, char* argv[]) yydebug = 1; #endif - if (sizeof(short) == sizeof(int)) - maxcost = SHRT_MAX / 2; - for (i = 1; i < argc; i++) - if (strcmp(argv[i], "-I") == 0) - Iflag = 1; - else if (strcmp(argv[i], "-T") == 0) - Tflag = 1; - else if (strncmp(argv[i], "-maxcost=", 9) == 0 && isdigit(argv[i][9])) - maxcost = atoi(argv[i] + 9); - else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2]) - prefix = &argv[i][2]; - else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc) - prefix = argv[++i]; - else if (*argv[i] == '-' && argv[i][1]) + for (;;) + { + int opt = getopt(argc, argv, "p:"); + if (opt == -1) + break; + + switch (opt) { - yyerror("usage: %s [-T | -I | -p prefix | -maxcost=ddd ]... [ [ input ] output \n", - argv[0]); - exit(1); - } - else if (infp == NULL) - { - if (strcmp(argv[i], "-") == 0) - infp = stdin; - else if ((infp = fopen(argv[i], "r")) == NULL) - { - yyerror("%s: can't read `%s'\n", argv[0], argv[i]); + case 'p': + prefix = optarg; + break; + + default: + yyerror("usage: %s [-p prefix] < input > output\n", argv[0]); exit(1); - } } - else if (outfp == NULL) - { - if (strcmp(argv[i], "-") == 0) - outfp = stdout; - if ((outfp = fopen(argv[i], "w")) == NULL) - { - yyerror("%s: can't write `%s'\n", argv[0], argv[i]); - exit(1); - } - } - if (infp == NULL) - infp = stdin; - if (outfp == NULL) - outfp = stdout; + } + + infp = stdin; + outfp = stdout; yyin = infp; yyparse(); @@ -108,8 +86,7 @@ int main(int argc, char* argv[]) emitstruct(nts, ntnumber); emitnts(rules, nrules); emitterms(terms); - if (Iflag) - emitstring(rules); + emitstring(rules); emitrule(nts); emitclosure(nts); emitpredicatedefinitions(rules); @@ -521,14 +498,11 @@ static void emitdefs(Nonterm nts, int ntnumber) for (p = nts; p; p = p->link) print("#define %P%S_NT %d\n", p, p->number); - print("int %Pmax_nt = %d;\n\n", ntnumber); - if (Iflag) - { - print("char *%Pntname[] = {\n%10,\n"); - for (p = nts; p; p = p->link) - print("%1\"%S\",\n", p); - print("%10\n};\n\n"); - } + print("static const int %Pmax_nt = %d;\n\n", ntnumber); + print("const char *%Pntname[] = {\n%10,\n"); + for (p = nts; p; p = p->link) + print("%1\"%S\",\n", p); + print("%10\n};\n\n"); } /* emitfuncs - emit functions to access node fields */ @@ -683,12 +657,12 @@ static void emitnts(Rule rules, int nrules) ; if (str[j] == NULL) { - print("static short %Pnts_%d[] = { %s0 };\n", j, buf); + print("static const short %Pnts_%d[] = { %s0 };\n", j, buf); str[j] = strdup(buf); } nts[i++] = j; } - print("\nshort *%Pnts[] = {\n"); + print("\nconst short *%Pnts[] = {\n"); for (i = j = 0, r = rules; r; r = r->link) { for (; j < r->ern; j++) @@ -722,7 +696,7 @@ static void emitrule(Nonterm nts) for (p = nts; p; p = p->link) { Rule r; - print("static short %Pdecode_%S[] = {\n%10,\n", p); + print("static const short %Pdecode_%S[] = {\n%10,\n", p); for (r = p->rules; r; r = r->decode) print("%1%d,\n", r->ern); print("};\n\n"); @@ -802,14 +776,14 @@ static void emitstring(Rule rules) Rule r; int k; - print("short %Pcost[][4] = {\n"); + print("static const short %Pcost[][4] = {\n"); for (k = 0, r = rules; r; r = r->link) { for (; k < r->ern; k++) print("%1{ 0 },%1/* %d */\n", k); print("%1{ %d },%1/* %d = %R */\n", r->cost, k++, r); } - print("};\n\nchar *%Pstring[] = {\n"); + print("};\n\nconst char *%Pstring[] = {\n"); for (k = 0, r = rules; r; r = r->link) { for (; k < r->ern; k++) @@ -841,7 +815,7 @@ static void emitterms(Term terms) Term p; int k; - print("char %Parity[] = {\n"); + print("static const char %Parity[] = {\n"); for (k = 0, p = terms; p; p = p->link) { for (; k < p->esn; k++) @@ -849,17 +823,15 @@ static void emitterms(Term terms) print("%1%d,%1/* %d=%S */\n", p->arity < 0 ? 0 : p->arity, k++, p); } print("};\n\n"); - if (Iflag) + + print("static const char *%Popname[] = {\n"); + for (k = 0, p = terms; p; p = p->link) { - print("char *%Popname[] = {\n"); - for (k = 0, p = terms; p; p = p->link) - { - for (; k < p->esn; k++) - print("%1/* %d */%10,\n", k); - print("%1/* %d */%1\"%S\",\n", k++, p); - } - print("};\n\n"); + for (; k < p->esn; k++) + print("%1/* %d */%10,\n", k); + print("%1/* %d */%1\"%S\",\n", k++, p); } + print("};\n\n"); } /* emittest - emit clause for testing a match */ diff --git a/util/mcgg/mcgg_generated_footer.h b/util/mcgg/mcgg_generated_footer.h index 820543956..5b4d20109 100644 --- a/util/mcgg/mcgg_generated_footer.h +++ b/util/mcgg/mcgg_generated_footer.h @@ -1,7 +1,7 @@ static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { #ifdef TRACE int eruleno = burm_rule(STATE_LABEL(p), goalnt); - short *nts = burm_nts[eruleno]; + const short *nts = burm_nts[eruleno]; NODEPTR_TYPE kids[10]; int i; From 151665790796f14402509e49a4eaaf8efcb0637c Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 17:20:40 +0200 Subject: [PATCH 022/230] Crudely bolt on mcgg to mcg itself. --- mach/proto/mcg/build.lua | 9 +- .../proto/mcg}/mcgg_generated_footer.h | 0 mach/proto/mcg/mcgg_generated_header.h | 32 +++++++ mach/proto/mcg/table | 86 +++++++++++++++++++ util/mcgg/build.lua | 34 ++++++++ util/mcgg/iburg.c | 12 ++- 6 files changed, 165 insertions(+), 8 deletions(-) rename {util/mcgg => mach/proto/mcg}/mcgg_generated_footer.h (100%) create mode 100644 mach/proto/mcg/mcgg_generated_header.h create mode 100644 mach/proto/mcg/table diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index d1b2a3f49..246a11ee3 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -1,3 +1,5 @@ +include("util/mcgg/build.lua") + normalrule { name = "ircodes", outleaves = { "ircodes.h", "ircodes.c" }, @@ -10,10 +12,16 @@ normalrule { } } +mcgg { + name = "mcgg_c", + srcs = { "./table" } +} + cprogram { name = "mcg", srcs = { "./*.c", + "+mcgg_c", matching(filenamesof("+ircodes"), "%.c$") }, deps = { @@ -28,7 +36,6 @@ cprogram { "modules/src/string+lib", "modules/src/system+lib", "./*.h", - "util/mcgg+mcgg", }, vars = { ["+cflags"] = { diff --git a/util/mcgg/mcgg_generated_footer.h b/mach/proto/mcg/mcgg_generated_footer.h similarity index 100% rename from util/mcgg/mcgg_generated_footer.h rename to mach/proto/mcg/mcgg_generated_footer.h diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h new file mode 100644 index 000000000..2545e8af3 --- /dev/null +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include + +#define TRACE + +#define STATE_TYPE void* +typedef struct tree { + int op; + struct tree *kids[2]; + STATE_TYPE state_label; +} *NODEPTR_TYPE; +#define OP_LABEL(p) ((p)->op) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->state_label) +#define PANIC printf + +static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { +#ifdef TRACE + extern const char *burm_string[]; + + fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p, + burm_string[eruleno], cost, bestcost); +#endif +} + +#define burm_assert(b, s) assert(b && s) + diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table new file mode 100644 index 000000000..f9a51c904 --- /dev/null +++ b/mach/proto/mcg/table @@ -0,0 +1,86 @@ +%{ +#if 0 +#include +#include +#include +#include + +#define TRACE + +#define STATE_TYPE void* +typedef struct tree { + int op; + struct tree *kids[2]; + STATE_TYPE state_label; +} *NODEPTR_TYPE; +#define OP_LABEL(p) ((p)->op) +#define LEFT_CHILD(p) ((p)->kids[0]) +#define RIGHT_CHILD(p) ((p)->kids[1]) +#define STATE_LABEL(p) ((p)->state_label) +#define PANIC printf + +static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { +#ifdef TRACE + extern const char *burm_string[]; + + fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p, + burm_string[eruleno], cost, bestcost); +#endif +} +#endif +%} +%term LOAD STORE LABEL CONST ADD FOO BAR BAZ BOO; +%% + + stm = STORE(addr:address, value:reg) + ins value:GPR + emit "str %value, %addr" + cost 4; + + reg = LOAD(addr:address) + outs dest:ANY + emit "ld %dest, %addr" + cost 4; + + address = ADD(addr:reg, offset:CONST) + ins addr:GPR + fragment "[%addr, #%offset.ivalue]"; + + address = addr:reg + ins addr:GPR + fragment "[%addr]"; + + stm = reg; + + reg = ADD(left:reg, right:aluparam) + ins left:GPR, right:GPR + outs out:GPR + emit "add %out, %left, %right" + cost 4; + + reg = ADD(left:aluparam, right:reg) + ins left:GPR, right:GPR + outs out:GPR + emit "add %out, %right, %left" + cost 4; + + aluparam = value:CONST + when { return false; } + fragment "#%value.ivalue"; + + aluparam = reg; + + reg = value:aluparam + outs out:GPR + emit "mov %out, %value" + cost 4; + + reg = value:LABEL + outs out:GPR + emit "adr %out, #value.lvalue" + cost 4; + + reg = value:CONST + outs out:GPR + emit "ldr %out, #value.lvalue" + cost 4; diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index d0022baa9..a7d3cfde3 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -22,4 +22,38 @@ cprogram { "+yacc" } } + +definerule("mcgg", + { + srcs = { type="targets" } + }, + function(e) + -- Remember this is executed from the caller's directory; local + -- target names will resolve there + if (#e.srcs ~= 1) then + error("you must supply exactly one input file") + end + + local cpptable = cppfile { + name = e.name.."/cpptable", + outleaf = "cpptable", + srcs = e.srcs + } + + return normalrule { + name = e.name, + cwd = e.cwd, + outleaves = { + "tables.c", + }, + ins = { + "util/mcgg+mcgg", + cpptable + }, + commands = { + "%{ins[1]} < %{ins[2]} > %{outs}", + } + } + end +) diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 8f305e751..05dd6c4ed 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -73,6 +73,8 @@ int main(int argc, char* argv[]) infp = stdin; outfp = stdout; + emitheader(); + yyin = infp; yyparse(); @@ -81,7 +83,7 @@ int main(int argc, char* argv[]) for (p = nts; p; p = p->link) if (!p->reached) yyerror("can't reach non-terminal `%s'\n", p->name); - emitheader(); + emitdefs(nts, ntnumber); emitstruct(nts, ntnumber); emitnts(rules, nrules); @@ -524,10 +526,7 @@ static void emitfuncs(void) /* emitheader - emit initial definitions */ static void emitheader(void) { - print("#include \n#include \n"); - print("#ifndef STATE_TYPE\n#define STATE_TYPE int\n#endif\n"); - print("#ifndef ALLOC\n#define ALLOC(n) malloc(n)\n#endif\n" - "#ifndef %Passert\n#define %Passert(x,y) if (!(x)) { y; abort(); }\n#endif\n\n"); + print("#include \"mcgg_generated_header.h\"\n"); if (Tflag) print("static NODEPTR_TYPE %Pnp;\n\n"); } @@ -752,8 +751,7 @@ static void emitstate(Term terms, Nonterm start, int ntnumber) "%1struct %Pstate* r = (struct %Pstate *)right;\n" "\n" "%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1"); - print("%1p = ALLOC(sizeof *p);\n" - "%1%Passert(p, PANIC(\"ALLOC returned NULL in %Pstate\\n\"));\n" + print("%1p = malloc(sizeof *p);\n" "%1p->op = op;\n" "%1p->left = l;\n" "%1p->right = r;\n" From 2acc4ed29dd5c5d034c4cb1ebc40c785829a4fea Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 18:31:35 +0200 Subject: [PATCH 023/230] IR codes are now owned by mcgg; ir terminals are inserted into the table during compilation (so you can refer to them). --- mach/proto/mcg/build.lua | 15 +----- mach/proto/mcg/ir.dat | 71 ------------------------ mach/proto/mcg/ircodes.sh | 36 ------------- mach/proto/mcg/mcgg_generated_footer.h | 16 +++--- mach/proto/mcg/table | 17 +++--- util/mcgg/build.lua | 25 ++++++++- util/mcgg/iburg.c | 62 +++++++++++++++++++-- util/mcgg/iburg.h | 11 ++++ util/mcgg/ir.dat | 74 ++++++++++++++++++++++++++ util/mcgg/ircodes.sh | 61 +++++++++++++++++++++ 10 files changed, 244 insertions(+), 144 deletions(-) delete mode 100644 mach/proto/mcg/ir.dat delete mode 100755 mach/proto/mcg/ircodes.sh create mode 100644 util/mcgg/ir.dat create mode 100755 util/mcgg/ircodes.sh diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index 246a11ee3..b9440a790 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -1,17 +1,5 @@ include("util/mcgg/build.lua") -normalrule { - name = "ircodes", - outleaves = { "ircodes.h", "ircodes.c" }, - ins = { - "./ircodes.sh", - "./ir.dat" - }, - commands = { - "%{ins[1]} %{ins[2]} %{outs[1]} %{outs[2]}" - } -} - mcgg { name = "mcgg_c", srcs = { "./table" } @@ -22,10 +10,9 @@ cprogram { srcs = { "./*.c", "+mcgg_c", - matching(filenamesof("+ircodes"), "%.c$") }, deps = { - "+ircodes", + "util/mcgg+lib", "h+emheaders", "modules+headers", "modules/src/alloc+lib", diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat deleted file mode 100644 index 36787525c..000000000 --- a/mach/proto/mcg/ir.dat +++ /dev/null @@ -1,71 +0,0 @@ -# Simple terminals -CONST -REG -LABEL -BLOCK -PAIR -ANY -LOCAL -PHI - -# Magic stack operations -PUSH -POP -SET - -# Memory operations -LOAD -STORE - -# Arithemetic operations -ADD -SUB -MUL -DIV -MOD -NEG - -ADDF -SUBF -MULF -DIVF -NEGF - -AND -OR -EOR -NOT - -# Conversions -CII1 -CII2 -CII4 -CII8 - -CIU1 -CIU2 -CIU4 -CIU8 - -# Tristate comparisons -COMPARES -COMPAREU - -# Boolean comparisons -IFEQ -IFLT -IFLE - -# Procedures -CALL - -# Flow control --- these never return -JUMP -CJUMP -RET - -# Special -STACKADJUST -GETRET -SETRET - diff --git a/mach/proto/mcg/ircodes.sh b/mach/proto/mcg/ircodes.sh deleted file mode 100755 index 3fdf1982d..000000000 --- a/mach/proto/mcg/ircodes.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -in=$1 -header=$2 -source=$3 - -awk -f - $in >$header << "EOF" - BEGIN { - print "enum ir_opcode {" - } - - /^[^#]+/ { - print "\tIR_" $1 "," - } - - END { - print "};" - } -EOF - -awk -f - $in >$source << "EOF" - BEGIN { - print "#include \"mcg.h\"" - print "#include \"ir.h\"" - print "const char* ir_names[] = {" - } - - /^[^#]+/ { - printf("\t\"%s\",\n", $1) - } - - END { - print "};" - } -EOF - diff --git a/mach/proto/mcg/mcgg_generated_footer.h b/mach/proto/mcg/mcgg_generated_footer.h index 5b4d20109..56bdc9168 100644 --- a/mach/proto/mcg/mcgg_generated_footer.h +++ b/mach/proto/mcg/mcgg_generated_footer.h @@ -31,17 +31,17 @@ static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) { int main(void) { NODEPTR_TYPE p; - p = tree(STORE, - tree(ADD, - tree(LABEL, 0, 0), - tree(CONST, 0, 0) + p = tree(STORE4, + tree(ADD4, + tree(LABEL4, 0, 0), + tree(CONST4, 0, 0) ), - tree(ADD, - tree(LOAD, - tree(LABEL, 0, 0), + tree(ADD4, + tree(LOAD4, + tree(LABEL4, 0, 0), 0 ), - tree(CONST, 0, 0) + tree(CONST4, 0, 0) ) ); burm_label(p); diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index f9a51c904..dc0bc0b3d 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -29,20 +29,19 @@ static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { } #endif %} -%term LOAD STORE LABEL CONST ADD FOO BAR BAZ BOO; %% - stm = STORE(addr:address, value:reg) + stm = STORE4(addr:address, value:reg) ins value:GPR emit "str %value, %addr" cost 4; - reg = LOAD(addr:address) + reg = LOAD4(addr:address) outs dest:ANY emit "ld %dest, %addr" cost 4; - address = ADD(addr:reg, offset:CONST) + address = ADD4(addr:reg, offset:CONST) ins addr:GPR fragment "[%addr, #%offset.ivalue]"; @@ -52,19 +51,19 @@ static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { stm = reg; - reg = ADD(left:reg, right:aluparam) + reg = ADD4(left:reg, right:aluparam) ins left:GPR, right:GPR outs out:GPR emit "add %out, %left, %right" cost 4; - reg = ADD(left:aluparam, right:reg) + reg = ADD4(left:aluparam, right:reg) ins left:GPR, right:GPR outs out:GPR emit "add %out, %right, %left" cost 4; - aluparam = value:CONST + aluparam = value:CONST4 when { return false; } fragment "#%value.ivalue"; @@ -75,12 +74,12 @@ static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { emit "mov %out, %value" cost 4; - reg = value:LABEL + reg = value:LABEL4 outs out:GPR emit "adr %out, #value.lvalue" cost 4; - reg = value:CONST + reg = value:CONST4 outs out:GPR emit "ldr %out, #value.lvalue" cost 4; diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index a7d3cfde3..8afdbc0a9 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -10,6 +10,28 @@ yacc { srcs = { "./*.y" }, } +normalrule { + name = "ircodes", + outleaves = { "ircodes.h", "ircodes.c" }, + ins = { + "./ircodes.sh", + "./ir.dat" + }, + commands = { + "%{ins[1]} %{ins[2]} %{outs[1]} %{outs[2]}" + } +} + +clibrary { + name = "lib", + srcs = { + matching(filenamesof("+ircodes"), "%.c$") + }, + hdrs = { + matching(filenamesof("+ircodes"), "%.h$") + } +} + cprogram { name = "mcgg", srcs = { @@ -19,6 +41,7 @@ cprogram { }, deps = { "./*.h", + "+lib", "+yacc" } } @@ -51,7 +74,7 @@ definerule("mcgg", cpptable }, commands = { - "%{ins[1]} < %{ins[2]} > %{outs}", + "%{ins[1]} -i %{ins[2]} -o %{outs}", } } end diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 05dd6c4ed..b4ef1442e 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -6,7 +6,9 @@ #include #include #include +#include #include "iburg.h" +#include "ircodes.h" static char rcsid[] = "$Id$"; @@ -23,6 +25,7 @@ static int nrules; static void print(char* fmt, ...); static void ckreach(Nonterm p); +static void registerterminals(void); static void emitclosure(Nonterm nts); static void emitcost(Tree t, char* v); static void emitcostcalc(Rule r); @@ -52,9 +55,12 @@ int main(int argc, char* argv[]) yydebug = 1; #endif + infp = stdin; + outfp = stdout; + for (;;) { - int opt = getopt(argc, argv, "p:"); + int opt = getopt(argc, argv, "p:i:o:"); if (opt == -1) break; @@ -64,16 +70,32 @@ int main(int argc, char* argv[]) prefix = optarg; break; + case 'i': + infp = fopen(optarg, "r"); + if (!infp) + { + yyerror("cannot open input file: %s\n", strerror(errno)); + exit(1); + } + break; + + case 'o': + outfp = fopen(optarg, "w"); + if (!outfp) + { + yyerror("cannot open output file: %s\n", strerror(errno)); + exit(1); + } + break; + default: yyerror("usage: %s [-p prefix] < input > output\n", argv[0]); exit(1); } } - infp = stdin; - outfp = stdout; - emitheader(); + registerterminals(); yyin = infp; yyparse(); @@ -126,6 +148,32 @@ char* stringf(char* fmt, ...) return p; } +static void registerterminal(const char* name, int iropcode, int size) +{ + const char* s = (size == 0) ? name : stringf("%s%d", name, size); + int esn = ir_to_esn(iropcode, size); + + term(s, esn); +} + +static void registerterminals(void) +{ + int i; + + for (i=0; ikind = TERM; diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 5c5334c79..59bbfd7d8 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -86,4 +86,15 @@ extern int yylineno; extern void printlineno(void); +/* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit. + * + * Sizes are mapped as: 0=1, 1=1, 2=2, 4=3, 8=4. + */ +#define ir_to_esn(iropcode, size) \ + ((iropcode)*4 + \ + (((size) == 4) ? 2 : \ + ((size) == 8) ? 3 : \ + ((size) == 0) ? 0 : \ + (size-1))) + #endif diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat new file mode 100644 index 000000000..95059a650 --- /dev/null +++ b/util/mcgg/ir.dat @@ -0,0 +1,74 @@ +# Flags: +# S: has size (use in CONST1, CONST2, CONST4, CONST8 forms) +# V: has no size (use in JUMP, CJUMP, RET forms) + +# Simple terminals +S CONST +S REG +S LABEL +S BLOCK +S PAIR +S ANY +S LOCAL +S PHI + +# Magic stack operations +S PUSH +S POP + +# Memory operations +S LOAD +S STORE + +# Arithemetic operations +S ADD +S SUB +S MUL +S DIV +S MOD +S NEG + +S ADDF +S SUBF +S MULF +S DIVF +S NEGF + +S AND +S OR +S EOR +S NOT + +# Conversions +S CII1 +S CII2 +S CII4 +S CII8 + +S CIU1 +S CIU2 +S CIU4 +S CIU8 + +# Tristate comparisons +S COMPARES +S COMPAREU + +# Boolean comparisons +S IFEQ +S IFLT +S IFLE + +# Procedures +V CALL + +# Flow control --- these never return +V JUMP +V CJUMP +V RET + +# Special +S STACKADJUST +S GETRET +S SETRET + diff --git a/util/mcgg/ircodes.sh b/util/mcgg/ircodes.sh new file mode 100755 index 000000000..1e382e7a2 --- /dev/null +++ b/util/mcgg/ircodes.sh @@ -0,0 +1,61 @@ +#!/bin/sh + +in=$1 +header=$2 +source=$3 + +awk -f - $in >$header << "EOF" + BEGIN { + print "enum ir_opcode {" + } + + /^ *[^# ]+/ { + print "\tIR_" $2 "," + } + + END { + print "\tIR__COUNT" + print "};" + print "" + print "enum {" + print "\tIRF_SIZED = 1" + print "};" + print "" + print "extern const char* ir_names[IR__COUNT];" + print "extern const char ir_flags[IR__COUNT];" + } +EOF + +awk -f - $in >$source << "EOF" + BEGIN { + print "#include \"ircodes.h\"" + print "const char* ir_names[IR__COUNT] = {" + } + + /^ *[^# ]+/ { + printf("\t\"%s\",\n", $2) + } + + END { + print "};" + } +EOF + +awk -f - $in >>$source << "EOF" + BEGIN { + print "" + print "const char ir_flags[IR__COUNT] = {" + } + + /^ *[^# ]+/ { + if ($1 == "S") + print("\tIRF_SIZED,") + else + print("\t0,") + } + + END { + print "};" + } +EOF + From c8fcbe282ac501860b68c510aed6ab8d84d026c0 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 19:03:55 +0200 Subject: [PATCH 024/230] More grammar changes. --- mach/proto/mcg/table | 37 ++--------------------- util/mcgg/gram.y | 72 +++++++++----------------------------------- util/mcgg/iburg.c | 15 ++++++--- util/mcgg/iburg.h | 2 +- 4 files changed, 29 insertions(+), 97 deletions(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index dc0bc0b3d..daf0fbbad 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,37 +1,6 @@ -%{ -#if 0 -#include -#include -#include -#include +PATTERNS -#define TRACE - -#define STATE_TYPE void* -typedef struct tree { - int op; - struct tree *kids[2]; - STATE_TYPE state_label; -} *NODEPTR_TYPE; -#define OP_LABEL(p) ((p)->op) -#define LEFT_CHILD(p) ((p)->kids[0]) -#define RIGHT_CHILD(p) ((p)->kids[1]) -#define STATE_LABEL(p) ((p)->state_label) -#define PANIC printf - -static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { -#ifdef TRACE - extern const char *burm_string[]; - - fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p, - burm_string[eruleno], cost, bestcost); -#endif -} -#endif -%} -%% - - stm = STORE4(addr:address, value:reg) + STORE4(addr:address, value:reg) ins value:GPR emit "str %value, %addr" cost 4; @@ -49,7 +18,7 @@ static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { ins addr:GPR fragment "[%addr]"; - stm = reg; + reg; reg = ADD4(left:reg, right:aluparam) ins left:GPR, right:GPR diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 5f100c7d2..82f8de7e1 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -7,14 +7,14 @@ #define YYDEBUG 1 static char rcsid[] = "$Id$"; -static int nextesn = 0; -static int nextern = 0; +static int nextern = 1; %} %union { int n; char* string; Tree tree; + Rule rule; Stringlist stringlist; char* stringpair[2]; } @@ -36,37 +36,16 @@ static int nextern = 0; %token STRING %type cost -%type lhs +%type pattern %type stringlist %type when %type rhs %type labelledid %% spec - : decls PPERCENT patterns - | decls + : PATTERNS patterns ; -decls : /* lambda */ - | decls decl - ; - -decl - : TERMINAL blist ';' - | START lhs ';' - { - if (nonterm($2)->number != 1) - yyerror("redeclaration of the start symbol\n"); - } - | ';' - | error ';' { yyerrok; } - ; - -blist - : /* nothing */ - | blist ID { term($2, nextesn++); } - ; - patterns : /* nothing */ | patterns pattern ';' @@ -75,13 +54,16 @@ patterns ; pattern - : lhs '=' rhs when ins outs emits cost { rule($1, $3, nextern++, $4, $8); } + : ID '=' rhs { nonterm($1); $$ = rule($1, $3, nextern++); } + | rhs { $$ = rule("stmt", $1, nextern++); } + | pattern WHEN stringlist { $$ = $1; $$->when = $3; } + | pattern INS ins { $$ = $1; } + | pattern OUTS outs { $$ = $1; } + | pattern EMIT STRING { $$ = $1; } + | pattern FRAGMENT STRING { $$ = $1; } + | pattern COST INT { $$ = $1; $$->cost = $3; } ; -lhs - : ID { $$ = $1; nonterm($$); } - ; - rhs : labelledid { $$ = tree($1[1], $1[0], NULL, NULL); } | labelledid '(' rhs ')' { $$ = tree($1[1], $1[0], $3, NULL); } @@ -104,12 +86,7 @@ stringlist ; ins - : /* nothing */ - | INS inslist - ; - -inslist - : inslist ',' in + : ins ',' in | in ; @@ -118,12 +95,7 @@ in ; outs - : /* nothing */ - | OUTS outslist - ; - -outslist - : outslist ',' out + : outs ',' out | out ; @@ -131,22 +103,6 @@ out : ID ':' ID ; -emits - : /* nothing */ - | EMIT STRING - | FRAGMENT STRING - ; - -cost - : /* lambda */ { $$ = 0; } - | COST INT { - if ($2 > maxcost) { - yyerror("%d exceeds maximum cost of %d\n", $2, maxcost); - $$ = maxcost; - } else - $$ = $2; - } - ; %% #include #include diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index b4ef1442e..e581b7b90 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -60,7 +60,7 @@ int main(int argc, char* argv[]) for (;;) { - int opt = getopt(argc, argv, "p:i:o:"); + int opt = getopt(argc, argv, "p:i:o:y"); if (opt == -1) break; @@ -88,6 +88,13 @@ int main(int argc, char* argv[]) } break; + case 'y': + { + extern int yydebug; + yydebug = 1; + break; + } + default: yyerror("usage: %s [-p prefix] < input > output\n", argv[0]); exit(1); @@ -97,6 +104,8 @@ int main(int argc, char* argv[]) emitheader(); registerterminals(); + start = nonterm("stmt"); + yyin = infp; yyparse(); @@ -308,14 +317,13 @@ Tree tree(const char* id, const char* label, Tree left, Tree right) } /* rule - create & initialize a rule with the given fields */ -Rule rule(char* id, Tree pattern, int ern, Stringlist when, int cost) +Rule rule(char* id, Tree pattern, int ern) { Rule r = calloc(1, sizeof *r); Rule *q; Term p = pattern->op; nrules++; - r->when = when; r->lhs = nonterm(id); r->packed = ++r->lhs->lhscount; for (q = &r->lhs->rules; *q; q = &(*q)->decode) @@ -323,7 +331,6 @@ Rule rule(char* id, Tree pattern, int ern, Stringlist when, int cost) *q = r; r->pattern = pattern; r->ern = ern; - r->cost = cost; if (p->kind == TERM) { r->next = p->rules; diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 59bbfd7d8..59c84a3ea 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -68,7 +68,7 @@ struct rule Rule kids; /* next rule with same burm_kids pattern */ Stringlist when; /* C predicate string */ }; -extern Rule rule(char* id, Tree pattern, int ern, Stringlist when, int cost); +extern Rule rule(char* id, Tree pattern, int ern); extern int maxcost; /* maximum cost */ /* gram.y: */ From 629e0ddfc61cbd0a5f873cceb361989faed9ce52 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 22:46:08 +0200 Subject: [PATCH 025/230] Some instruction selection is now happening. --- mach/proto/mcg/ir.h | 4 + mach/proto/mcg/main.c | 3 +- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/mcgg_generated_footer.h | 2 + mach/proto/mcg/mcgg_generated_header.h | 38 ++++----- mach/proto/mcg/pass_instsel.c | 87 +++++++++++++++++++++ mach/proto/mcg/procedure.c | 2 + mach/proto/mcg/table | 104 ++++++++++++++++++++++++- mach/proto/mcg/treebuilder.c | 16 ++-- util/mcgg/build.lua | 5 +- util/mcgg/iburg.c | 8 +- util/mcgg/iburg.h | 11 +-- util/mcgg/ir.dat | 6 +- util/mcgg/mcgg.h | 30 +++++++ util/mcgg/scan.l | 2 +- 15 files changed, 264 insertions(+), 55 deletions(-) create mode 100644 mach/proto/mcg/pass_instsel.c create mode 100644 util/mcgg/mcgg.h diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 795b6dd6d..eaf031475 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -33,7 +33,11 @@ struct ir const char* lvalue; struct basicblock* bvalue; } u; + + void* state_label; /* used by the iburg instruction selector */ + bool is_sequence : 1; + bool is_generated : 1; }; extern const char* ir_names[]; diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 5be59e639..83d510107 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -37,9 +37,10 @@ bool tracing(char k) { switch (k) { + case 0: return true; case 'E': return false; case '0': return false; - case '1': return true; + case '1': return false; case '2': return true; default: return true; } diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 4fa1b1177..193ed3690 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -119,6 +119,7 @@ extern void tb_regvar(arith offset, int size, int type, int priority); extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); +extern void pass_instruction_selector(struct procedure* proc); extern void procedure_compile(struct procedure* proc); diff --git a/mach/proto/mcg/mcgg_generated_footer.h b/mach/proto/mcg/mcgg_generated_footer.h index 56bdc9168..11b40205a 100644 --- a/mach/proto/mcg/mcgg_generated_footer.h +++ b/mach/proto/mcg/mcgg_generated_footer.h @@ -19,6 +19,7 @@ static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { #endif } +#if 0 static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) { NODEPTR_TYPE p = malloc(sizeof *p); @@ -48,4 +49,5 @@ int main(void) { dumpCover(p, 1, 0); return 0; } +#endif diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index 2545e8af3..36e394b6c 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -1,32 +1,20 @@ -#include -#include -#include -#include -#include -#include +#include "mcg.h" +#include "mcgg.h" -#define TRACE -#define STATE_TYPE void* -typedef struct tree { - int op; - struct tree *kids[2]; - STATE_TYPE state_label; -} *NODEPTR_TYPE; -#define OP_LABEL(p) ((p)->op) -#define LEFT_CHILD(p) ((p)->kids[0]) -#define RIGHT_CHILD(p) ((p)->kids[1]) -#define STATE_LABEL(p) ((p)->state_label) #define PANIC printf -static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) { -#ifdef TRACE - extern const char *burm_string[]; - - fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p, - burm_string[eruleno], cost, bestcost); -#endif +static int OP_LABEL(struct ir* ir) +{ + if (ir->is_generated) + return ir_to_esn(IR_REG, ir->size); + return ir_to_esn(ir->opcode, ir->size); } -#define burm_assert(b, s) assert(b && s) +#define LEFT_CHILD(p) ((p)->left) +#define RIGHT_CHILD(p) ((p)->right) + +#define burm_assert(b, s) assert(b) + +extern void burm_panic_cannot_match(struct ir* ir); diff --git a/mach/proto/mcg/pass_instsel.c b/mach/proto/mcg/pass_instsel.c new file mode 100644 index 000000000..8d1fa4718 --- /dev/null +++ b/mach/proto/mcg/pass_instsel.c @@ -0,0 +1,87 @@ +#include "mcg.h" +#include "mcgg.h" + +#if 0 +static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { +#ifdef TRACE + int eruleno = burm_rule(STATE_LABEL(p), goalnt); + const short *nts = burm_nts[eruleno]; + NODEPTR_TYPE kids[10]; + int i; + + for (i = 0; i < indent; i++) + fprintf(stderr, " "); + fprintf(stderr, "%s\n", burm_string[eruleno]); + burm_kids(p, eruleno, kids); + for (i = 0; nts[i]; i++) + { + if (kids[i]) + dumpCover(kids[i], nts[i], indent + 1); + else + fprintf(stderr, "failed!\n"); + } +#endif +} +#endif + +void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) { + tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p, + burm_string[ruleno], cost, bestcost); +} + +void burm_panic_cannot_match(struct ir* ir) +{ + fprintf(stderr, "could not find any patterns to match:\n"); + ir_print(0, ir); + fprintf(stderr, "aborting!\n"); + exit(1); +} + +static void queue_instructions(struct ir* ir, int goal) +{ + struct ir* children[10]; + int ruleno = burm_rule(ir->state_label, goal); + const short* nts = burm_nts[ruleno]; + int i; + + burm_kids(ir, ruleno, children); + for (i=0; nts[i]; i++) + queue_instructions(children[i], nts[i]); + + printf("selected insn %d: %s\n", ruleno, burm_string[ruleno]); +} + +static void select_instructions(struct basicblock* bb) +{ + int i; + + tracef('I', "I: BLOCK: %s\n", bb->name); + + for (i=0; iirs_count; i++) + { + int insnno; + struct ir* ir = bb->irs[i]; + burm_label(ir); + + insnno = burm_rule(ir->state_label, 1); + if (!insnno) + burm_panic_cannot_match(ir); + + queue_instructions(ir, 1); + } +} + +void pass_instruction_selector(struct procedure* proc) +{ + int i; + + for (i=0; iblocks_count; i++) + { + struct basicblock* bb = proc->blocks[i]; + select_instructions(bb); + } + exit(1); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 8958a8b7e..b0bc1a0e3 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -31,6 +31,8 @@ void procedure_compile(struct procedure* proc) pass_convert_stack_ops(proc); print_blocks('2', proc); + + pass_instruction_selector(proc); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index daf0fbbad..f9f468f53 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,5 +1,33 @@ PATTERNS +/* Special */ + + reg; + + PAIR(BLOCK4, BLOCK4); + + +/* Miscellaneous special things */ + + PUSH4(in:reg) + emit "push %in" + cost 4; + + reg = POP4 + outs out:ANY + emit "pop %out" + cost 4; + + RET + emit "ret" + cost 4; + + SETRET4(in:reg) + emit "mov r0, %in" + cost 4; + +/* Memory operations */ + STORE4(addr:address, value:reg) ins value:GPR emit "str %value, %addr" @@ -7,9 +35,33 @@ PATTERNS reg = LOAD4(addr:address) outs dest:ANY - emit "ld %dest, %addr" + emit "ldr %dest, %addr" cost 4; + reg = LOAD1(addr:address) + outs dest:ANY + emit "ldrb %dest, %addr" + cost 4; + + reg = CIU14(LOAD1(addr:address)) + outs dest:ANY + emit "ldrb %dest, %addr" + cost 4; + + +/* Locals */ + + reg = in:LOCAL4 + outs out:GPR + emit "add %out, fp, #%in.ivalue" + cost 4; + + address = in:LOCAL4 + fragment "[fp, #%in.ivalue]"; + + +/* Memory addressing modes */ + address = ADD4(addr:reg, offset:CONST) ins addr:GPR fragment "[%addr, #%offset.ivalue]"; @@ -18,7 +70,47 @@ PATTERNS ins addr:GPR fragment "[%addr]"; - reg; + +/* Branches */ + + JUMP(addr:BLOCK4) + emit "b %addr.bvalue" + cost 4; + + CJUMPEQ(value:tristate, PAIR(true:BLOCK4, false:BLOCK4)) + emit "beq %trueblock.bvalue" + emit "bne %falseblock.bvalue" + cost 8; + + +/* Comparisons */ + + tristate = COMPARES4(val1:reg, val2:aluparam) + outs CC + emit "cmp %val1, %val2" + cost 4; + + reg = tristate + emit "mov %out, #0" + emit "movlt %out, #-1" + emit "movgt %out, #1" + cost 12; + + +/* Conversions */ + + reg = CII14(CIU41(value:reg)) + outs out:GPR + emit "sxtb %out, %value" + cost 4; + + reg = CIU41(in:reg) + outs out:GPR + emit "and %out, %in, #0xff" + cost 4; + + +/* ALU operations */ reg = ADD4(left:reg, right:aluparam) ins left:GPR, right:GPR @@ -33,7 +125,6 @@ PATTERNS cost 4; aluparam = value:CONST4 - when { return false; } fragment "#%value.ivalue"; aluparam = reg; @@ -45,7 +136,12 @@ PATTERNS reg = value:LABEL4 outs out:GPR - emit "adr %out, #value.lvalue" + emit "adr %out, %value.lvalue" + cost 4; + + reg = value:BLOCK4 + outs out:GPR + emit "adr %out, %value.bvalue" cost 4; reg = value:CONST4 diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index ea699d720..1b0d51da5 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -231,9 +231,9 @@ static void simple_branch2(int opcode, int size, materialise_stack(); appendir( new_ir2( - IR_CJUMP, 0, + irop, 0, new_ir2( - irop, size, + IR_COMPARES, size, left, right ), new_ir2( @@ -260,13 +260,13 @@ static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock { switch (opcode) { - case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_IFEQ); break; - case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_IFLT); break; - case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_IFLE); break; + case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPEQ); break; + case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPLT); break; + case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPLE); break; - case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_IFEQ); break; - case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_IFLT); break; - case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_IFLE); break; + case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPEQ); break; + case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLT); break; + case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLE); break; case op_bra: { diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index 8afdbc0a9..0485197a9 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -28,7 +28,8 @@ clibrary { matching(filenamesof("+ircodes"), "%.c$") }, hdrs = { - matching(filenamesof("+ircodes"), "%.h$") + matching(filenamesof("+ircodes"), "%.h$"), + "./mcgg.h" } } @@ -40,7 +41,7 @@ cprogram { matching(filenamesof("+yacc"), "%.c$") }, deps = { - "./*.h", + "./iburg.h", "+lib", "+yacc" } diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index e581b7b90..c26cfeef7 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -419,7 +419,7 @@ static void print(char* fmt, ...) void printlineno(void) { - print("#line %d\n", yylineno); + //print("#line %d\n", yylineno); } /* reach - mark all non-terminals in tree t as reachable */ @@ -451,6 +451,9 @@ static void emitcase(Term p, int ntnumber) { Rule r; + if (!p->rules) + return; + print("%1case %d: /* %S */\n", p->esn, p); switch (p->arity) { @@ -823,7 +826,8 @@ static void emitstate(Term terms, Nonterm start, int ntnumber) for (p = terms; p; p = p->link) emitcase(p, ntnumber); print("%1default:\n" - "%2%Passert(0, PANIC(\"Bad operator %%d in %Pstate\\n\", op));\n%1}\n" + "%2%Ppanic_cannot_match(node);\n" + "%1}\n" "%1return (STATE_TYPE)p;\n}\n\n"); } diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 59c84a3ea..0ad0fdeea 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -86,15 +86,6 @@ extern int yylineno; extern void printlineno(void); -/* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit. - * - * Sizes are mapped as: 0=1, 1=1, 2=2, 4=3, 8=4. - */ -#define ir_to_esn(iropcode, size) \ - ((iropcode)*4 + \ - (((size) == 4) ? 2 : \ - ((size) == 8) ? 3 : \ - ((size) == 0) ? 0 : \ - (size-1))) +#include "mcgg.h" #endif diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 95059a650..a7487cda0 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -7,7 +7,7 @@ S CONST S REG S LABEL S BLOCK -S PAIR +V PAIR S ANY S LOCAL S PHI @@ -64,7 +64,9 @@ V CALL # Flow control --- these never return V JUMP -V CJUMP +V CJUMPEQ +V CJUMPLT +V CJUMPLE V RET # Special diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h new file mode 100644 index 000000000..297be186b --- /dev/null +++ b/util/mcgg/mcgg.h @@ -0,0 +1,30 @@ +#ifndef MCGG_H +#define MCGG_H + +/* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit. + * + * Sizes are mapped as: 0=1, 1=1, 2=2, 4=3, 8=4. + */ +#define ir_to_esn(iropcode, size) \ + ((iropcode)*4 + \ + (((size) == 4) ? 2 : \ + ((size) == 8) ? 3 : \ + ((size) == 0) ? 0 : \ + (size-1))) + + +#define STATE_TYPE void* +typedef struct ir* NODEPTR_TYPE; + +#define STATE_LABEL(p) ((p)->state_label) + +extern void* burm_label(struct ir* ir); +extern int burm_rule(void* state, int goalnt); +extern const char* burm_string[]; +extern const short *burm_nts[]; +extern struct ir** burm_kids(struct ir* p, int eruleno, struct ir* kids[]); +extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index ebcb9c107..0e0a92cd4 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -22,7 +22,7 @@ static int braces = 0; [^%\n]* fputs(yytext, outfp); "{" { - yylval.string = stringf("#line %d\n", yylineno); + yylval.string = ""; //stringf("#line %d\n", yylineno); braces = 1; BEGIN(CSTRING); return CFRAGMENT; From 717b77dd0a521fb7217d1e106c3d0c919aa1654a Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 24 Sep 2016 22:50:53 +0200 Subject: [PATCH 026/230] Instruction selection is so important the file needs a longer name. --- mach/proto/mcg/{pass_instsel.c => pass_instructionselection.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mach/proto/mcg/{pass_instsel.c => pass_instructionselection.c} (100%) diff --git a/mach/proto/mcg/pass_instsel.c b/mach/proto/mcg/pass_instructionselection.c similarity index 100% rename from mach/proto/mcg/pass_instsel.c rename to mach/proto/mcg/pass_instructionselection.c From 7c028bdd45b85dd302cd260a01eeced6eb967296 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 25 Sep 2016 00:21:46 +0200 Subject: [PATCH 027/230] We now record the code fragments to be emitted by each rule. --- mach/proto/mcg/pass_instructionselection.c | 2 +- mach/proto/mcg/table | 18 +++++----- util/mcgg/gram.y | 41 +++++++++++++--------- util/mcgg/iburg.c | 12 ++++++- util/mcgg/iburg.h | 2 ++ util/mcgg/scan.l | 23 ++++++++---- 6 files changed, 63 insertions(+), 35 deletions(-) diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 8d1fa4718..e54b6ea75 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -48,7 +48,7 @@ static void queue_instructions(struct ir* ir, int goal) for (i=0; nts[i]; i++) queue_instructions(children[i], nts[i]); - printf("selected insn %d: %s\n", ruleno, burm_string[ruleno]); + tracef('I', "I: $%d selected insn %d: %s\n", ir->id, ruleno, burm_string[ruleno]); } static void select_instructions(struct basicblock* bb) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index f9f468f53..b32d43210 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -53,18 +53,18 @@ PATTERNS reg = in:LOCAL4 outs out:GPR - emit "add %out, fp, #%in.ivalue" + emit "add %out, fp, #%in" cost 4; address = in:LOCAL4 - fragment "[fp, #%in.ivalue]"; + fragment "[fp, #%in]"; /* Memory addressing modes */ address = ADD4(addr:reg, offset:CONST) ins addr:GPR - fragment "[%addr, #%offset.ivalue]"; + fragment "[%addr, #%offset]"; address = addr:reg ins addr:GPR @@ -74,12 +74,12 @@ PATTERNS /* Branches */ JUMP(addr:BLOCK4) - emit "b %addr.bvalue" + emit "b %addr" cost 4; CJUMPEQ(value:tristate, PAIR(true:BLOCK4, false:BLOCK4)) - emit "beq %trueblock.bvalue" - emit "bne %falseblock.bvalue" + emit "beq %true" + emit "bne %false" cost 8; @@ -136,15 +136,15 @@ PATTERNS reg = value:LABEL4 outs out:GPR - emit "adr %out, %value.lvalue" + emit "adr %out, %value" cost 4; reg = value:BLOCK4 outs out:GPR - emit "adr %out, %value.bvalue" + emit "adr %out, %value" cost 4; reg = value:CONST4 outs out:GPR - emit "ldr %out, #value.lvalue" + emit "ldr %out, #value" cost 4; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 82f8de7e1..369c65ef3 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -1,12 +1,14 @@ %{ #include #include +#include #include #include "iburg.h" #define YYDEBUG 1 -static char rcsid[] = "$Id$"; +extern int yylex(void); + static int nextern = 1; %} @@ -33,15 +35,16 @@ static int nextern = 1; %token INT %token ID %token CFRAGMENT -%token STRING +%token QFRAGMENT -%type cost %type pattern -%type stringlist -%type when +%type emit +%type cfragments +%type qfragments %type rhs %type labelledid %% + spec : PATTERNS patterns ; @@ -50,17 +53,15 @@ patterns : /* nothing */ | patterns pattern ';' | patterns ';' - | patterns error ';' { yyerrok; } ; pattern : ID '=' rhs { nonterm($1); $$ = rule($1, $3, nextern++); } | rhs { $$ = rule("stmt", $1, nextern++); } - | pattern WHEN stringlist { $$ = $1; $$->when = $3; } + | pattern WHEN cfragments { $$ = $1; $$->when = $3; } | pattern INS ins { $$ = $1; } | pattern OUTS outs { $$ = $1; } - | pattern EMIT STRING { $$ = $1; } - | pattern FRAGMENT STRING { $$ = $1; } + | emit { $$ = $1; } | pattern COST INT { $$ = $1; $$->cost = $3; } ; @@ -75,14 +76,9 @@ labelledid | ID ':' ID { $$[0] = $1; $$[1] = $3; } ; -when +cfragments : /* nothing */ { $$ = NULL; } - | WHEN stringlist { $$ = $2; } - ; - -stringlist - : /* nothing */ { $$ = NULL; } - | CFRAGMENT stringlist { $$ = pushstring($1, $2); } + | CFRAGMENT cfragments { $$ = pushstring($1, $2); } ; ins @@ -100,7 +96,18 @@ outs ; out - : ID ':' ID + : ID + | ID ':' ID + ; + +emit + : pattern EMIT qfragments { $$ = $1; $$->code = $3; $$->is_fragment = false; } + | pattern FRAGMENT qfragments { $$ = $1; $$->code = $3; $$->is_fragment = true; } + ; + +qfragments + : QFRAGMENT { $$ = pushstring($1, NULL); } + | QFRAGMENT qfragments { $$ = pushstring($1, $2); } ; %% diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index c26cfeef7..cbbfab50a 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,8 @@ static void emitstruct(Nonterm nts, int ntnumber); static void emitterms(Term terms); static void emittest(Tree t, char* v, char* suffix); +extern int yy_flex_debug; + int main(int argc, char* argv[]) { int c, i; @@ -57,10 +60,11 @@ int main(int argc, char* argv[]) infp = stdin; outfp = stdout; + yy_flex_debug = 0; for (;;) { - int opt = getopt(argc, argv, "p:i:o:y"); + int opt = getopt(argc, argv, "p:i:o:yf"); if (opt == -1) break; @@ -95,6 +99,12 @@ int main(int argc, char* argv[]) break; } + case 'f': + { + yy_flex_debug = 1; + break; + } + default: yyerror("usage: %s [-p prefix] < input > output\n", argv[0]); exit(1); diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 0ad0fdeea..361cdba33 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -67,6 +67,8 @@ struct rule Rule decode; /* next rule with same lhs */ Rule kids; /* next rule with same burm_kids pattern */ Stringlist when; /* C predicate string */ + Stringlist code; /* compiler output code strings */ + bool is_fragment; /* does this rule generate an instruction fragment? */ }; extern Rule rule(char* id, Tree pattern, int ern); extern int maxcost; /* maximum cost */ diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 0e0a92cd4..941830c73 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -1,4 +1,5 @@ %{ +#include #include "iburg.h" #include "y.tab.h" @@ -9,18 +10,14 @@ static int braces = 0; %option nodefault %option noyywrap %option yylineno +%option debug %x CSTRING +%x QSTRING %x ECHO %% -"%{" { printlineno(); BEGIN(ECHO); } - -"%}" BEGIN(INITIAL); -[%\n] fputc(yytext[0], outfp); -[^%\n]* fputs(yytext, outfp); - "{" { yylval.string = ""; //stringf("#line %d\n", yylineno); braces = 1; @@ -50,6 +47,19 @@ static int braces = 0; return CFRAGMENT; } +"\"" BEGIN(QSTRING); +"\"" BEGIN(INITIAL); + +%[a-zA-Z_]+ { + yylval.string = strdup(yytext); + return QFRAGMENT; + } + +[^\r\n%"]+ { + yylval.string = strdup(yytext); + return QFRAGMENT; + } + "%%" return PPERCENT; "%term" return TERMINAL; "%start" return START; @@ -62,7 +72,6 @@ static int braces = 0; "fragment" return FRAGMENT; "cost" return COST; -\"[^"\n]*\" { yylval.string = strdup(yytext); return STRING; } [A-Za-z_][A-Za-z0-9_]* { yylval.string = strdup(yytext); return ID; } [0-9]+ { yylval.n = atoi(yytext); return INT; } [ \t\r\n]* ; From 9f78e0b36b2949b603839d76e9052f571e98ad95 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 25 Sep 2016 11:49:51 +0200 Subject: [PATCH 028/230] Rethink the way patterns are mapped to rules; generate emitters (probably badly). --- mach/proto/mcg/table | 54 +++++++------------- util/mcgg/build.lua | 8 +-- util/mcgg/iburg.c | 114 +++++++++++++++++++++++++++++++++++++++++++ util/mcgg/iburg.h | 1 + util/mcgg/mcgg.h | 10 ++++ util/mcgg/scan.l | 11 ++++- 6 files changed, 153 insertions(+), 45 deletions(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index b32d43210..efaffdc36 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -14,8 +14,7 @@ PATTERNS cost 4; reg = POP4 - outs out:ANY - emit "pop %out" + emit "pop %reg" cost 4; RET @@ -29,31 +28,26 @@ PATTERNS /* Memory operations */ STORE4(addr:address, value:reg) - ins value:GPR emit "str %value, %addr" cost 4; reg = LOAD4(addr:address) - outs dest:ANY - emit "ldr %dest, %addr" + emit "ldr %reg, %addr" cost 4; reg = LOAD1(addr:address) - outs dest:ANY - emit "ldrb %dest, %addr" + emit "ldrb %reg, %addr" cost 4; reg = CIU14(LOAD1(addr:address)) - outs dest:ANY - emit "ldrb %dest, %addr" + emit "ldrb %reg, %addr" cost 4; /* Locals */ reg = in:LOCAL4 - outs out:GPR - emit "add %out, fp, #%in" + emit "add %reg, fp, #%in" cost 4; address = in:LOCAL4 @@ -63,11 +57,9 @@ PATTERNS /* Memory addressing modes */ address = ADD4(addr:reg, offset:CONST) - ins addr:GPR fragment "[%addr, #%offset]"; address = addr:reg - ins addr:GPR fragment "[%addr]"; @@ -85,43 +77,37 @@ PATTERNS /* Comparisons */ - tristate = COMPARES4(val1:reg, val2:aluparam) + tristate = COMPARES4(left:reg, right:aluparam) outs CC - emit "cmp %val1, %val2" + emit "cmp %left, %right" cost 4; reg = tristate - emit "mov %out, #0" - emit "movlt %out, #-1" - emit "movgt %out, #1" + emit "mov %reg, #0" + emit "movlt %reg, #-1" + emit "movgt %reg, #1" cost 12; /* Conversions */ reg = CII14(CIU41(value:reg)) - outs out:GPR - emit "sxtb %out, %value" + emit "sxtb %reg, %value" cost 4; reg = CIU41(in:reg) - outs out:GPR - emit "and %out, %in, #0xff" + emit "and %reg, %in, #0xff" cost 4; /* ALU operations */ reg = ADD4(left:reg, right:aluparam) - ins left:GPR, right:GPR - outs out:GPR - emit "add %out, %left, %right" + emit "add %reg, %left, %right" cost 4; reg = ADD4(left:aluparam, right:reg) - ins left:GPR, right:GPR - outs out:GPR - emit "add %out, %right, %left" + emit "add %reg, %right, %left" cost 4; aluparam = value:CONST4 @@ -130,21 +116,17 @@ PATTERNS aluparam = reg; reg = value:aluparam - outs out:GPR - emit "mov %out, %value" + emit "mov %reg, %value" cost 4; reg = value:LABEL4 - outs out:GPR - emit "adr %out, %value" + emit "adr %reg, %value" cost 4; reg = value:BLOCK4 - outs out:GPR - emit "adr %out, %value" + emit "adr %reg, %value" cost 4; reg = value:CONST4 - outs out:GPR - emit "ldr %out, #value" + emit "ldr %reg, #value" cost 4; diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index 0485197a9..ee230d73a 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -58,12 +58,6 @@ definerule("mcgg", error("you must supply exactly one input file") end - local cpptable = cppfile { - name = e.name.."/cpptable", - outleaf = "cpptable", - srcs = e.srcs - } - return normalrule { name = e.name, cwd = e.cwd, @@ -72,7 +66,7 @@ definerule("mcgg", }, ins = { "util/mcgg+mcgg", - cpptable + e.srcs[1] }, commands = { "%{ins[1]} -i %{ins[2]} -o %{outs}", diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index cbbfab50a..52df9cc31 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ static void emitnts(Rule rules, int nrules); static void emitrecord(char* pre, Rule r, int cost); static void emitrule(Nonterm nts); static void emitpredicatedefinitions(Rule rules); +static void emitemitters(Rule rules); static void emitstate(Term terms, Nonterm start, int ntnumber); static void emitstring(Rule rules); static void emitstruct(Nonterm nts, int ntnumber); @@ -133,6 +135,7 @@ int main(int argc, char* argv[]) emitrule(nts); emitclosure(nts); emitpredicatedefinitions(rules); + emitemitters(rules); if (start) emitstate(terms, start, ntnumber); print("#ifdef STATE_LABEL\n"); @@ -334,6 +337,7 @@ Rule rule(char* id, Tree pattern, int ern) Term p = pattern->op; nrules++; + r->lineno = yylineno; r->lhs = nonterm(id); r->packed = ++r->lhs->lhscount; for (q = &r->lhs->rules; *q; q = &(*q)->decode) @@ -791,6 +795,7 @@ static void emitpredicatedefinitions(Rule r) Stringlist s = r->when; if (s) { + print("/* %R */\n", r); print("static int %Ppredicate_%d(NODEPTR_TYPE n) {\n", r->ern); while (s) { @@ -803,6 +808,115 @@ static void emitpredicatedefinitions(Rule r) } } +static void emittreefetchers(uint32_t path, Tree tree) +{ + if (tree->label) + { + int i = 0; + uint32_t p = path; + print("%1NODEPTR_TYPE node_%s = ", tree->label); + while (p > 0) + { + switch (p % 3) + { + case 1: print("LEFT_CHILD("); break; + case 2: print("RIGHT_CHILD("); break; + } + p /= 3; + i++; + } + + print("node"); + + while (i > 0) + { + print(")"); + i--; + } + + print(";\n"); + } + + if (tree->left) + emittreefetchers(path*3 + 1, tree->left); + if (tree->right) + emittreefetchers(path*3 + 2, tree->right); +} + +static Tree find_label(Tree root, const char* name) +{ + Tree t; + + if (root->label && (strcmp(root->label, name) == 0)) + return root; + + t = NULL; + if (root->left && !t) + t = find_label(root->left, name); + if (root->right && !t) + t = find_label(root->right, name); + return t; +} + +/* emitemitters - emit the code generation routines */ +static void emitemitters(Rule rules) +{ + Rule r; + + r = rules; + while (r) + { + Stringlist s = r->code; + if (s) + { + print("/* %R */\n", r); + print("static void %Pemitter_%d(NODEPTR_TYPE node, struct %Pemitter_data* data) {\n", r->ern); + emittreefetchers(0, r->pattern); + print("%1NODEPTR_TYPE node_%s = node;\n", r->lhs->name); + + while (s) + { + if (s->payload[0] == '%') + { + const char* label = s->payload + 1; + Tree t = find_label(r->pattern, label); + if (!t && (strcmp(label, r->lhs->name) != 0)) + { + yylineno = r->lineno; + yyerror("label '%s' not found", label); + exit(1); + } + print("%1data->emit_ir(node_%s);\n", label); + } + else + print("%1data->emit_string(\"%s\");\n", s->payload); + + s = s->next; + } + + print("}\n\n"); + } + + r = r->link; + } + + r = rules; + print("%Pemitter_t* const %Pemitters[] = {\n"); + while (r) + { + Stringlist s = r->code; + print("%1"); + if (s) + print("&%Pemitter_%d,", r->ern); + else + print("NULL,"); + print(" /* %R */\n", r); + + r = r->link; + } + print("};\n\n"); +} + /* emitcost - emit a cost calculation via a predicate */ static void emitcostcalc(Rule r) { diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 361cdba33..0a6c90dfc 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -58,6 +58,7 @@ struct rule { /* rules: */ Nonterm lhs; /* lefthand side non-terminal */ Tree pattern; /* rule pattern */ + int lineno; /* line number where allocated */ int ern; /* external rule number */ int packed; /* packed external rule number */ int cost; /* associated cost */ diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 297be186b..10d8f5166 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -25,6 +25,16 @@ extern const short *burm_nts[]; extern struct ir** burm_kids(struct ir* p, int eruleno, struct ir* kids[]); extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost); +struct burm_emitter_data +{ + void* user; + void (*emit_string)(const char* data); + void (*emit_ir)(struct ir* ir); +}; + +typedef void burm_emitter_t(struct ir* ir, struct burm_emitter_data* data); +extern burm_emitter_t* const burm_emitters[]; + #endif /* vim: set sw=4 ts=4 expandtab : */ diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 941830c73..479a115fc 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -14,7 +14,7 @@ static int braces = 0; %x CSTRING %x QSTRING -%x ECHO +%x COMMENT %% @@ -50,7 +50,7 @@ static int braces = 0; "\"" BEGIN(QSTRING); "\"" BEGIN(INITIAL); -%[a-zA-Z_]+ { +%[a-zA-Z_][a-zA_Z_0-9]+ { yylval.string = strdup(yytext); return QFRAGMENT; } @@ -60,6 +60,11 @@ static int braces = 0; return QFRAGMENT; } +"/*" BEGIN(COMMENT); +"*/" BEGIN(INITIAL); +[^*]* ; +"*" ; + "%%" return PPERCENT; "%term" return TERMINAL; "%start" return START; @@ -72,6 +77,8 @@ static int braces = 0; "fragment" return FRAGMENT; "cost" return COST; +"//"[^\n]*\n ; + [A-Za-z_][A-Za-z0-9_]* { yylval.string = strdup(yytext); return ID; } [0-9]+ { yylval.n = atoi(yytext); return INT; } [ \t\r\n]* ; From bcc74ba18db11276c7db3d47b5e7a1bb5eda35e7 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 25 Sep 2016 12:18:39 +0200 Subject: [PATCH 029/230] Stupid stringlist is stupid. Use a proper data structure, properly abstracted out (so other things can use it). --- modules/src/data/build.lua | 9 +++++ modules/src/data/stringlist.c | 43 +++++++++++++++++++++++ modules/src/data/stringlist.h | 23 +++++++++++++ util/mcgg/build.lua | 3 +- util/mcgg/gram.y | 26 +++++++++----- util/mcgg/iburg.c | 65 ++++++++++++++++++----------------- util/mcgg/iburg.h | 39 +++++++++------------ util/mcgg/mcgg.h | 1 + 8 files changed, 146 insertions(+), 63 deletions(-) create mode 100644 modules/src/data/build.lua create mode 100644 modules/src/data/stringlist.c create mode 100644 modules/src/data/stringlist.h diff --git a/modules/src/data/build.lua b/modules/src/data/build.lua new file mode 100644 index 000000000..7250f4f72 --- /dev/null +++ b/modules/src/data/build.lua @@ -0,0 +1,9 @@ +clibrary { + name = "lib", + srcs = { "./*.c" }, + hdrs = { "./*.h" }, + deps = { + }, +} + + diff --git a/modules/src/data/stringlist.c b/modules/src/data/stringlist.c new file mode 100644 index 000000000..28322bf98 --- /dev/null +++ b/modules/src/data/stringlist.c @@ -0,0 +1,43 @@ +#include +#include "stringlist.h" + +void stringlist_add(struct stringlist* list, const char* data) +{ + struct stringfragment* f = calloc(1, sizeof *f); + f->data = data; + + if (!list->last) + list->first = list->last = f; + else + { + list->last->next = f; + list->last = f; + } +} + +void stringlist_addall(struct stringlist* list, struct stringlist* src) +{ + struct stringfragment* f = src->first; + + while (f) + { + stringlist_add(list, f->data); + f = f->next; + } +} + +void stringlist_free(struct stringlist* list) +{ + struct stringfragment* f = list->first; + + while (f) + { + struct stringfragment* next = f->next; + free(f); + f = next; + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/modules/src/data/stringlist.h b/modules/src/data/stringlist.h new file mode 100644 index 000000000..493d7ff1e --- /dev/null +++ b/modules/src/data/stringlist.h @@ -0,0 +1,23 @@ +#ifndef STRINGLIST_H +#define STRINGLIST_H + +struct stringfragment +{ + const char* data; + struct stringfragment* next; +}; + +struct stringlist +{ + struct stringfragment* first; + struct stringfragment* last; +}; + +extern void stringlist_add(struct stringlist* list, const char* data); +extern void stringlist_addall(struct stringlist* list, struct stringlist* src); +extern void stringlist_free(struct stringlist* list); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index ee230d73a..b3ffe81f6 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -43,7 +43,8 @@ cprogram { deps = { "./iburg.h", "+lib", - "+yacc" + "+yacc", + "modules/src/data+lib", } } diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 369c65ef3..e24859851 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -1,4 +1,5 @@ %{ +#include #include #include #include @@ -17,7 +18,7 @@ static int nextern = 1; char* string; Tree tree; Rule rule; - Stringlist stringlist; + struct stringlist* stringlist; char* stringpair[2]; } %term TERMINAL @@ -58,7 +59,7 @@ patterns pattern : ID '=' rhs { nonterm($1); $$ = rule($1, $3, nextern++); } | rhs { $$ = rule("stmt", $1, nextern++); } - | pattern WHEN cfragments { $$ = $1; $$->when = $3; } + | pattern WHEN cfragments { $$ = $1; stringlist_addall(&$$->when, $3); } | pattern INS ins { $$ = $1; } | pattern OUTS outs { $$ = $1; } | emit { $$ = $1; } @@ -77,8 +78,8 @@ labelledid ; cfragments - : /* nothing */ { $$ = NULL; } - | CFRAGMENT cfragments { $$ = pushstring($1, $2); } + : /* nothing */ { $$ = calloc(1, sizeof *$$); } + | cfragments CFRAGMENT { $$ = $1; stringlist_add($$, $2); } ; ins @@ -101,13 +102,22 @@ out ; emit - : pattern EMIT qfragments { $$ = $1; $$->code = $3; $$->is_fragment = false; } - | pattern FRAGMENT qfragments { $$ = $1; $$->code = $3; $$->is_fragment = true; } + : pattern EMIT qfragments { + $$ = $1; + stringlist_add($3, "\n"); + stringlist_addall(&$$->code, $3); + $$->is_fragment = false; + } + | pattern FRAGMENT qfragments { + $$ = $1; + stringlist_addall(&$$->code, $3); + $$->is_fragment = true; + } ; qfragments - : QFRAGMENT { $$ = pushstring($1, NULL); } - | QFRAGMENT qfragments { $$ = pushstring($1, $2); } + : /* nothing */ { $$ = calloc(1, sizeof *$$); } + | qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); } ; %% diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 52df9cc31..c4189f560 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -365,14 +365,6 @@ Rule rule(char* id, Tree pattern, int ern) return r; } -Stringlist pushstring(const char* data, Stringlist list) -{ - Stringlist sl = calloc(1, sizeof *sl); - sl->payload = data; - sl->next = list; - return sl; -} - /* print - formatted output */ static void print(char* fmt, ...) { @@ -792,15 +784,15 @@ static void emitpredicatedefinitions(Rule r) { while (r) { - Stringlist s = r->when; - if (s) + struct stringfragment* f = r->when.first; + if (f) { print("/* %R */\n", r); print("static int %Ppredicate_%d(NODEPTR_TYPE n) {\n", r->ern); - while (s) + while (f) { - print("%s", s->payload); - s = s->next; + print("%s", f->data); + f = f->next; } print("\n}\n\n"); } @@ -866,32 +858,42 @@ static void emitemitters(Rule rules) r = rules; while (r) { - Stringlist s = r->code; - if (s) + struct stringfragment* f = r->code.first; + if (f) { print("/* %R */\n", r); print("static void %Pemitter_%d(NODEPTR_TYPE node, struct %Pemitter_data* data) {\n", r->ern); emittreefetchers(0, r->pattern); print("%1NODEPTR_TYPE node_%s = node;\n", r->lhs->name); - while (s) + while (f) { - if (s->payload[0] == '%') + switch (f->data[0]) { - const char* label = s->payload + 1; - Tree t = find_label(r->pattern, label); - if (!t && (strcmp(label, r->lhs->name) != 0)) + case '%': { - yylineno = r->lineno; - yyerror("label '%s' not found", label); - exit(1); + const char* label = f->data + 1; + Tree t = find_label(r->pattern, label); + if (!t && (strcmp(label, r->lhs->name) != 0)) + { + yylineno = r->lineno; + yyerror("label '%s' not found", label); + exit(1); + } + print("%1data->emit_ir(node_%s);\n", label); + break; } - print("%1data->emit_ir(node_%s);\n", label); - } - else - print("%1data->emit_string(\"%s\");\n", s->payload); - s = s->next; + case '\n': + assert(f->data[1] == 0); + print("%1data->emit_eoi();\n"); + break; + + default: + print("%1data->emit_string(\"%s\");\n", f->data); + } + + f = f->next; } print("}\n\n"); @@ -904,9 +906,10 @@ static void emitemitters(Rule rules) print("%Pemitter_t* const %Pemitters[] = {\n"); while (r) { - Stringlist s = r->code; + struct stringfragment* f = r->code.first; + print("%1"); - if (s) + if (f) print("&%Pemitter_%d,", r->ern); else print("NULL,"); @@ -920,7 +923,7 @@ static void emitemitters(Rule rules) /* emitcost - emit a cost calculation via a predicate */ static void emitcostcalc(Rule r) { - if (r->when) + if (r->when.first) print("!%Ppredicate_%d(node) ? %d : ", r->ern, maxcost); } diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 0a6c90dfc..b2897587a 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -1,16 +1,9 @@ #ifndef BURG_INCLUDED #define BURG_INCLUDED -/* $Id$ */ -/* iburg.c: */ -extern char* stringf(char* fmt, ...); +#include "stringlist.h" -typedef struct stringlist* Stringlist; -struct stringlist { - const char* payload; - Stringlist next; -}; -extern Stringlist pushstring(const char* data, Stringlist list); +extern char* stringf(char* fmt, ...); typedef enum { @@ -56,20 +49,20 @@ extern Tree tree(const char* op, const char* label, Tree left, Tree right); struct rule { /* rules: */ - Nonterm lhs; /* lefthand side non-terminal */ - Tree pattern; /* rule pattern */ - int lineno; /* line number where allocated */ - int ern; /* external rule number */ - int packed; /* packed external rule number */ - int cost; /* associated cost */ - Rule link; /* next rule in ern order */ - Rule next; /* next rule with same pattern root */ - Rule chain; /* next chain rule with same rhs */ - Rule decode; /* next rule with same lhs */ - Rule kids; /* next rule with same burm_kids pattern */ - Stringlist when; /* C predicate string */ - Stringlist code; /* compiler output code strings */ - bool is_fragment; /* does this rule generate an instruction fragment? */ + Nonterm lhs; /* lefthand side non-terminal */ + Tree pattern; /* rule pattern */ + int lineno; /* line number where allocated */ + int ern; /* external rule number */ + int packed; /* packed external rule number */ + int cost; /* associated cost */ + Rule link; /* next rule in ern order */ + Rule next; /* next rule with same pattern root */ + Rule chain; /* next chain rule with same rhs */ + Rule decode; /* next rule with same lhs */ + Rule kids; /* next rule with same burm_kids pattern */ + struct stringlist when; /* C predicate string */ + struct stringlist code; /* compiler output code strings */ + bool is_fragment; /* does this rule generate an instruction fragment? */ }; extern Rule rule(char* id, Tree pattern, int ern); extern int maxcost; /* maximum cost */ diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 10d8f5166..1a1be1b83 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -30,6 +30,7 @@ struct burm_emitter_data void* user; void (*emit_string)(const char* data); void (*emit_ir)(struct ir* ir); + void (*emit_eoi)(void); }; typedef void burm_emitter_t(struct ir* ir, struct burm_emitter_data* data); From 67eb21d428e6bbd863e1b03d6cdd7bb0caa758b7 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 25 Sep 2016 12:29:03 +0200 Subject: [PATCH 030/230] Rename struct insn to struct em (throughout). --- mach/proto/mcg/mcg.h | 4 +- mach/proto/mcg/parse_em.c | 160 +++++++++++++++++------------------ mach/proto/mcg/treebuilder.c | 36 ++++---- 3 files changed, 100 insertions(+), 100 deletions(-) diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 193ed3690..a5a148847 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -50,7 +50,7 @@ enum PARAM_BVALUE, }; -struct insn +struct em { int opcode; int paramtype; @@ -78,7 +78,7 @@ struct procedure struct basicblock { const char* name; - ARRAY(struct insn, insns); + ARRAY(struct em, ems); ARRAY(struct ir, irs); bool is_fake : 1; bool is_root : 1; diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 699e6b4f4..705bc1587 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -1,6 +1,6 @@ #include "mcg.h" -static struct e_instr insn; +static struct e_instr em; static struct procedure* current_proc; static struct basicblock* code_bb; static struct basicblock* data_bb; @@ -46,7 +46,7 @@ static void unknown_type(const char* s) { fatal("%s with unknown type '%s'", s, - argtype_to_str(insn.em_arg.ema_argtype)); + argtype_to_str(em.em_arg.ema_argtype)); } static const char* ilabel_to_str(label l) @@ -66,18 +66,18 @@ static void terminate_block(void) code_bb = NULL; } -static struct insn* new_insn(int opcode) +static struct em* new_insn(int opcode) { - struct insn* insn = calloc(sizeof(struct insn), 1); - insn->opcode = opcode; - return insn; + struct em* em = calloc(sizeof(struct em), 1); + em->opcode = opcode; + return em; } static void queue_insn_simple(int opcode) { - struct insn* insn = new_insn(opcode); - insn->paramtype = PARAM_NONE; - APPEND(code_bb->insns, insn); + struct em* em = new_insn(opcode); + em->paramtype = PARAM_NONE; + APPEND(code_bb->ems, em); switch (opcode) { @@ -89,10 +89,10 @@ static void queue_insn_simple(int opcode) static void queue_insn_value(int opcode, arith value) { - struct insn* insn = new_insn(opcode); - insn->paramtype = PARAM_IVALUE; - insn->u.ivalue = value; - APPEND(code_bb->insns, insn); + struct em* em = new_insn(opcode); + em->paramtype = PARAM_IVALUE; + em->u.ivalue = value; + APPEND(code_bb->ems, em); switch (opcode) { @@ -106,11 +106,11 @@ static void queue_insn_value(int opcode, arith value) static void queue_insn_label(int opcode, const char* label, arith offset) { - struct insn* insn = new_insn(opcode); - insn->paramtype = PARAM_LVALUE; - insn->u.lvalue.label = label; - insn->u.lvalue.offset = offset; - APPEND(code_bb->insns, insn); + struct em* em = new_insn(opcode); + em->paramtype = PARAM_LVALUE; + em->u.lvalue.label = label; + em->u.lvalue.offset = offset; + APPEND(code_bb->ems, em); switch (opcode) { @@ -122,11 +122,11 @@ static void queue_insn_label(int opcode, const char* label, arith offset) static void queue_insn_block(int opcode, struct basicblock* left, struct basicblock* right) { - struct insn* insn = new_insn(opcode); - insn->paramtype = PARAM_BVALUE; - insn->u.bvalue.left = left; - insn->u.bvalue.right = right; - APPEND(code_bb->insns, insn); + struct em* em = new_insn(opcode); + em->paramtype = PARAM_BVALUE; + em->u.bvalue.left = left; + em->u.bvalue.right = right; + APPEND(code_bb->ems, em); terminate_block(); } @@ -143,13 +143,13 @@ static void change_basicblock(struct basicblock* newbb) static void queue_insn_ilabel(int opcode, int label) { - const char* name = ilabel_to_str(insn.em_ilb); + const char* name = ilabel_to_str(em.em_ilb); struct basicblock* left = bb_get(name); switch (opcode) { case op_bra: - queue_insn_block(insn.em_opcode, left, NULL); + queue_insn_block(em.em_opcode, left, NULL); break; case op_zeq: @@ -160,7 +160,7 @@ static void queue_insn_ilabel(int opcode, int label) case op_zge: { struct basicblock* bb = bb_get(NULL); - queue_insn_block(insn.em_opcode, left, bb); + queue_insn_block(em.em_opcode, left, bb); change_basicblock(bb); break; } @@ -178,30 +178,30 @@ static void queue_ilabel(arith label) static void parse_pseu(void) { - switch (insn.em_opcode) + switch (em.em_opcode) { case ps_exp: /* external proc */ case ps_exa: /* external array */ case ps_inp: /* internal proc */ case ps_ina: /* internal array */ { - bool export = (insn.em_opcode == ps_exp) || (insn.em_opcode == ps_exa); - bool proc = (insn.em_opcode == ps_exp) || (insn.em_opcode == ps_inp); + bool export = (em.em_opcode == ps_exp) || (em.em_opcode == ps_exa); + bool proc = (em.em_opcode == ps_exp) || (em.em_opcode == ps_inp); - switch (insn.em_arg.ema_argtype) + switch (em.em_arg.ema_argtype) { case pro_ptyp: - symbol_declare(strdup(insn.em_pnam), export, proc); + symbol_declare(strdup(em.em_pnam), export, proc); break; case sof_ptyp: - assert(insn.em_off == 0); - symbol_declare(strdup(insn.em_dnam), export, proc); + assert(em.em_off == 0); + symbol_declare(strdup(em.em_dnam), export, proc); break; case nof_ptyp: - assert(insn.em_off == 0); - symbol_declare(dlabel_to_str(insn.em_dlb), export, proc); + assert(em.em_off == 0); + symbol_declare(dlabel_to_str(em.em_dlb), export, proc); break; default: @@ -213,33 +213,33 @@ static void parse_pseu(void) case ps_con: /* .data */ case ps_rom: /* .rom */ { - bool ro = (insn.em_opcode == ps_rom); + bool ro = (em.em_opcode == ps_rom); - switch (insn.em_arg.ema_argtype) + switch (em.em_arg.ema_argtype) { case ico_ptyp: case uco_ptyp: { - arith val = atol(insn.em_string); - data_int(val, insn.em_size, ro); + arith val = atol(em.em_string); + data_int(val, em.em_size, ro); break; } case str_ptyp: - data_block(strdup(insn.em_string), insn.em_size, ro); + data_block(strdup(em.em_string), em.em_size, ro); break; case cst_ptyp: - data_int(insn.em_cst, EM_wordsize, ro); + data_int(em.em_cst, EM_wordsize, ro); break; case nof_ptyp: - data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro); + data_offset(dlabel_to_str(em.em_dlb), em.em_off, ro); break; case ilb_ptyp: { - const char* label = ilabel_to_str(insn.em_ilb); + const char* label = ilabel_to_str(em.em_ilb); /* This is really hacky; to handle basic block flow * descriptor blocks, we need to track which bbs a descriptor @@ -249,10 +249,10 @@ static void parse_pseu(void) if (data_bb) { - struct insn* insn = new_insn(op_bra); - insn->paramtype = PARAM_BVALUE; - insn->u.bvalue.left = bb_get(label); - APPEND(data_bb->insns, insn); + struct em* em = new_insn(op_bra); + em->paramtype = PARAM_BVALUE; + em->u.bvalue.left = bb_get(label); + APPEND(data_bb->ems, em); } data_offset(label, 0, ro); @@ -267,10 +267,10 @@ static void parse_pseu(void) case ps_bss: { - switch (insn.em_arg.ema_argtype) + switch (em.em_arg.ema_argtype) { case cst_ptyp: - data_bss(EM_bsssize, insn.em_cst); + data_bss(EM_bsssize, em.em_cst); break; default: @@ -284,9 +284,9 @@ static void parse_pseu(void) struct symbol* symbol; current_proc = calloc(sizeof(struct procedure), 1); - current_proc->name = strdup(insn.em_pnam); + current_proc->name = strdup(em.em_pnam); current_proc->root_bb = bb_get(current_proc->name); - current_proc->nlocals = insn.em_nlocals; + current_proc->nlocals = em.em_nlocals; code_bb = current_proc->root_bb; code_bb->is_root = true; APPEND(current_proc->blocks, code_bb); @@ -306,22 +306,22 @@ static void parse_pseu(void) break; default: - fatal("unknown pseudo with opcode %d\n", insn.em_opcode); + fatal("unknown pseudo with opcode %d\n", em.em_opcode); } } static arith mes_get_cst(void) { - EM_getinstr(&insn); - if (insn.em_type != EM_MESARG) + EM_getinstr(&em); + if (em.em_type != EM_MESARG) fatal("malformed MES"); - return insn.em_cst; + return em.em_cst; } static void parse_mes(void) { - assert(insn.em_arg.ema_argtype == cst_ptyp); - switch (insn.em_cst) + assert(em.em_arg.ema_argtype == cst_ptyp); + switch (em.em_cst) { case 0: /* error */ fatal("MES 0 received (explicit halt)"); @@ -337,10 +337,10 @@ static void parse_mes(void) } } - while ((insn.em_type == EM_STARTMES) || (insn.em_type == EM_MESARG)) - EM_getinstr(&insn); + while ((em.em_type == EM_STARTMES) || (em.em_type == EM_MESARG)) + EM_getinstr(&em); - if (insn.em_type != EM_ENDMES) + if (em.em_type != EM_ENDMES) fatal("malformed MES"); } @@ -357,27 +357,27 @@ static void create_data_label(const char* label) void parse_em(void) { - EM_getinstr(&insn); + EM_getinstr(&em); tb_filestart(); - while (insn.em_type != EM_EOF) + while (em.em_type != EM_EOF) { - switch (insn.em_type) + switch (em.em_type) { case EM_PSEU: parse_pseu(); break; case EM_DEFILB: - queue_ilabel(insn.em_ilb); + queue_ilabel(em.em_ilb); break; case EM_DEFDLB: - create_data_label(dlabel_to_str(insn.em_dlb)); + create_data_label(dlabel_to_str(em.em_dlb)); break; case EM_DEFDNAM: - create_data_label(strdup(insn.em_dnam)); + create_data_label(strdup(em.em_dnam)); break; case EM_STARTMES: @@ -387,36 +387,36 @@ void parse_em(void) case EM_MNEM: if (code_bb) { - int flags = em_flag[insn.em_opcode - sp_fmnem]; + int flags = em_flag[em.em_opcode - sp_fmnem]; if (flags & EM_PAR) { - switch (insn.em_argtype) + switch (em.em_argtype) { case ilb_ptyp: - queue_insn_ilabel(insn.em_opcode, insn.em_ilb); + queue_insn_ilabel(em.em_opcode, em.em_ilb); break; case nof_ptyp: - queue_insn_label(insn.em_opcode, - dlabel_to_str(insn.em_dlb), insn.em_off); + queue_insn_label(em.em_opcode, + dlabel_to_str(em.em_dlb), em.em_off); break; case sof_ptyp: - queue_insn_label(insn.em_opcode, - strdup(insn.em_dnam), insn.em_off); + queue_insn_label(em.em_opcode, + strdup(em.em_dnam), em.em_off); break; case pro_ptyp: - queue_insn_label(insn.em_opcode, - strdup(insn.em_pnam), 0); + queue_insn_label(em.em_opcode, + strdup(em.em_pnam), 0); break; case cst_ptyp: if ((flags & EM_PAR) == PAR_B) - queue_insn_ilabel(insn.em_opcode, insn.em_ilb); + queue_insn_ilabel(em.em_opcode, em.em_ilb); else - queue_insn_value(insn.em_opcode, insn.em_cst); + queue_insn_value(em.em_opcode, em.em_cst); break; default: @@ -424,15 +424,15 @@ void parse_em(void) } } else - queue_insn_simple(insn.em_opcode); + queue_insn_simple(em.em_opcode); } break; default: - fatal("unrecognised instruction type '%d'", insn.em_type); + fatal("unrecognised instruction type '%d'", em.em_type); } - EM_getinstr(&insn); + EM_getinstr(&em); } tb_fileend(); diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 1b0d51da5..92c7bcf3f 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -323,15 +323,15 @@ static struct ir* extract_block_refs(struct basicblock* bb) struct ir* outir = NULL; int i; - for (i=0; iinsns_count; i++) + for (i=0; iems_count; i++) { - struct insn* insn = bb->insns[i]; - assert(insn->opcode == op_bra); - assert(insn->paramtype == PARAM_BVALUE); + struct em* em = bb->ems[i]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); outir = new_ir2( IR_PAIR, 0, - new_bbir(insn->u.bvalue.left), + new_bbir(em->u.bvalue.left), outir ); } @@ -651,34 +651,34 @@ static void generate_tree(struct basicblock* bb) current_bb = bb; reset_stack(); - for (i=0; iinsns_count; i++) + for (i=0; iems_count; i++) { - struct insn* insn = bb->insns[i]; - tracef('E', "E: read %s ", em_mnem[insn->opcode - sp_fmnem]); - switch (insn->paramtype) + struct em* em = bb->ems[i]; + tracef('E', "E: read %s ", em_mnem[em->opcode - sp_fmnem]); + switch (em->paramtype) { case PARAM_NONE: tracef('E', "\n"); - insn_simple(insn->opcode); + insn_simple(em->opcode); break; case PARAM_IVALUE: - tracef('E', "value=%d\n", insn->u.ivalue); - insn_ivalue(insn->opcode, insn->u.ivalue); + tracef('E', "value=%d\n", em->u.ivalue); + insn_ivalue(em->opcode, em->u.ivalue); break; case PARAM_LVALUE: tracef('E', "label=%s offset=%d\n", - insn->u.lvalue.label, insn->u.lvalue.offset); - insn_lvalue(insn->opcode, insn->u.lvalue.label, insn->u.lvalue.offset); + em->u.lvalue.label, em->u.lvalue.offset); + insn_lvalue(em->opcode, em->u.lvalue.label, em->u.lvalue.offset); break; case PARAM_BVALUE: - tracef('E', "true=%s", insn->u.bvalue.left->name); - if (insn->u.bvalue.right) - tracef('E', " false=%s", insn->u.bvalue.right->name); + tracef('E', "true=%s", em->u.bvalue.left->name); + if (em->u.bvalue.right) + tracef('E', " false=%s", em->u.bvalue.right->name); tracef('E', "\n"); - insn_bvalue(insn->opcode, insn->u.bvalue.left, insn->u.bvalue.right); + insn_bvalue(em->opcode, em->u.bvalue.left, em->u.bvalue.right); break; default: From bde5792b1a202174f95efaece3bd9af3b16195db Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 25 Sep 2016 17:14:54 +0200 Subject: [PATCH 031/230] Collapse several rule arrays into one; actually generate the array properly. --- mach/proto/mcg/pass_instructionselection.c | 10 +- mach/proto/mcg/table | 24 ++-- util/mcgg/iburg.c | 124 ++++++++++----------- util/mcgg/mcgg.h | 11 +- 4 files changed, 93 insertions(+), 76 deletions(-) diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index e54b6ea75..bfdaa77bd 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -25,8 +25,9 @@ static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { #endif void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) { + const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p, - burm_string[ruleno], cost, bestcost); + insndata->name, cost, bestcost); } void burm_panic_cannot_match(struct ir* ir) @@ -41,6 +42,7 @@ static void queue_instructions(struct ir* ir, int goal) { struct ir* children[10]; int ruleno = burm_rule(ir->state_label, goal); + const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; const short* nts = burm_nts[ruleno]; int i; @@ -48,7 +50,11 @@ static void queue_instructions(struct ir* ir, int goal) for (i=0; nts[i]; i++) queue_instructions(children[i], nts[i]); - tracef('I', "I: $%d selected insn %d: %s\n", ir->id, ruleno, burm_string[ruleno]); + tracef('I', "I: $%d selected %s %d: %s\n", + ir->id, + insndata->is_fragment ? "fragment" : "instruction", + ruleno, + insndata->name); } static void select_instructions(struct basicblock* bb) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index efaffdc36..9146f6339 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -42,22 +42,26 @@ PATTERNS reg = CIU14(LOAD1(addr:address)) emit "ldrb %reg, %addr" cost 4; + + reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) + emit "ldrsb %reg, %addr" + cost 4; /* Locals */ reg = in:LOCAL4 - emit "add %reg, fp, #%in" + emit "add %reg, fp, #$in" cost 4; address = in:LOCAL4 - fragment "[fp, #%in]"; + fragment "[fp, #$in]"; /* Memory addressing modes */ address = ADD4(addr:reg, offset:CONST) - fragment "[%addr, #%offset]"; + fragment "[%addr, #$offset]"; address = addr:reg fragment "[%addr]"; @@ -66,12 +70,12 @@ PATTERNS /* Branches */ JUMP(addr:BLOCK4) - emit "b %addr" + emit "b $addr" cost 4; CJUMPEQ(value:tristate, PAIR(true:BLOCK4, false:BLOCK4)) - emit "beq %true" - emit "bne %false" + emit "beq $true" + emit "bne $false" cost 8; @@ -111,7 +115,7 @@ PATTERNS cost 4; aluparam = value:CONST4 - fragment "#%value.ivalue"; + fragment "#$value"; aluparam = reg; @@ -120,13 +124,13 @@ PATTERNS cost 4; reg = value:LABEL4 - emit "adr %reg, %value" + emit "adr %reg, $value" cost 4; reg = value:BLOCK4 - emit "adr %reg, %value" + emit "adr %reg, $value" cost 4; reg = value:CONST4 - emit "ldr %reg, #value" + emit "ldr %reg, #$value" cost 4; diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index c4189f560..399ebdd85 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -41,7 +41,7 @@ static void emitnts(Rule rules, int nrules); static void emitrecord(char* pre, Rule r, int cost); static void emitrule(Nonterm nts); static void emitpredicatedefinitions(Rule rules); -static void emitemitters(Rule rules); +static void emitinsndata(Rule rules); static void emitstate(Term terms, Nonterm start, int ntnumber); static void emitstring(Rule rules); static void emitstruct(Nonterm nts, int ntnumber); @@ -135,7 +135,7 @@ int main(int argc, char* argv[]) emitrule(nts); emitclosure(nts); emitpredicatedefinitions(rules); - emitemitters(rules); + emitinsndata(rules); if (start) emitstate(terms, start, ntnumber); print("#ifdef STATE_LABEL\n"); @@ -800,59 +800,51 @@ static void emitpredicatedefinitions(Rule r) } } -static void emittreefetchers(uint32_t path, Tree tree) +static void print_path(uint32_t path) { - if (tree->label) + int i = 0; + + while (path > 0) { - int i = 0; - uint32_t p = path; - print("%1NODEPTR_TYPE node_%s = ", tree->label); - while (p > 0) + switch (path % 3) { - switch (p % 3) - { - case 1: print("LEFT_CHILD("); break; - case 2: print("RIGHT_CHILD("); break; - } - p /= 3; - i++; + case 1: print("LEFT_CHILD("); break; + case 2: print("RIGHT_CHILD("); break; } - - print("node"); - - while (i > 0) - { - print(")"); - i--; - } - - print(";\n"); + path /= 3; + i++; } - if (tree->left) - emittreefetchers(path*3 + 1, tree->left); - if (tree->right) - emittreefetchers(path*3 + 2, tree->right); + print("node"); + + while (i > 0) + { + print(")"); + i--; + } } -static Tree find_label(Tree root, const char* name) +static const uint32_t PATH_MISSING = 0xffffffff; + +static uint32_t find_label(Tree root, const char* name, uint32_t path) { - Tree t; + uint32_t p; if (root->label && (strcmp(root->label, name) == 0)) - return root; + return path; - t = NULL; - if (root->left && !t) - t = find_label(root->left, name); - if (root->right && !t) - t = find_label(root->right, name); - return t; + p = PATH_MISSING; + if (root->left && (p == PATH_MISSING)) + p = find_label(root->left, name, path*3 + 1); + if (root->right && (p == PATH_MISSING)) + p = find_label(root->right, name, path*3 + 2); + return p; } -/* emitemitters - emit the code generation routines */ -static void emitemitters(Rule rules) +/* emitinsndata - emit the code generation data */ +static void emitinsndata(Rule rules) { + int k; Rule r; r = rules; @@ -863,8 +855,6 @@ static void emitemitters(Rule rules) { print("/* %R */\n", r); print("static void %Pemitter_%d(NODEPTR_TYPE node, struct %Pemitter_data* data) {\n", r->ern); - emittreefetchers(0, r->pattern); - print("%1NODEPTR_TYPE node_%s = node;\n", r->lhs->name); while (f) { @@ -873,14 +863,22 @@ static void emitemitters(Rule rules) case '%': { const char* label = f->data + 1; - Tree t = find_label(r->pattern, label); - if (!t && (strcmp(label, r->lhs->name) != 0)) + + print("%1data->emit_ir("); + if (strcmp(label, r->lhs->name) == 0) + print("node"); + else { - yylineno = r->lineno; - yyerror("label '%s' not found", label); - exit(1); + uint32_t path = find_label(r->pattern, label, 0); + if (path == PATH_MISSING) + { + yylineno = r->lineno; + yyerror("label '%s' not found", label); + exit(1); + } + print_path(path); } - print("%1data->emit_ir(node_%s);\n", label); + print(");\n"); break; } @@ -903,18 +901,27 @@ static void emitemitters(Rule rules) } r = rules; - print("%Pemitter_t* const %Pemitters[] = {\n"); + print("const struct %Pinstruction_data %Pinstruction_data[] = {\n"); + k = 0; while (r) { - struct stringfragment* f = r->code.first; + for (; k < r->ern; k++) + print("%1{ 0 }, /* %d */\n", k); + k++; - print("%1"); - if (f) - print("&%Pemitter_%d,", r->ern); + print("%1{ /* %d: %R */\n", r->ern, r); + + print("%2\"%R\",\n", r); + + print("%2"); + if (r->code.first) + print("&%Pemitter_%d,\n", r->ern); else - print("NULL,"); - print(" /* %R */\n", r); + print("NULL,\n"); + print("%2%s,\n", r->is_fragment ? "true" : "false"); + + print("%1},\n"); r = r->link; } print("};\n\n"); @@ -971,13 +978,6 @@ static void emitstring(Rule rules) print("%1{ 0 },%1/* %d */\n", k); print("%1{ %d },%1/* %d = %R */\n", r->cost, k++, r); } - print("};\n\nconst char *%Pstring[] = {\n"); - for (k = 0, r = rules; r; r = r->link) - { - for (; k < r->ern; k++) - print("%1/* %d */%10,\n", k); - print("%1/* %d */%1\"%R\",\n", k++, r); - } print("};\n\n"); } diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 1a1be1b83..1279ee0ec 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -20,7 +20,6 @@ typedef struct ir* NODEPTR_TYPE; extern void* burm_label(struct ir* ir); extern int burm_rule(void* state, int goalnt); -extern const char* burm_string[]; extern const short *burm_nts[]; extern struct ir** burm_kids(struct ir* p, int eruleno, struct ir* kids[]); extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost); @@ -34,7 +33,15 @@ struct burm_emitter_data }; typedef void burm_emitter_t(struct ir* ir, struct burm_emitter_data* data); -extern burm_emitter_t* const burm_emitters[]; + +struct burm_instruction_data +{ + const char* name; + burm_emitter_t* emitter; + bool is_fragment; +}; + +extern const struct burm_instruction_data burm_instruction_data[]; #endif From 39aa672422abe94a5ce6dc964d0a3b1e2adc0e6a Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 25 Sep 2016 22:17:14 +0200 Subject: [PATCH 032/230] Sort of keep track of registers and register classes. Start walking the generated instruction tree --- holy cow, they look like instructions! --- mach/proto/mcg/ir.h | 1 + mach/proto/mcg/mcgg_generated_header.h | 3 + mach/proto/mcg/pass_instructionselection.c | 85 ++++++++--- mach/proto/mcg/table | 38 ++++- util/mcgg/gram.y | 96 +++++++----- util/mcgg/iburg.c | 165 +++++++++++++++++---- util/mcgg/iburg.h | 47 ++++-- util/mcgg/mcgg.h | 8 +- util/mcgg/scan.l | 19 ++- 9 files changed, 346 insertions(+), 116 deletions(-) diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index eaf031475..5868551db 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -35,6 +35,7 @@ struct ir } u; void* state_label; /* used by the iburg instruction selector */ + int insn_no; bool is_sequence : 1; bool is_generated : 1; diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index 36e394b6c..fbe0603dd 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -7,7 +7,10 @@ static int OP_LABEL(struct ir* ir) { if (ir->is_generated) + { + assert(ir->is_sequence); return ir_to_esn(IR_REG, ir->size); + } return ir_to_esn(ir->opcode, ir->size); } diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index bfdaa77bd..dd386a77b 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -38,25 +38,75 @@ void burm_panic_cannot_match(struct ir* ir) exit(1); } -static void queue_instructions(struct ir* ir, int goal) +static const struct burm_emitter_data emitter_data; + +static void emit_string(const char* data) { - struct ir* children[10]; - int ruleno = burm_rule(ir->state_label, goal); - const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; - const short* nts = burm_nts[ruleno]; - int i; - - burm_kids(ir, ruleno, children); - for (i=0; nts[i]; i++) - queue_instructions(children[i], nts[i]); - - tracef('I', "I: $%d selected %s %d: %s\n", - ir->id, - insndata->is_fragment ? "fragment" : "instruction", - ruleno, - insndata->name); + tracef('I', "I: emit: %s\n", data); } +static void emit_reg(struct ir* ir) +{ + const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no]; + if (insndata->is_fragment) + insndata->emitter(ir, &emitter_data); + else + tracef('I', "I: emit reg $%d\n", ir->id); +} + +static void emit_value(struct ir* ir) +{ + tracef('I', "I: emit value\n"); +} + +static void emit_resultreg(void) +{ + tracef('I', "I: emit resultreg\n"); +} + +static void emit_eoi(void) +{ + tracef('I', "I: emit eoi\n"); +} + +static const struct burm_emitter_data emitter_data = +{ + &emit_string, + &emit_reg, + &emit_value, + &emit_resultreg, + &emit_eoi +}; + +static void walk_instructions(struct ir* ir, int goal) +{ + struct ir* children[10]; + int insn_no = burm_rule(ir->state_label, goal); + const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; + const short* nts = burm_nts[insn_no]; + int i; + + ir->insn_no = insn_no; + + burm_kids(ir, insn_no, children); + for (i=0; nts[i]; i++) + walk_instructions(children[i], nts[i]); + + tracef('I', "I: $%d %s selected %s %d: %s\n", + ir->id, + ir->is_sequence ? "S" : " ", + insndata->is_fragment ? "fragment" : "instruction", + insn_no, + insndata->name); + ir->is_generated = true; + + if (insndata->allocate) + tracef('I', "I: allocate reg of class %d\n", insndata->allocate); + if (!insndata->is_fragment && insndata->emitter) + insndata->emitter(ir, &emitter_data); +} + + static void select_instructions(struct basicblock* bb) { int i; @@ -73,7 +123,7 @@ static void select_instructions(struct basicblock* bb) if (!insnno) burm_panic_cannot_match(ir); - queue_instructions(ir, 1); + walk_instructions(ir, 1); } } @@ -86,7 +136,6 @@ void pass_instruction_selector(struct procedure* proc) struct basicblock* bb = proc->blocks[i]; select_instructions(bb); } - exit(1); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 9146f6339..d450842aa 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,9 +1,35 @@ +REGISTERS + + r0 GPR RET0; + r1 GPR RET1; + r2 GPR; + r3 GPR; + r4 GPR; + r5 GPR; + r6 GPR; + r7 GPR; + r8 GPR; + r9 GPR; + r10 GPR; + r11 GPR; + + cc CC; + +DECLARATIONS + + address fragment; + aluparam fragment; + reg allocates(GPR); + tristate allocates(CC); + PATTERNS /* Special */ reg; + reg = REG4; + PAIR(BLOCK4, BLOCK4); @@ -25,6 +51,7 @@ PATTERNS emit "mov r0, %in" cost 4; + /* Memory operations */ STORE4(addr:address, value:reg) @@ -55,16 +82,16 @@ PATTERNS cost 4; address = in:LOCAL4 - fragment "[fp, #$in]"; + emit "[fp, #$in]"; /* Memory addressing modes */ - address = ADD4(addr:reg, offset:CONST) - fragment "[%addr, #$offset]"; + address = ADD4(addr:reg, offset:CONST4) + emit "[%addr, #$offset]"; address = addr:reg - fragment "[%addr]"; + emit "[%addr]"; /* Branches */ @@ -82,7 +109,6 @@ PATTERNS /* Comparisons */ tristate = COMPARES4(left:reg, right:aluparam) - outs CC emit "cmp %left, %right" cost 4; @@ -115,7 +141,7 @@ PATTERNS cost 4; aluparam = value:CONST4 - fragment "#$value"; + emit "#$value"; aluparam = reg; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index e24859851..177f33d72 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -16,40 +16,80 @@ static int nextern = 1; %union { int n; char* string; + Nonterm nonterm; Tree tree; Rule rule; + struct reg* reg; struct stringlist* stringlist; char* stringpair[2]; } -%term TERMINAL -%term START -%term PPERCENT -%term PATTERNS -%term WHEN +%term ALLOCATES +%term COST +%term DECLARATIONS %term EMIT %term FRAGMENT -%term COST %term INS %term OUTS +%term PATTERNS +%term REGISTERS +%term WHEN %token INT %token ID %token CFRAGMENT %token QFRAGMENT -%type pattern +%type allocates +%type declaration +%type register %type emit +%type pattern %type cfragments %type qfragments -%type rhs %type labelledid +%type rhs %% spec - : PATTERNS patterns + : REGISTERS registers + DECLARATIONS declarations + PATTERNS patterns ; +registers + : /* nothing */ + | registers register ';' + | register ';' + ; + +register + : ID { $$ = makereg($1); } + | register ID { $$ = $1; addregclass($1, $2); } + ; + +declarations + : /* nothing */ + | declarations declaration ';' + | declaration ';' + ; + +declaration + : ID { $$ = nonterm($1, true); } + | declaration FRAGMENT { $$ = $1; $$->is_fragment = true; } + | allocates { $$ = $1; } + ; + +allocates + : declaration ALLOCATES '(' ID ')' + { + $$ = $1; + if ($$->allocate) + yyerror("pattern type is defined to already allocate a register"); + $$->allocate = getregclass($4); + } + ; + patterns : /* nothing */ | patterns pattern ';' @@ -57,11 +97,9 @@ patterns ; pattern - : ID '=' rhs { nonterm($1); $$ = rule($1, $3, nextern++); } - | rhs { $$ = rule("stmt", $1, nextern++); } + : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } + | rhs { $$ = rule("stmt", $1, nextern++); } | pattern WHEN cfragments { $$ = $1; stringlist_addall(&$$->when, $3); } - | pattern INS ins { $$ = $1; } - | pattern OUTS outs { $$ = $1; } | emit { $$ = $1; } | pattern COST INT { $$ = $1; $$->cost = $3; } ; @@ -82,42 +120,18 @@ cfragments | cfragments CFRAGMENT { $$ = $1; stringlist_add($$, $2); } ; -ins - : ins ',' in - | in - ; - -in - : ID ':' ID - ; - -outs - : outs ',' out - | out - ; - -out - : ID - | ID ':' ID - ; - emit : pattern EMIT qfragments { $$ = $1; - stringlist_add($3, "\n"); + if (!$$->lhs->is_fragment) + stringlist_add($3, "\n"); stringlist_addall(&$$->code, $3); - $$->is_fragment = false; - } - | pattern FRAGMENT qfragments { - $$ = $1; - stringlist_addall(&$$->code, $3); - $$->is_fragment = true; } ; qfragments - : /* nothing */ { $$ = calloc(1, sizeof *$$); } - | qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); } + : /* nothing */ { $$ = calloc(1, sizeof *$$); } + | qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); } ; %% diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 399ebdd85..9ac77edef 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -20,6 +20,8 @@ static char* prefix = "burm"; static int Tflag = 1; /* tracing */ static int ntnumber = 0; static Nonterm start = 0; +static struct reg* regs = NULL; +static struct regclass* regclasses = NULL; static Term terms; static Nonterm nts; static Rule rules; @@ -34,14 +36,16 @@ static void emitcostcalc(Rule r); static void emitdefs(Nonterm nts, int ntnumber); static void emitfuncs(void); static void emitheader(void); +static void emitinsndata(Rule rules); static void emitkids(Rule rules, int nrules); static void emitlabel(Nonterm start); static void emitleaf(Term p, int ntnumber); static void emitnts(Rule rules, int nrules); -static void emitrecord(char* pre, Rule r, int cost); -static void emitrule(Nonterm nts); static void emitpredicatedefinitions(Rule rules); -static void emitinsndata(Rule rules); +static void emitrecord(char* pre, Rule r, int cost); +static void emitregisterclasses(struct regclass* rc); +static void emitregisters(struct reg* regs); +static void emitrule(Nonterm nts); static void emitstate(Term terms, Nonterm start, int ntnumber); static void emitstring(Rule rules); static void emitstruct(Nonterm nts, int ntnumber); @@ -116,7 +120,7 @@ int main(int argc, char* argv[]) emitheader(); registerterminals(); - start = nonterm("stmt"); + start = nonterm("stmt", true); yyin = infp; yyparse(); @@ -127,6 +131,8 @@ int main(int argc, char* argv[]) if (!p->reached) yyerror("can't reach non-terminal `%s'\n", p->name); + emitregisterclasses(regclasses); + emitregisters(regs); emitdefs(nts, ntnumber); emitstruct(nts, ntnumber); emitnts(rules, nrules); @@ -203,6 +209,8 @@ struct entry const char* name; struct term t; struct nonterm nt; + struct reg r; + struct regclass rc; } sym; struct entry* link; } * table[211]; @@ -219,7 +227,7 @@ static unsigned hash(const char* str) } /* lookup - lookup symbol name */ -static void* lookup(const char* name) +void* lookup(const char* name) { struct entry* p = table[hash(name) % HASHSIZE]; @@ -241,15 +249,69 @@ static void* install(const char* name) return &p->sym; } -/* nonterm - create a new terminal id, if necessary */ -Nonterm nonterm(const char* id) +struct reg* makereg(const char* id) { - Nonterm p = lookup(id), * q = &nts; + struct reg* p = lookup(id); + struct reg** q = ®s; + static int number = 1; + + if (p) + yyerror("redefinition of '%s'", id); + p = install(id); + p->kind = REG; + p->number = number++; + + while (*q && (*q)->number < p->number) + q = &(*q)->link; + assert(*q == 0 || (*q)->number != p->number); + p->link = *q; + *q = p; + return p; +} + +void addregclass(struct reg* reg, const char* id) +{ + struct regclass* p = lookup(id); + struct regclass** q = ®classes; + static int number = 1; + + if (p && (p->kind != REGCLASS)) + yyerror("redefinition of '%s' as something else\n", id); + if (!p) + { + p = install(id); + p->kind = REGCLASS; + p->number = number++; + + while (*q && (*q)->number < p->number) + q = &(*q)->link; + assert(*q == 0 || (*q)->number != p->number); + p->link = *q; + *q = p; + } +} + +struct regclass* getregclass(const char* id) +{ + struct regclass* p = lookup(id); + if (!p || (p->kind != REGCLASS)) + yyerror("'%p' is not the name of a register class"); + return p; +} + +/* nonterm - create a new terminal id, if necessary */ +Nonterm nonterm(const char* id, bool allocate) +{ + Nonterm p = lookup(id); + Nonterm* q = &nts; if (p && p->kind == NONTERM) return p; - if (p && p->kind == TERM) - yyerror("`%s' is a terminal\n", id); + if (p) + yyerror("redefinition of '%s' as something else\n", id); + if (!allocate) + yyerror("'%s' has not been declared\n", id); + p = install(id); p->kind = NONTERM; p->number = ++ntnumber; @@ -270,12 +332,9 @@ Term term(const char* id, int esn) Term* q = &terms; if (p) - { - yyerror("redefinition of terminal `%s'\n", id); - exit(1); - } - else - p = install(id); + yyerror("redefinition of '%s'\n", id); + + p = install(id); p->kind = TERM; p->esn = esn; p->arity = -1; @@ -309,7 +368,7 @@ Tree tree(const char* id, const char* label, Tree left, Tree right) p = term(id, -1); } else if (p == NULL && arity == 0) - p = (Term)nonterm(id); + p = (Term)nonterm(id, false); else if (p && p->kind == NONTERM && arity > 0) { yyerror("`%s' is a non-terminal\n", id); @@ -338,7 +397,7 @@ Rule rule(char* id, Tree pattern, int ern) nrules++; r->lineno = yylineno; - r->lhs = nonterm(id); + r->lhs = nonterm(id, false); r->packed = ++r->lhs->lhscount; for (q = &r->lhs->rules; *q; q = &(*q)->decode) ; @@ -452,6 +511,38 @@ static void ckreach(Nonterm p) reach(r->pattern); } +static void emitregisterclasses(struct regclass* rc) +{ + int k = 0; + print("const char* %Pregister_class_names[] = {\n"); + while (rc) + { + for (; k < rc->number; k++) + print("%1NULL,\n"); + k++; + + print("%1\"%s\",\n", rc->name); + rc = rc->link; + } + print("};\n\n"); +} + +static void emitregisters(struct reg* r) +{ + int k = 0; + print("const char* %Pregister_names[] = {\n"); + while (r) + { + for (; k < r->number; k++) + print("%1NULL,\n"); + k++; + + print("%1\"%s\",\n", r->name); + r = r->link; + } + print("};\n\n"); +} + /* emitcase - emit one case in function state */ static void emitcase(Term p, int ntnumber) { @@ -841,6 +932,13 @@ static uint32_t find_label(Tree root, const char* name, uint32_t path) return p; } +static void label_not_found(Rule rule, const char* label) +{ + yylineno = rule->lineno; + yyerror("label '%s' not found", label); + exit(1); +} + /* emitinsndata - emit the code generation data */ static void emitinsndata(Rule rules) { @@ -854,7 +952,7 @@ static void emitinsndata(Rule rules) if (f) { print("/* %R */\n", r); - print("static void %Pemitter_%d(NODEPTR_TYPE node, struct %Pemitter_data* data) {\n", r->ern); + print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern); while (f) { @@ -864,20 +962,28 @@ static void emitinsndata(Rule rules) { const char* label = f->data + 1; - print("%1data->emit_ir("); if (strcmp(label, r->lhs->name) == 0) - print("node"); + print("%1data->emit_resultreg();\n"); else { uint32_t path = find_label(r->pattern, label, 0); + print("%1data->emit_reg("); if (path == PATH_MISSING) - { - yylineno = r->lineno; - yyerror("label '%s' not found", label); - exit(1); - } + label_not_found(r, label); print_path(path); + print(");\n"); } + break; + } + + case '$': + { + const char* label = f->data + 1; + uint32_t path = find_label(r->pattern, label, 0); + print("%1data->emit_value("); + if (path == PATH_MISSING) + label_not_found(r, label); + print_path(path); print(");\n"); break; } @@ -919,7 +1025,12 @@ static void emitinsndata(Rule rules) else print("NULL,\n"); - print("%2%s,\n", r->is_fragment ? "true" : "false"); + if (r->lhs->allocate) + print("%2%d,\n", r->lhs->allocate->number); + else + print("%20,\n"); + + print("%2%s,\n", r->lhs->is_fragment ? "true" : "false"); print("%1},\n"); r = r->link; diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index b2897587a..5709ae13e 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -8,10 +8,33 @@ extern char* stringf(char* fmt, ...); typedef enum { TERM = 1, - NONTERM + NONTERM, + REG, + REGCLASS } Kind; typedef struct rule* Rule; typedef struct term* Term; + +struct reg +{ + const char* name; /* register name */ + Kind kind; /* REG */ + int number; /* identifying number */ + struct reg* link; /* next in list */ +}; + +struct regclass +{ + const char* name; /* class name */ + Kind kind; /* REGCLASS */ + int number; /* identifying number */ + struct regclass* link; /* next in list */ +}; + +extern struct reg* makereg(const char* name); +extern void addregclass(struct reg* reg, const char* regclass); +extern struct regclass* getregclass(const char* name); + struct term { /* terminals: */ char* name; /* terminal name */ @@ -25,16 +48,19 @@ struct term typedef struct nonterm* Nonterm; struct nonterm { /* non-terminals: */ - char* name; /* non-terminal name */ - Kind kind; /* NONTERM */ - int number; /* identifying number */ - int lhscount; /* # times nt appears in a rule lhs */ - int reached; /* 1 iff reached from start non-terminal */ - Rule rules; /* rules w/non-terminal on lhs */ - Rule chain; /* chain rules w/non-terminal on rhs */ - Nonterm link; /* next terminal in number order */ + char* name; /* non-terminal name */ + Kind kind; /* NONTERM */ + int number; /* identifying number */ + int lhscount; /* # times nt appears in a rule lhs */ + int reached; /* 1 iff reached from start non-terminal */ + Rule rules; /* rules w/non-terminal on lhs */ + Rule chain; /* chain rules w/non-terminal on rhs */ + Nonterm link; /* next terminal in number order */ + bool is_fragment; /* these instructions are all fragments */ + struct regclass* allocate; /* allocate this kind of register */ }; -extern Nonterm nonterm(const char* id); +extern void* lookup(const char* name); +extern Nonterm nonterm(const char* id, bool allocate); extern Term term(const char* id, int esn); typedef struct tree* Tree; @@ -62,7 +88,6 @@ struct rule Rule kids; /* next rule with same burm_kids pattern */ struct stringlist when; /* C predicate string */ struct stringlist code; /* compiler output code strings */ - bool is_fragment; /* does this rule generate an instruction fragment? */ }; extern Rule rule(char* id, Tree pattern, int ern); extern int maxcost; /* maximum cost */ diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 1279ee0ec..9c15eea82 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -26,18 +26,20 @@ extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost); struct burm_emitter_data { - void* user; void (*emit_string)(const char* data); - void (*emit_ir)(struct ir* ir); + void (*emit_reg)(struct ir* ir); + void (*emit_value)(struct ir* ir); + void (*emit_resultreg)(void); void (*emit_eoi)(void); }; -typedef void burm_emitter_t(struct ir* ir, struct burm_emitter_data* data); +typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data); struct burm_instruction_data { const char* name; burm_emitter_t* emitter; + int allocate; bool is_fragment; }; diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 479a115fc..83e0fe3cf 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -50,12 +50,12 @@ static int braces = 0; "\"" BEGIN(QSTRING); "\"" BEGIN(INITIAL); -%[a-zA-Z_][a-zA_Z_0-9]+ { +[%$][a-zA-Z_][a-zA_Z_0-9]+ { yylval.string = strdup(yytext); return QFRAGMENT; } -[^\r\n%"]+ { +[^\r\n%$"]+ { yylval.string = strdup(yytext); return QFRAGMENT; } @@ -65,17 +65,16 @@ static int braces = 0; [^*]* ; "*" ; -"%%" return PPERCENT; -"%term" return TERMINAL; -"%start" return START; - +"DECLARATIONS" return DECLARATIONS; "PATTERNS" return PATTERNS; -"when" return WHEN; -"ins" return INS; -"outs" return OUTS; +"REGISTERS" return REGISTERS; +"allocates" return ALLOCATES; +"cost" return COST; "emit" return EMIT; "fragment" return FRAGMENT; -"cost" return COST; +"ins" return INS; +"outs" return OUTS; +"when" return WHEN; "//"[^\n]*\n ; From 416b13fd768be42e362c384275304a918aa8ba59 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 25 Sep 2016 23:29:59 +0200 Subject: [PATCH 033/230] Start factoring out the hardware op code. --- mach/proto/mcg/hop.c | 39 ++++++++++++++++++++++ mach/proto/mcg/hop.h | 27 +++++++++++++++ mach/proto/mcg/ir.h | 1 + mach/proto/mcg/mcg.h | 3 ++ mach/proto/mcg/pass_instructionselection.c | 26 +++++++++++---- util/mcgg/mcgg.h | 2 ++ 6 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 mach/proto/mcg/hop.c create mode 100644 mach/proto/mcg/hop.h diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c new file mode 100644 index 000000000..ccc180540 --- /dev/null +++ b/mach/proto/mcg/hop.c @@ -0,0 +1,39 @@ +#include "mcg.h" + +struct hop* new_hop(int insn_no, struct ir* ir) +{ + struct hop* hop = calloc(1, sizeof *hop); + hop->insn_no = insn_no; + hop->ir = ir; +} + +static void add_reg(struct vreg* vregs[], struct vreg* vreg) +{ + int i; + + for (i=0; iinvregs, vreg); +} + +void hop_add_out_reg(struct hop* hop, struct vreg* vreg) +{ + add_reg(hop->outvregs, vreg); +} + +void hop_emit(struct hop* hop, const struct burm_emitter_data* ed) +{ + const struct burm_instruction_data* insndata = &burm_instruction_data[hop->insn_no]; + insndata->emitter(hop->ir, ed); +} + diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h new file mode 100644 index 000000000..d6cc6e79d --- /dev/null +++ b/mach/proto/mcg/hop.h @@ -0,0 +1,27 @@ +#ifndef HOP_H +#define HOP_H + +struct vreg +{ + int id; + int regclass; +}; + +#define HOP_INOUT_REGS 4 + +struct hop +{ + int insn_no; + struct ir* ir; + struct vreg* invregs[HOP_INOUT_REGS]; + struct vreg* outvregs[HOP_INOUT_REGS]; +}; + +extern struct hop* new_hop(int insn_no, struct ir* ir); + +extern void hop_add_in_reg(struct hop* hop, struct vreg* reg); +extern void hop_add_out_reg(struct hop* hop, struct vreg* reg); + +#endif + + diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 5868551db..ac01f1633 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -36,6 +36,7 @@ struct ir void* state_label; /* used by the iburg instruction selector */ int insn_no; + int vreg; bool is_sequence : 1; bool is_generated : 1; diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index a5a148847..45bb691c6 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -19,6 +19,8 @@ #include "array.h" #include "map.h" #include "ir.h" +#include "mcgg.h" +#include "hop.h" extern char em_pseu[][4]; extern char em_mnem[][4]; @@ -80,6 +82,7 @@ struct basicblock const char* name; ARRAY(struct em, ems); ARRAY(struct ir, irs); + ARRAY(struct hop, hops); bool is_fake : 1; bool is_root : 1; bool is_terminated : 1; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index dd386a77b..aebfd9160 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -1,5 +1,6 @@ #include "mcg.h" -#include "mcgg.h" + +static int vregcount; #if 0 static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { @@ -26,8 +27,8 @@ static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) { const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; - tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p, - insndata->name, cost, bestcost); + //tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p, + // insndata->name, cost, bestcost); } void burm_panic_cannot_match(struct ir* ir) @@ -51,7 +52,7 @@ static void emit_reg(struct ir* ir) if (insndata->is_fragment) insndata->emitter(ir, &emitter_data); else - tracef('I', "I: emit reg $%d\n", ir->id); + tracef('I', "I: emit reg %d\n", ir->vreg); } static void emit_value(struct ir* ir) @@ -85,13 +86,26 @@ static void walk_instructions(struct ir* ir, int goal) const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; const short* nts = burm_nts[insn_no]; int i; + int resultreg = 0; ir->insn_no = insn_no; + if (insndata->allocate) + { + resultreg = vregcount++; + tracef('I', "I: new %s %d\n", + burm_register_class_names[insndata->allocate], resultreg); + } + burm_kids(ir, insn_no, children); for (i=0; nts[i]; i++) walk_instructions(children[i], nts[i]); + if (ir->vreg) + tracef('I', "I: use %d\n", ir->vreg); + if (resultreg) + ir->vreg = resultreg; + tracef('I', "I: $%d %s selected %s %d: %s\n", ir->id, ir->is_sequence ? "S" : " ", @@ -100,8 +114,6 @@ static void walk_instructions(struct ir* ir, int goal) insndata->name); ir->is_generated = true; - if (insndata->allocate) - tracef('I', "I: allocate reg of class %d\n", insndata->allocate); if (!insndata->is_fragment && insndata->emitter) insndata->emitter(ir, &emitter_data); } @@ -131,6 +143,8 @@ void pass_instruction_selector(struct procedure* proc) { int i; + vregcount = 1; + for (i=0; iblocks_count; i++) { struct basicblock* bb = proc->blocks[i]; diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 9c15eea82..004146bb3 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -31,6 +31,7 @@ struct burm_emitter_data void (*emit_value)(struct ir* ir); void (*emit_resultreg)(void); void (*emit_eoi)(void); + void (*emit_usereg)(struct ir* ir); }; typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data); @@ -44,6 +45,7 @@ struct burm_instruction_data }; extern const struct burm_instruction_data burm_instruction_data[]; +extern const char* burm_register_class_names[]; #endif From cc176e5183e5327f1c506c02cfadf09d3a7f3220 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 26 Sep 2016 22:12:46 +0200 Subject: [PATCH 034/230] Keep more data around about ir instructions. Implement a half-baked type inference routine to propagate information about floats up the tree, so we know whether to put floats into special registers as early as possible. --- mach/proto/mcg/ir.c | 8 +- mach/proto/mcg/ir.h | 17 +--- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_typeinference.c | 63 +++++++++++++ mach/proto/mcg/procedure.c | 1 + util/mcgg/build.lua | 9 +- util/mcgg/iburg.c | 16 ++-- util/mcgg/ir.dat | 134 ++++++++++++++++------------ util/mcgg/ircodes.h | 33 +++++++ util/mcgg/ircodes.sh | 46 ++++------ 10 files changed, 215 insertions(+), 113 deletions(-) create mode 100644 mach/proto/mcg/pass_typeinference.c create mode 100644 util/mcgg/ircodes.h diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index f0c495f7e..9d1dab112 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -103,9 +103,15 @@ struct ir* ir_find(struct ir* ir, int opcode) static void print_expr(char k, const struct ir* ir) { - tracef(k, "%s", ir_names[ir->opcode]); + tracef(k, "%s", ir_data[ir->opcode].name); if (ir->size) tracef(k, "%d", ir->size); + if (ir->type) + tracef(k, ".%s", + ((ir->type == IRT_INT) ? "I" : + (ir->type == IRT_FLOAT) ? "F" : + (ir->type == IRT_ANY) ? "*" : + "?")); tracef(k, "("); switch (ir->opcode) diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index ac01f1633..79dbfdb8f 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -3,27 +3,12 @@ #include "ircodes.h" -enum -{ - IRR_LB = -1, - IRR_AB = -2, - IRR_SP = -3, - IRR_RR = -4, -}; - -enum -{ - IRS_1, - IRS_2, - IRS_4, - IRS_8 -}; - struct ir { int id; enum ir_opcode opcode; int size; + enum ir_type type; struct ir* left; struct ir* right; union diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 45bb691c6..e40bbcbf5 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -123,6 +123,7 @@ extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_instruction_selector(struct procedure* proc); +extern void pass_type_inference(struct procedure* proc); extern void procedure_compile(struct procedure* proc); diff --git a/mach/proto/mcg/pass_typeinference.c b/mach/proto/mcg/pass_typeinference.c new file mode 100644 index 000000000..4d57e3212 --- /dev/null +++ b/mach/proto/mcg/pass_typeinference.c @@ -0,0 +1,63 @@ +#include "mcg.h" + +static enum ir_type search_for_type(struct ir* ir, enum ir_type desired) +{ + const struct ir_data* data; + + if (ir->type != IRT_UNSET) + return ir->type; + + data = &ir_data[ir->opcode]; + if (ir->left) + ir->left->type = search_for_type(ir->left, data->lefttype); + if (ir->right) + ir->right->type = search_for_type(ir->right, data->righttype); + + switch (data->returntype) + { + case IRT_ANY: + if (desired == IRT_FLOAT) + ir->opcode++; + return desired; + + case IRT_UNSET: + assert(!((data->lefttype == IRT_ANY) && (data->righttype == IRT_ANY))); + if (((data->lefttype == IRT_ANY) && (ir->left->type == IRT_FLOAT)) || + ((data->righttype == IRT_ANY) && (ir->right->type == IRT_FLOAT))) + { + ir->opcode++; + return IRT_FLOAT; + } + if ((data->lefttype == IRT_ANY) && (ir->left->type == IRT_ANY)) + ir->left->type = IRT_INT; + if ((data->righttype == IRT_ANY) && (ir->right->type == IRT_ANY)) + ir->right->type = IRT_INT; + return IRT_INT; + + default: + return data->returntype; + } +} + +static void push_types_up(struct basicblock* bb) +{ + int i; + + for (i=0; iirs_count; i++) + { + struct ir* ir = bb->irs[i]; + ir->type = search_for_type(ir, ir->type); + } +} + +void pass_type_inference(struct procedure* proc) +{ + int i; + + for (i=0; iblocks_count; i++) + push_types_up(proc->blocks[i]); +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index b0bc1a0e3..78d8f3311 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -29,6 +29,7 @@ void procedure_compile(struct procedure* proc) pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); pass_convert_stack_ops(proc); + pass_type_inference(proc); print_blocks('2', proc); diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index b3ffe81f6..83d800eaf 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -12,7 +12,7 @@ yacc { normalrule { name = "ircodes", - outleaves = { "ircodes.h", "ircodes.c" }, + outleaves = { "ircodes-dyn.h", "ircodes.c" }, ins = { "./ircodes.sh", "./ir.dat" @@ -25,10 +25,15 @@ normalrule { clibrary { name = "lib", srcs = { - matching(filenamesof("+ircodes"), "%.c$") + matching(filenamesof("+ircodes"), "%.c$"), + }, + deps = { + "+ircodes", + "./ircodes.h" }, hdrs = { matching(filenamesof("+ircodes"), "%.h$"), + "./ircodes.h", "./mcgg.h" } } diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 9ac77edef..f29c85907 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -176,9 +176,9 @@ char* stringf(char* fmt, ...) return p; } -static void registerterminal(const char* name, int iropcode, int size) +static void registerterminal(const struct ir_data* data, int iropcode, int size) { - const char* s = (size == 0) ? name : stringf("%s%d", name, size); + const char* s = (size == 0) ? data->name : stringf("%s%d", data->name, size); int esn = ir_to_esn(iropcode, size); term(s, esn); @@ -190,15 +190,15 @@ static void registerterminals(void) for (i=0; i$header << "EOF" END { print "\tIR__COUNT" print "};" - print "" - print "enum {" - print "\tIRF_SIZED = 1" - print "};" - print "" - print "extern const char* ir_names[IR__COUNT];" - print "extern const char ir_flags[IR__COUNT];" } EOF awk -f - $in >$source << "EOF" BEGIN { print "#include \"ircodes.h\"" - print "const char* ir_names[IR__COUNT] = {" + print "const struct ir_data ir_data[IR__COUNT] = {" + } + + function char_to_type(c) { + if (c == "I") return "IRT_INT" + if (c == "F") return "IRT_FLOAT" + if (c == "A") return "IRT_ANY" + return "IRT_UNSET" + } + + function char_to_flags(c) { + if (c == "S") return "IRF_SIZED" + return "0" } /^ *[^# ]+/ { - printf("\t\"%s\",\n", $2) - } - - END { - print "};" - } -EOF - -awk -f - $in >>$source << "EOF" - BEGIN { - print "" - print "const char ir_flags[IR__COUNT] = {" - } - - /^ *[^# ]+/ { - if ($1 == "S") - print("\tIRF_SIZED,") - else - print("\t0,") + printf("\t{ \"%s\", ", $2) + printf("%s, ", char_to_flags(substr($1, 1, 1))) + printf("%s, ", char_to_type(substr($1, 2, 1))) + printf("%s, ", char_to_type(substr($1, 3, 1))) + printf("%s", char_to_type(substr($1, 4, 1))) + printf(" },\n") } END { From 3671892c34d1ad41795794352d5cd7d8ff6cff64 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 26 Sep 2016 22:24:49 +0200 Subject: [PATCH 035/230] Move the array library into the data module. --- mach/proto/mcg/build.lua | 1 + {mach/proto/mcg => modules/src/data}/array.c | 5 ++--- {mach/proto/mcg => modules/src/data}/array.h | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename {mach/proto/mcg => modules/src/data}/array.c (93%) rename {mach/proto/mcg => modules/src/data}/array.h (100%) diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index b9440a790..dc3504294 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -16,6 +16,7 @@ cprogram { "h+emheaders", "modules+headers", "modules/src/alloc+lib", + "modules/src/data+lib", "modules/src/em_code+lib_k", "modules/src/em_data+lib", "modules/src/idf+lib", diff --git a/mach/proto/mcg/array.c b/modules/src/data/array.c similarity index 93% rename from mach/proto/mcg/array.c rename to modules/src/data/array.c index a375bafb5..9f61d2805 100644 --- a/mach/proto/mcg/array.c +++ b/modules/src/data/array.c @@ -1,4 +1,5 @@ -#include "mcg.h" +#include +#include #include "array.h" void array_append(void*** array, int* count, int* max, void* value) @@ -7,8 +8,6 @@ void array_append(void*** array, int* count, int* max, void* value) { int newmax = (*max == 0) ? 8 : (*max * 2); void** newarray = realloc(*array, newmax * sizeof(void*)); - if (!newarray) - fatal("memory allocation failure"); *max = newmax; *array = newarray; diff --git a/mach/proto/mcg/array.h b/modules/src/data/array.h similarity index 100% rename from mach/proto/mcg/array.h rename to modules/src/data/array.h From c4b8e00ae21d138dd1415b3033acc9ea43d34e53 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 26 Sep 2016 22:48:58 +0200 Subject: [PATCH 036/230] Revamp the array module not to use nasty macros any more. Slightly more verbose to use, but definitely cleaner. --- mach/proto/mcg/mcg.h | 8 ++-- mach/proto/mcg/parse_em.c | 16 +++---- mach/proto/mcg/pass_convertstackops.c | 44 +++++++++---------- mach/proto/mcg/pass_eliminatetrivialblocks.c | 16 +++---- mach/proto/mcg/pass_instructionselection.c | 8 ++-- mach/proto/mcg/pass_removedeadblocks.c | 20 ++++----- mach/proto/mcg/pass_typeinference.c | 8 ++-- mach/proto/mcg/procedure.c | 8 ++-- mach/proto/mcg/treebuilder.c | 14 +++--- modules/src/data/array.c | 46 +++++++++++--------- modules/src/data/array.h | 40 ++++++++--------- 11 files changed, 113 insertions(+), 115 deletions(-) diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index e40bbcbf5..8cf16f952 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -74,15 +74,15 @@ struct procedure const char* name; struct basicblock* root_bb; size_t nlocals; - ARRAY(struct basicblock, blocks); + ARRAYOF(struct basicblock) blocks; }; struct basicblock { const char* name; - ARRAY(struct em, ems); - ARRAY(struct ir, irs); - ARRAY(struct hop, hops); + ARRAYOF(struct em) ems; + ARRAYOF(struct ir) irs; + ARRAYOF(struct hop) hops; bool is_fake : 1; bool is_root : 1; bool is_terminated : 1; diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 705bc1587..7c0015184 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -77,7 +77,7 @@ static void queue_insn_simple(int opcode) { struct em* em = new_insn(opcode); em->paramtype = PARAM_NONE; - APPEND(code_bb->ems, em); + array_append(&code_bb->ems, em); switch (opcode) { @@ -92,7 +92,7 @@ static void queue_insn_value(int opcode, arith value) struct em* em = new_insn(opcode); em->paramtype = PARAM_IVALUE; em->u.ivalue = value; - APPEND(code_bb->ems, em); + array_append(&code_bb->ems, em); switch (opcode) { @@ -110,7 +110,7 @@ static void queue_insn_label(int opcode, const char* label, arith offset) em->paramtype = PARAM_LVALUE; em->u.lvalue.label = label; em->u.lvalue.offset = offset; - APPEND(code_bb->ems, em); + array_append(&code_bb->ems, em); switch (opcode) { @@ -126,14 +126,14 @@ static void queue_insn_block(int opcode, struct basicblock* left, struct basicbl em->paramtype = PARAM_BVALUE; em->u.bvalue.left = left; em->u.bvalue.right = right; - APPEND(code_bb->ems, em); + array_append(&code_bb->ems, em); terminate_block(); } static void change_basicblock(struct basicblock* newbb) { - APPENDU(current_proc->blocks, newbb); + array_appendu(¤t_proc->blocks, newbb); if (code_bb && !code_bb->is_terminated) queue_insn_block(op_bra, newbb, NULL); @@ -252,7 +252,7 @@ static void parse_pseu(void) struct em* em = new_insn(op_bra); em->paramtype = PARAM_BVALUE; em->u.bvalue.left = bb_get(label); - APPEND(data_bb->ems, em); + array_append(&data_bb->ems, em); } data_offset(label, 0, ro); @@ -289,7 +289,7 @@ static void parse_pseu(void) current_proc->nlocals = em.em_nlocals; code_bb = current_proc->root_bb; code_bb->is_root = true; - APPEND(current_proc->blocks, code_bb); + array_append(¤t_proc->blocks, code_bb); symbol = symbol_get(current_proc->name); symbol->section = SECTION_TEXT; @@ -351,7 +351,7 @@ static void create_data_label(const char* label) { data_bb = bb_get(label); data_bb->is_fake = true; - APPEND(current_proc->blocks, data_bb); + array_append(¤t_proc->blocks, data_bb); } } diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index 77cdf39d9..fd18ab67b 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -1,16 +1,16 @@ #include "mcg.h" STATICMAP(graph); -STATICARRAY(struct ir, pops); -STATICARRAY(struct ir, pushes); +static ARRAYOF(struct ir) pops; +static ARRAYOF(struct ir) pushes; static struct ir* get_last_push(struct basicblock* bb) { int i; - for (i=bb->irs_count-1; i>=0; i--) + for (i=bb->irs.count-1; i>=0; i--) { - struct ir* ir = bb->irs[i]; + struct ir* ir = bb->irs.item[i]; if (ir->opcode == IR_PUSH) return ir; @@ -25,10 +25,10 @@ static struct ir* get_first_pop(struct basicblock* bb) { int i; - for (i=0; iirs_count; i++) + for (i=0; iirs.count; i++) { struct ir* irr; - struct ir* ir = bb->irs[i]; + struct ir* ir = bb->irs.item[i]; if (ir->opcode == IR_PUSH) return NULL; @@ -55,11 +55,11 @@ static void make_bb_graph(struct procedure* proc) int i, j; graph_count = 0; - for (i=0; iblocks_count; i++) + for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks[i]; - for (j=0; jirs_count; j++) - ir_walk(bb->irs[j], collect_outputs_cb, bb); + struct basicblock* bb = proc->blocks.item[i]; + for (j=0; jirs.count; j++) + ir_walk(bb->irs.item[j], collect_outputs_cb, bb); } } @@ -68,7 +68,7 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) int i, j; struct ir* ir; - pushes_count = pops_count = 0; + pushes.count = pops.count = 0; for (;;) { struct ir* lastpush = get_last_push(bb); @@ -87,7 +87,7 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) ir = get_first_pop(outbb); if (!ir || (ir->size != lastpush->size)) return; - APPENDU(pops, ir); + array_appendu(&pops, ir); /* Also abort unless *every* predecessor block of the one we've * just found *also* ends in a push of the same size. */ @@ -101,7 +101,7 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) ir = get_last_push(inbb); if (!ir || (ir->size != lastpush->size)) return; - APPENDU(pushes, ir); + array_appendu(&pushes, ir); } } } @@ -109,22 +109,22 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) /* Okay, now we can wire them all up. */ - for (i=0; iis_sequence); *ir = *ir->left; ir->is_sequence = true; } - for (i=0; isize, pushir); - for (j=1; jsize, phi, pushes[j]); + for (j=1; jsize, phi, pushes.item[j]); phi->is_sequence = ir->is_sequence; *ir = *phi; @@ -138,8 +138,8 @@ void pass_convert_stack_ops(struct procedure* proc) make_bb_graph(proc); - for (i=0; iblocks_count; i++) - convert_block(proc, proc->blocks[i]); + for (i=0; iblocks.count; i++) + convert_block(proc, proc->blocks.item[i]); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_eliminatetrivialblocks.c b/mach/proto/mcg/pass_eliminatetrivialblocks.c index 3b7280466..a152d7c97 100644 --- a/mach/proto/mcg/pass_eliminatetrivialblocks.c +++ b/mach/proto/mcg/pass_eliminatetrivialblocks.c @@ -6,11 +6,11 @@ static bool rewrite_jumps_cb(struct ir* ir, void* user) { struct basicblock* bb = ir->u.bvalue; if (!bb->is_fake - && (bb->irs_count > 0) - && (bb->irs[0]->opcode == IR_JUMP) - && (bb->irs[0]->left->opcode == IR_BLOCK)) + && (bb->irs.count > 0) + && (bb->irs.item[0]->opcode == IR_JUMP) + && (bb->irs.item[0]->left->opcode == IR_BLOCK)) { - ir->u.bvalue = bb->irs[0]->left->u.bvalue; + ir->u.bvalue = bb->irs.item[0]->left->u.bvalue; } } @@ -21,9 +21,9 @@ static void rewrite_jumps(struct basicblock* bb) { int i; - for (i=0; iirs_count; i++) + for (i=0; iirs.count; i++) { - struct ir* ir = bb->irs[i]; + struct ir* ir = bb->irs.item[i]; ir_walk(ir, rewrite_jumps_cb, NULL); } } @@ -32,9 +32,9 @@ void pass_eliminate_trivial_blocks(struct procedure* proc) { int i; - for (i=0; iblocks_count; i++) + for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks[i]; + struct basicblock* bb = proc->blocks.item[i]; rewrite_jumps(bb); } } diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index aebfd9160..9d17c06e3 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -125,10 +125,10 @@ static void select_instructions(struct basicblock* bb) tracef('I', "I: BLOCK: %s\n", bb->name); - for (i=0; iirs_count; i++) + for (i=0; iirs.count; i++) { int insnno; - struct ir* ir = bb->irs[i]; + struct ir* ir = bb->irs.item[i]; burm_label(ir); insnno = burm_rule(ir->state_label, 1); @@ -145,9 +145,9 @@ void pass_instruction_selector(struct procedure* proc) vregcount = 1; - for (i=0; iblocks_count; i++) + for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks[i]; + struct basicblock* bb = proc->blocks.item[i]; select_instructions(bb); } } diff --git a/mach/proto/mcg/pass_removedeadblocks.c b/mach/proto/mcg/pass_removedeadblocks.c index af2d54d70..24cb41889 100644 --- a/mach/proto/mcg/pass_removedeadblocks.c +++ b/mach/proto/mcg/pass_removedeadblocks.c @@ -1,6 +1,6 @@ #include "mcg.h" -STATICARRAY(struct basicblock, used); +static ARRAYOF(struct basicblock) used; static void walk_blocks(struct basicblock* bb); @@ -15,12 +15,12 @@ static void walk_blocks(struct basicblock* bb) { int i; - if (!CONTAINS(used, bb)) + if (!array_contains(&used, bb)) { - APPENDU(used, bb); + array_append(&used, bb); - for (i=0; iirs_count; i++) - ir_walk(bb->irs[i], walk_blocks_cb, NULL); + for (i=0; iirs.count; i++) + ir_walk(bb->irs.item[i], walk_blocks_cb, NULL); } } @@ -28,12 +28,12 @@ void pass_remove_dead_blocks(struct procedure* proc) { int i, j; - used_count = 0; - walk_blocks(proc->blocks[0]); + used.count = 0; + walk_blocks(proc->blocks.item[0]); - proc->blocks_count = 0; - for (i=0; iblocks, used[i]); + proc->blocks.count = 0; + for (i=0; iblocks, used.item[i]); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_typeinference.c b/mach/proto/mcg/pass_typeinference.c index 4d57e3212..a3a8335ee 100644 --- a/mach/proto/mcg/pass_typeinference.c +++ b/mach/proto/mcg/pass_typeinference.c @@ -43,9 +43,9 @@ static void push_types_up(struct basicblock* bb) { int i; - for (i=0; iirs_count; i++) + for (i=0; iirs.count; i++) { - struct ir* ir = bb->irs[i]; + struct ir* ir = bb->irs.item[i]; ir->type = search_for_type(ir, ir->type); } } @@ -54,8 +54,8 @@ void pass_type_inference(struct procedure* proc) { int i; - for (i=0; iblocks_count; i++) - push_types_up(proc->blocks[i]); + for (i=0; iblocks.count; i++) + push_types_up(proc->blocks.item[i]); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 78d8f3311..2adc74c0f 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -5,9 +5,9 @@ static void print_blocks(char k, struct procedure* proc) int i; tracef(k, "%c: procedure %s\n", k, proc->name); - for (int i=0; iblocks_count; i++) + for (int i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks[i]; + struct basicblock* bb = proc->blocks.item[i]; int j; tracef(k, "%c:\n", k); @@ -15,8 +15,8 @@ static void print_blocks(char k, struct procedure* proc) bb->is_fake ? "FAKE " : "", bb->name); - for (int j=0; jirs_count; j++) - ir_print(k, bb->irs[j]); + for (int j=0; jirs.count; j++) + ir_print(k, bb->irs.item[j]); } } diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 92c7bcf3f..a0ebe0e3f 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -77,7 +77,7 @@ static struct ir* appendir(struct ir* ir) assert(current_bb != NULL); ir->is_sequence = true; - APPEND(current_bb->irs, ir); + array_append(¤t_bb->irs, ir); ir_print('0', ir); return ir; @@ -323,9 +323,9 @@ static struct ir* extract_block_refs(struct basicblock* bb) struct ir* outir = NULL; int i; - for (i=0; iems_count; i++) + for (i=0; iems.count; i++) { - struct em* em = bb->ems[i]; + struct em* em = bb->ems.item[i]; assert(em->opcode == op_bra); assert(em->paramtype == PARAM_BVALUE); @@ -651,9 +651,9 @@ static void generate_tree(struct basicblock* bb) current_bb = bb; reset_stack(); - for (i=0; iems_count; i++) + for (i=0; iems.count; i++) { - struct em* em = bb->ems[i]; + struct em* em = bb->ems.item[i]; tracef('E', "E: read %s ", em_mnem[em->opcode - sp_fmnem]); switch (em->paramtype) { @@ -696,8 +696,8 @@ void tb_procedure(struct procedure* current_proc) { int i; - for (i=0; iblocks_count; i++) - generate_tree(current_proc->blocks[i]); + for (i=0; iblocks.count; i++) + generate_tree(current_proc->blocks.item[i]); } diff --git a/modules/src/data/array.c b/modules/src/data/array.c index 9f61d2805..68fad1ff5 100644 --- a/modules/src/data/array.c +++ b/modules/src/data/array.c @@ -2,52 +2,56 @@ #include #include "array.h" -void array_append(void*** array, int* count, int* max, void* value) +void array_append(void* arrayp, void* value) { - if (*count == *max) - { - int newmax = (*max == 0) ? 8 : (*max * 2); - void** newarray = realloc(*array, newmax * sizeof(void*)); + struct array* array = arrayp; - *max = newmax; - *array = newarray; + if (array->count == array->max) + { + int newmax = (array->max == 0) ? 8 : (array->max * 2); + void** newarray = realloc(array->item, newmax * sizeof(void*)); + + array->max = newmax; + array->item = newarray; } - (*array)[*count] = value; - (*count)++; + array->item[array->count] = value; + array->count++; } -bool array_contains(void** array, int count, void* value) +bool array_contains(void* arrayp, void* value) { + struct array* array = arrayp; int i; - for (i=0; icount; i++) + if (array->item[i] == value) return true; return false; } -void array_appendu(void*** array, int* count, int* max, void* value) +void array_appendu(void* arrayp, void* value) { - if (!array_contains(*array, *count, value)) - array_append(array, count, max, value); + if (!array_contains(arrayp, value)) + array_append(arrayp, value); } -void array_remove(void** array, int* count, void* value) +void array_remove(void* arrayp, void* value) { + struct array* array = arrayp; int i; - for (i=0; i<*count; i++) + for (i=0; icount; i++) { - if (array[i] == value) + if (array->item[i] == value) { - while (i < (*count-1)) + while (i < (array->count-1)) { - array[i] = array[i+1]; + array->item[i] = array->item[i+1]; i++; } - (*count)--; + array->count--; return; } } diff --git a/modules/src/data/array.h b/modules/src/data/array.h index b3c9a03e5..156bad1e2 100644 --- a/modules/src/data/array.h +++ b/modules/src/data/array.h @@ -1,32 +1,26 @@ #ifndef ARRAY_H #define ARRAY_H -#define ARRAY(TYPE, NAME) \ - TYPE** NAME; \ - int NAME##_count; \ - int NAME##_max +/* Danger, Will Robinson! The type and the macro must be compatible. */ -#define STATICARRAY(TYPE, NAME) \ - static TYPE** NAME; \ - static int NAME##_count; \ - static int NAME##_max +struct array +{ + void** item; + int count; + int max; +}; -#define APPEND(ARRAY, VALUE) \ - array_append((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE) +#define ARRAYOF(TYPE) \ + struct { \ + TYPE** item; \ + int count; \ + int max; \ + } -#define CONTAINS(ARRAY, VALUE) \ - array_contains((void**) ARRAY, ARRAY##_count, VALUE) - -#define APPENDU(ARRAY, VALUE) \ - array_appendu((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE) - -#define REMOVE(ARRAY, VALUE) \ - array_remove((void**) ARRAY, &ARRAY##_count, VALUE) - -extern void array_append(void*** array, int* count, int* max, void* value); -extern bool array_contains(void** array, int count, void* value); -extern void array_appendu(void*** array, int* count, int* max, void* value); -extern void array_remove(void** array, int* count, void* value); +extern void array_append(void* array, void* value); +extern void array_appendu(void* array, void* value); +extern void array_remove(void* array, void* value); +extern bool array_contains(void* array, void* value); #endif From f552c9c7c6076bb2766267047991a892a3e0c299 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 26 Sep 2016 23:03:04 +0200 Subject: [PATCH 037/230] Move map into the data module. --- mach/proto/mcg/map.c | 58 --------------------------- mach/proto/mcg/map.h | 26 ------------ mach/proto/mcg/pass_convertstackops.c | 18 ++++----- modules/src/data/build.lua | 1 - modules/src/data/map.c | 58 +++++++++++++++++++++++++++ modules/src/data/map.h | 30 ++++++++++++++ 6 files changed, 97 insertions(+), 94 deletions(-) delete mode 100644 mach/proto/mcg/map.c delete mode 100644 mach/proto/mcg/map.h create mode 100644 modules/src/data/map.c create mode 100644 modules/src/data/map.h diff --git a/mach/proto/mcg/map.c b/mach/proto/mcg/map.c deleted file mode 100644 index 228cf8bcc..000000000 --- a/mach/proto/mcg/map.c +++ /dev/null @@ -1,58 +0,0 @@ -#include "mcg.h" - -static void extend(struct map_node** map, int* count, int* max) -{ - if (*count == *max) - { - int newmax = (*max == 0) ? 8 : (*max * 2); - struct map_node* newmap = realloc(*map, newmax * sizeof(struct map_node)); - if (!newmap) - fatal("memory allocation failure"); - - *max = newmax; - *map = newmap; - } -} - -void map_set(struct map_node** map, int* count, int* max, void* left, void* right) -{ - int i; - struct map_node* node; - - for (i=0; i<*count; i++) - { - node = &(*map)[i]; - if (node->left == left) - { - node->right = right; - return; - } - } - - extend(map, count, max); - node = &(*map)[*count]; - node->left = left; - node->right = right; - (*count)++; -} - -void map_add(struct map_node** map, int* count, int* max, void* left, void* right) -{ - int i; - struct map_node* node; - - for (i=0; i<*count; i++) - { - node = &(*map)[i]; - if ((node->left == left) && (node->right == right)) - return; - } - - extend(map, count, max); - node = &(*map)[*count]; - node->left = left; - node->right = right; - (*count)++; -} - -/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/map.h b/mach/proto/mcg/map.h deleted file mode 100644 index bf9d9e8e3..000000000 --- a/mach/proto/mcg/map.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef MAP_H -#define MAP_H - -struct map_node -{ - void* left; - void* right; -}; - -#define _MAP(MODIFIER, NAME) \ - MODIFIER struct map_node* NAME; \ - MODIFIER int NAME##_count; \ - MODIFIER int NAME##_max - -#define MAP(NAME) _MAP(, NAME) -#define STATICMAP(NAME) _MAP(static, NAME) - -#define MAP_SET(MAP, LEFT, RIGHT) \ - map_set(&MAP, &MAP##_count, &MAP##_max, LEFT, RIGHT) - -extern void map_set(struct map_node** map, int* count, int* max, void* left, void* right); -extern void map_add(struct map_node** map, int* count, int* max, void* left, void* right); - -#endif - - diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index fd18ab67b..adbe25068 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -1,6 +1,6 @@ #include "mcg.h" -STATICMAP(graph); +static MAPOF(struct basicblock, struct basicblock) graph; static ARRAYOF(struct ir) pops; static ARRAYOF(struct ir) pushes; @@ -46,7 +46,7 @@ static bool collect_outputs_cb(struct ir* ir, void* user) struct basicblock* caller = user; if (ir->opcode == IR_BLOCK) - MAP_SET(graph, caller, ir->u.bvalue); + map_addp(&graph, caller, ir->u.bvalue); return false; } @@ -54,7 +54,7 @@ static void make_bb_graph(struct procedure* proc) { int i, j; - graph_count = 0; + graph.count = 0; for (i=0; iblocks.count; i++) { struct basicblock* bb = proc->blocks.item[i]; @@ -78,11 +78,11 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) /* Abort unless *every* successor block of this one starts with a pop * of the same size... */ - for (i=0; isize != lastpush->size)) @@ -92,11 +92,11 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) /* Also abort unless *every* predecessor block of the one we've * just found *also* ends in a push of the same size. */ - for (j=0; jsize != lastpush->size)) diff --git a/modules/src/data/build.lua b/modules/src/data/build.lua index 7250f4f72..f9af7c519 100644 --- a/modules/src/data/build.lua +++ b/modules/src/data/build.lua @@ -6,4 +6,3 @@ clibrary { }, } - diff --git a/modules/src/data/map.c b/modules/src/data/map.c new file mode 100644 index 000000000..d75284762 --- /dev/null +++ b/modules/src/data/map.c @@ -0,0 +1,58 @@ +#include +#include +#include "map.h" + +static void append(void* mapp, void* left, void* right) +{ + struct map* map = mapp; + struct map_node* node; + + if (map->count == map->max) + { + int newmax = (map->max == 0) ? 8 : (map->max * 2); + struct map_node* newarray = realloc(map->item, newmax * sizeof(*newarray)); + + map->max = newmax; + map->item = newarray; + } + + node = &map->item[map->count]; + map->count++; + + node->left = left; + node->right = right; +} + +void map_putp(void* mapp, void* left, void* right) +{ + struct map* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct map_node* node = &map->item[i]; + if (node->left == left) + { + node->right = right; + return; + } + } + + append(map, left, right); +} + +void map_addp(void* mapp, void* left, void* right) +{ + struct map* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct map_node* node = &map->item[i]; + if ((node->left == left) && (node->right == right)) + return; + } + + append(map, left, right); +} + diff --git a/modules/src/data/map.h b/modules/src/data/map.h new file mode 100644 index 000000000..859618bd7 --- /dev/null +++ b/modules/src/data/map.h @@ -0,0 +1,30 @@ +#ifndef MAP_H +#define MAP_H + +struct map_node +{ + void* left; + void* right; +}; + +/* Danger, Will Robinson! The type and the macro must be compatible. */ + +struct map +{ + struct map_node* item; + int count; + int max; +}; + +#define MAPOF(LEFT, RIGHT) \ + struct { \ + struct { LEFT* left; RIGHT* right; }* item; \ + int count; \ + int max; \ + } + +extern void map_putp(void* map, void* left, void* right); +extern void map_addp(void* map, void* left, void* right); + +#endif + From e77c5164cf96c98150ad8092170c49fb59091cc0 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 27 Sep 2016 00:19:45 +0200 Subject: [PATCH 038/230] Fleshed out hops and vregs. The result is almost looking like code now --- uncanny. --- mach/proto/mcg/hop.c | 87 ++++++++++++---- mach/proto/mcg/hop.h | 18 ++-- mach/proto/mcg/ir.h | 4 +- mach/proto/mcg/main.c | 3 +- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_instructionselection.c | 110 +++++---------------- mach/proto/mcg/table | 2 +- mach/proto/mcg/vreg.c | 10 ++ mach/proto/mcg/vreg.h | 13 +++ 9 files changed, 128 insertions(+), 120 deletions(-) create mode 100644 mach/proto/mcg/vreg.c create mode 100644 mach/proto/mcg/vreg.h diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index ccc180540..9a87a341b 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -1,39 +1,92 @@ #include "mcg.h" +static char outbuf[256]; +static struct hop* current_hop; + +static const struct burm_emitter_data emitter_data; + struct hop* new_hop(int insn_no, struct ir* ir) { struct hop* hop = calloc(1, sizeof *hop); hop->insn_no = insn_no; hop->ir = ir; + return hop; } -static void add_reg(struct vreg* vregs[], struct vreg* vreg) +static void append(const char* fmt, ...) { - int i; - - for (i=0; iinvregs, vreg); + struct hop* hop = ir->hop; + if (hop) + { + /* Reference to another hop must be its result register. */ + append("%%%d", hop->resultvreg->id); + } + else + { + /* ...if there is no hop, it's a fragment. */ + const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no]; + insndata->emitter(ir, &emitter_data); + } } -void hop_add_out_reg(struct hop* hop, struct vreg* vreg) +static void emit_string(const char* data) { - add_reg(hop->outvregs, vreg); + append("%s", data); } -void hop_emit(struct hop* hop, const struct burm_emitter_data* ed) +static void emit_value(struct ir* ir) { + append("(val)"); +} + +static void emit_resultreg(void) +{ + append("%%%d", current_hop->resultvreg->id); +} + +static void emit_eoi(void) +{ + append("\n"); +} + +static const struct burm_emitter_data emitter_data = +{ + &emit_string, + &emit_reg, + &emit_value, + &emit_resultreg, + &emit_eoi +}; + +void hop_print(char k, struct hop* hop) +{ + char* s; const struct burm_instruction_data* insndata = &burm_instruction_data[hop->insn_no]; - insndata->emitter(hop->ir, ed); + + current_hop = hop; + outbuf[0] = 0; + if (insndata->emitter) + { + insndata->emitter(hop->ir, &emitter_data); + + s = strtok(outbuf, "\n"); + do + { + tracef(k, "%c: %p: %s\n", k, hop, s); + s = strtok(NULL, "\n"); + } + while (s); + } + else + tracef(k, "%c: %p: (empty)\n", k, hop); } diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index d6cc6e79d..2cb0c9f72 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -1,26 +1,20 @@ #ifndef HOP_H #define HOP_H -struct vreg -{ - int id; - int regclass; -}; - -#define HOP_INOUT_REGS 4 - struct hop { int insn_no; struct ir* ir; - struct vreg* invregs[HOP_INOUT_REGS]; - struct vreg* outvregs[HOP_INOUT_REGS]; + struct vreg* resultvreg; + ARRAYOF(struct vreg) invregs; + ARRAYOF(struct vreg) outvregs; + ARRAYOF(struct vreg) newvregs; + ARRAYOF(struct vreg) deadvregs; }; extern struct hop* new_hop(int insn_no, struct ir* ir); -extern void hop_add_in_reg(struct hop* hop, struct vreg* reg); -extern void hop_add_out_reg(struct hop* hop, struct vreg* reg); +extern void hop_print(char k, struct hop* hop); #endif diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 79dbfdb8f..f63272a6c 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -20,8 +20,8 @@ struct ir } u; void* state_label; /* used by the iburg instruction selector */ - int insn_no; - int vreg; + int insn_no; /* the table rule number for this instruction */ + struct hop* hop; /* only for IRs that root a hardware op */ bool is_sequence : 1; bool is_generated : 1; diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 83d510107..c17b60bb0 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -41,7 +41,8 @@ bool tracing(char k) case 'E': return false; case '0': return false; case '1': return false; - case '2': return true; + case '2': return false; + case 'I': return true; default: return true; } } diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 8cf16f952..746f3924c 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -20,6 +20,7 @@ #include "map.h" #include "ir.h" #include "mcgg.h" +#include "vreg.h" #include "hop.h" extern char em_pseu[][4]; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 9d17c06e3..a2a993c82 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -1,29 +1,6 @@ #include "mcg.h" -static int vregcount; - -#if 0 -static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) { -#ifdef TRACE - int eruleno = burm_rule(STATE_LABEL(p), goalnt); - const short *nts = burm_nts[eruleno]; - NODEPTR_TYPE kids[10]; - int i; - - for (i = 0; i < indent; i++) - fprintf(stderr, " "); - fprintf(stderr, "%s\n", burm_string[eruleno]); - burm_kids(p, eruleno, kids); - for (i = 0; nts[i]; i++) - { - if (kids[i]) - dumpCover(kids[i], nts[i], indent + 1); - else - fprintf(stderr, "failed!\n"); - } -#endif -} -#endif +static struct basicblock* current_bb; void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) { const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; @@ -39,72 +16,30 @@ void burm_panic_cannot_match(struct ir* ir) exit(1); } -static const struct burm_emitter_data emitter_data; - -static void emit_string(const char* data) -{ - tracef('I', "I: emit: %s\n", data); -} - -static void emit_reg(struct ir* ir) -{ - const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no]; - if (insndata->is_fragment) - insndata->emitter(ir, &emitter_data); - else - tracef('I', "I: emit reg %d\n", ir->vreg); -} - -static void emit_value(struct ir* ir) -{ - tracef('I', "I: emit value\n"); -} - -static void emit_resultreg(void) -{ - tracef('I', "I: emit resultreg\n"); -} - -static void emit_eoi(void) -{ - tracef('I', "I: emit eoi\n"); -} - -static const struct burm_emitter_data emitter_data = -{ - &emit_string, - &emit_reg, - &emit_value, - &emit_resultreg, - &emit_eoi -}; - -static void walk_instructions(struct ir* ir, int goal) +static void walk_instructions(struct hop* hop, struct ir* ir, int goal) { struct ir* children[10]; int insn_no = burm_rule(ir->state_label, goal); const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; const short* nts = burm_nts[insn_no]; int i; - int resultreg = 0; - + ir->insn_no = insn_no; + if (!insndata->is_fragment) + hop = ir->hop = new_hop(insn_no, ir);; if (insndata->allocate) { - resultreg = vregcount++; - tracef('I', "I: new %s %d\n", - burm_register_class_names[insndata->allocate], resultreg); + hop->resultvreg = new_vreg(); + array_append(&hop->newvregs, hop->resultvreg); + array_append(&hop->outvregs, hop->resultvreg); } burm_kids(ir, insn_no, children); for (i=0; nts[i]; i++) - walk_instructions(children[i], nts[i]); + walk_instructions(hop, children[i], nts[i]); - if (ir->vreg) - tracef('I', "I: use %d\n", ir->vreg); - if (resultreg) - ir->vreg = resultreg; + ir->is_generated = true; tracef('I', "I: $%d %s selected %s %d: %s\n", ir->id, @@ -112,30 +47,33 @@ static void walk_instructions(struct ir* ir, int goal) insndata->is_fragment ? "fragment" : "instruction", insn_no, insndata->name); - ir->is_generated = true; - if (!insndata->is_fragment && insndata->emitter) - insndata->emitter(ir, &emitter_data); + if (!insndata->is_fragment) + { + array_append(¤t_bb->hops, hop); + hop_print('I', hop); + } } -static void select_instructions(struct basicblock* bb) +static void select_instructions(void) { int i; - tracef('I', "I: BLOCK: %s\n", bb->name); + tracef('I', "I: BLOCK: %s\n", current_bb->name); - for (i=0; iirs.count; i++) + for (i=0; iirs.count; i++) { int insnno; - struct ir* ir = bb->irs.item[i]; + struct ir* ir = current_bb->irs.item[i]; burm_label(ir); insnno = burm_rule(ir->state_label, 1); if (!insnno) burm_panic_cannot_match(ir); - walk_instructions(ir, 1); + ir_print('I', ir); + walk_instructions(NULL, ir, 1); } } @@ -143,12 +81,10 @@ void pass_instruction_selector(struct procedure* proc) { int i; - vregcount = 1; - for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks.item[i]; - select_instructions(bb); + current_bb = proc->blocks.item[i]; + select_instructions(); } } diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index d450842aa..f0303a442 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -102,7 +102,7 @@ PATTERNS CJUMPEQ(value:tristate, PAIR(true:BLOCK4, false:BLOCK4)) emit "beq $true" - emit "bne $false" + emit "b $false" cost 8; diff --git a/mach/proto/mcg/vreg.c b/mach/proto/mcg/vreg.c new file mode 100644 index 000000000..c841822f8 --- /dev/null +++ b/mach/proto/mcg/vreg.c @@ -0,0 +1,10 @@ +#include "mcg.h" + +static int vreg_count = 0; + +struct vreg* new_vreg(void) +{ + struct vreg* vreg = calloc(1, sizeof *vreg); + vreg->id = vreg_count++; + return vreg; +} diff --git a/mach/proto/mcg/vreg.h b/mach/proto/mcg/vreg.h new file mode 100644 index 000000000..b764d3883 --- /dev/null +++ b/mach/proto/mcg/vreg.h @@ -0,0 +1,13 @@ +#ifndef VREG_H +#define VREG_H + +struct vreg +{ + int id; +}; + +extern struct vreg* new_vreg(void); + +#endif + + From 4572f1b774478332d3c38c71315637dd01f4b8bf Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 27 Sep 2016 23:38:47 +0200 Subject: [PATCH 039/230] Actually, I don't need vregs: hops work just as well. Particularly if I restructure things so that I don't need to walk the blasted ir / burg tree every time I look at an instruction. --- mach/proto/mcg/build.lua | 1 - mach/proto/mcg/hop.c | 118 ++++++++++++--------- mach/proto/mcg/hop.h | 34 +++++- mach/proto/mcg/mcg.h | 1 - mach/proto/mcg/pass_instructionselection.c | 68 ++++++++++-- mach/proto/mcg/table | 15 +++ mach/proto/mcg/vreg.c | 10 -- mach/proto/mcg/vreg.h | 13 --- 8 files changed, 166 insertions(+), 94 deletions(-) delete mode 100644 mach/proto/mcg/vreg.c delete mode 100644 mach/proto/mcg/vreg.h diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index dc3504294..0626c4a3c 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -28,7 +28,6 @@ cprogram { vars = { ["+cflags"] = { "-Werror-implicit-function-declaration", - "-Wint-conversion" } } } diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 9a87a341b..510190c70 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -1,6 +1,6 @@ #include "mcg.h" -static char outbuf[256]; +static int hop_count = 1; static struct hop* current_hop; static const struct burm_emitter_data emitter_data; @@ -8,85 +8,97 @@ static const struct burm_emitter_data emitter_data; struct hop* new_hop(int insn_no, struct ir* ir) { struct hop* hop = calloc(1, sizeof *hop); + hop->id = hop_count++; hop->insn_no = insn_no; hop->ir = ir; return hop; } -static void append(const char* fmt, ...) +static struct insel* new_insel(enum insel_type type) { - va_list ap; - - va_start(ap, fmt); - vsprintf(outbuf + strlen(outbuf), fmt, ap); - va_end(ap); + struct insel* insel = calloc(1, sizeof(*insel)); + insel->type = type; + return insel; } -static void emit_reg(struct ir* ir) +void hop_add_string_insel(struct hop* hop, const char* string) { - struct hop* hop = ir->hop; - if (hop) - { - /* Reference to another hop must be its result register. */ - append("%%%d", hop->resultvreg->id); - } - else - { - /* ...if there is no hop, it's a fragment. */ - const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no]; - insndata->emitter(ir, &emitter_data); - } + struct insel* insel = new_insel(INSEL_STRING); + insel->u.string = string; + array_append(&hop->insels, insel); } -static void emit_string(const char* data) +void hop_add_reg_insel(struct hop* hop, struct hop* reg) { - append("%s", data); + struct insel* insel = new_insel(INSEL_REG); + insel->u.reg = reg; + array_append(&hop->insels, insel); } -static void emit_value(struct ir* ir) +void hop_add_value_insel(struct hop* hop, struct ir* ir) { - append("(val)"); + struct insel* insel = new_insel(INSEL_VALUE); + insel->u.value = ir; + array_append(&hop->insels, insel); } -static void emit_resultreg(void) +void hop_add_eoi_insel(struct hop* hop) { - append("%%%d", current_hop->resultvreg->id); + struct insel* insel = new_insel(INSEL_EOI); + array_append(&hop->insels, insel); } -static void emit_eoi(void) -{ - append("\n"); -} - -static const struct burm_emitter_data emitter_data = -{ - &emit_string, - &emit_reg, - &emit_value, - &emit_resultreg, - &emit_eoi -}; - void hop_print(char k, struct hop* hop) { - char* s; - const struct burm_instruction_data* insndata = &burm_instruction_data[hop->insn_no]; + int i; + bool soi = true; - current_hop = hop; - outbuf[0] = 0; - if (insndata->emitter) + i = 0; + for (i=0; iinsels.count; i++) { - insndata->emitter(hop->ir, &emitter_data); + struct insel* insel = hop->insels.item[i]; - s = strtok(outbuf, "\n"); - do + if (soi) { - tracef(k, "%c: %p: %s\n", k, hop, s); - s = strtok(NULL, "\n"); + tracef(k, "%c: %d: ", k, hop->id); + soi = false; + } + + switch (insel->type) + { + case INSEL_EOI: + tracef(k, "\n"); + soi = true; + break; + + case INSEL_REG: + tracef(k, "%%%d", insel->u.reg->id); + break; + + case INSEL_STRING: + tracef(k, "%s", insel->u.string); + break; + + case INSEL_VALUE: + { + struct ir* ir = insel->u.value; + switch (ir->opcode) + { + case IR_BLOCK: + tracef(k, "%s", ir->u.bvalue->name); + break; + + case IR_LOCAL: + case IR_CONST: + tracef(k, "0x%d", ir->u.ivalue); + break; + } + break; + } } - while (s); } - else - tracef(k, "%c: %p: (empty)\n", k, hop); + + if (!soi) + tracef(k, "\n", k); } diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 2cb0c9f72..8f92d898e 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -1,19 +1,43 @@ #ifndef HOP_H #define HOP_H +enum insel_type +{ + INSEL_STRING, + INSEL_REG, + INSEL_VALUE, + INSEL_EOI +}; + +struct insel +{ + enum insel_type type; + union + { + const char* string; + struct hop* reg; + struct ir* value; + } + u; +}; + struct hop { + int id; int insn_no; struct ir* ir; - struct vreg* resultvreg; - ARRAYOF(struct vreg) invregs; - ARRAYOF(struct vreg) outvregs; - ARRAYOF(struct vreg) newvregs; - ARRAYOF(struct vreg) deadvregs; + struct hop* result; + ARRAYOF(struct hop) params; + ARRAYOF(struct insel) insels; }; extern struct hop* new_hop(int insn_no, struct ir* ir); +extern void hop_add_string_insel(struct hop* hop, const char* string); +extern void hop_add_reg_insel(struct hop* hop, struct hop* reg); +extern void hop_add_value_insel(struct hop* hop, struct ir* ir); +extern void hop_add_eoi_insel(struct hop* hop); + extern void hop_print(char k, struct hop* hop); #endif diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 746f3924c..8cf16f952 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -20,7 +20,6 @@ #include "map.h" #include "ir.h" #include "mcgg.h" -#include "vreg.h" #include "hop.h" extern char em_pseu[][4]; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index a2a993c82..13d3d892a 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -1,6 +1,9 @@ #include "mcg.h" static struct basicblock* current_bb; +static struct hop* current_hop; + +static const struct burm_emitter_data emitter_data; void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) { const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; @@ -16,28 +19,67 @@ void burm_panic_cannot_match(struct ir* ir) exit(1); } -static void walk_instructions(struct hop* hop, struct ir* ir, int goal) +static void emit_reg(struct ir* ir) +{ + if (ir->hop) + hop_add_reg_insel(current_hop, ir->hop); + else + { + const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no]; + if (insndata->emitter) + insndata->emitter(ir, &emitter_data); + } +} + +static void emit_string(const char* data) +{ + hop_add_string_insel(current_hop, data); +} + +static void emit_value(struct ir* ir) +{ + hop_add_value_insel(current_hop, ir); +} + +static void emit_resultreg(void) +{ + hop_add_reg_insel(current_hop, current_hop); +} + +static void emit_eoi(void) +{ + hop_add_eoi_insel(current_hop); +} + +static const struct burm_emitter_data emitter_data = +{ + &emit_string, + &emit_reg, + &emit_value, + &emit_resultreg, + &emit_eoi +}; + + +static void walk_instructions(struct ir* ir, int goal) { struct ir* children[10]; int insn_no = burm_rule(ir->state_label, goal); const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; const short* nts = burm_nts[insn_no]; + struct hop* parent_hop = NULL; int i; ir->insn_no = insn_no; if (!insndata->is_fragment) - hop = ir->hop = new_hop(insn_no, ir);; - - if (insndata->allocate) { - hop->resultvreg = new_vreg(); - array_append(&hop->newvregs, hop->resultvreg); - array_append(&hop->outvregs, hop->resultvreg); + parent_hop = current_hop; + current_hop = ir->hop = new_hop(insn_no, ir); } burm_kids(ir, insn_no, children); for (i=0; nts[i]; i++) - walk_instructions(hop, children[i], nts[i]); + walk_instructions(children[i], nts[i]); ir->is_generated = true; @@ -50,8 +92,12 @@ static void walk_instructions(struct hop* hop, struct ir* ir, int goal) if (!insndata->is_fragment) { - array_append(¤t_bb->hops, hop); - hop_print('I', hop); + if (insndata->emitter) + insndata->emitter(ir, &emitter_data); + + hop_print('I', current_hop); + array_append(¤t_bb->hops, current_hop); + current_hop = parent_hop; } } @@ -73,7 +119,7 @@ static void select_instructions(void) burm_panic_cannot_match(ir); ir_print('I', ir); - walk_instructions(NULL, ir, 1); + walk_instructions(ir, 1); } } diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index f0303a442..3348787c3 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -21,6 +21,7 @@ DECLARATIONS aluparam fragment; reg allocates(GPR); tristate allocates(CC); + bistate allocates(CC); PATTERNS @@ -105,6 +106,11 @@ PATTERNS emit "b $false" cost 8; + CJUMPEQ(value:bistate, PAIR(true:BLOCK4, false:BLOCK4)) + emit "beq $true" + emit "b $false" + cost 8; + /* Comparisons */ @@ -112,12 +118,21 @@ PATTERNS emit "cmp %left, %right" cost 4; + bistate = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4) + emit "cmp %left, %right" + cost 4; + reg = tristate emit "mov %reg, #0" emit "movlt %reg, #-1" emit "movgt %reg, #1" cost 12; + reg = bistate + emit "moveq %reg, #1" + emit "movne %reg, #0" + cost 8; + /* Conversions */ diff --git a/mach/proto/mcg/vreg.c b/mach/proto/mcg/vreg.c deleted file mode 100644 index c841822f8..000000000 --- a/mach/proto/mcg/vreg.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "mcg.h" - -static int vreg_count = 0; - -struct vreg* new_vreg(void) -{ - struct vreg* vreg = calloc(1, sizeof *vreg); - vreg->id = vreg_count++; - return vreg; -} diff --git a/mach/proto/mcg/vreg.h b/mach/proto/mcg/vreg.h deleted file mode 100644 index b764d3883..000000000 --- a/mach/proto/mcg/vreg.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef VREG_H -#define VREG_H - -struct vreg -{ - int id; -}; - -extern struct vreg* new_vreg(void); - -#endif - - From ba1a3656a14e9b71ca4e0608eb32b808f7e8de86 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 28 Sep 2016 23:39:00 +0200 Subject: [PATCH 040/230] You can tell whether an item already exists in the array when calling array_appendu() now. --- modules/src/data/array.c | 9 ++++++--- modules/src/data/array.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/src/data/array.c b/modules/src/data/array.c index 68fad1ff5..8943323cb 100644 --- a/modules/src/data/array.c +++ b/modules/src/data/array.c @@ -31,10 +31,13 @@ bool array_contains(void* arrayp, void* value) return false; } -void array_appendu(void* arrayp, void* value) +bool array_appendu(void* arrayp, void* value) { - if (!array_contains(arrayp, value)) - array_append(arrayp, value); + if (array_contains(arrayp, value)) + return true; + + array_append(arrayp, value); + return false; } void array_remove(void* arrayp, void* value) diff --git a/modules/src/data/array.h b/modules/src/data/array.h index 156bad1e2..601873571 100644 --- a/modules/src/data/array.h +++ b/modules/src/data/array.h @@ -18,7 +18,7 @@ struct array } extern void array_append(void* array, void* value); -extern void array_appendu(void* array, void* value); +extern bool array_appendu(void* array, void* value); extern void array_remove(void* array, void* value); extern bool array_contains(void* array, void* value); From a0131fdb479e664d86c941de5c416d02d8c554c1 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 29 Sep 2016 19:58:02 +0200 Subject: [PATCH 041/230] You know what, the type inference stuff is a complete red herring. What this actually needs is a more intelligent register allocator. So, remove the type inference. --- mach/proto/mcg/ir.c | 6 -- mach/proto/mcg/ir.h | 1 - mach/proto/mcg/mcg.h | 1 - mach/proto/mcg/pass_typeinference.c | 63 --------------- mach/proto/mcg/procedure.c | 1 - mach/proto/mcg/table | 2 +- util/mcgg/ir.dat | 114 ++++++++++++---------------- util/mcgg/ircodes.h | 11 --- util/mcgg/ircodes.sh | 12 +-- 9 files changed, 51 insertions(+), 160 deletions(-) delete mode 100644 mach/proto/mcg/pass_typeinference.c diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index 9d1dab112..4d61bddeb 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -106,12 +106,6 @@ static void print_expr(char k, const struct ir* ir) tracef(k, "%s", ir_data[ir->opcode].name); if (ir->size) tracef(k, "%d", ir->size); - if (ir->type) - tracef(k, ".%s", - ((ir->type == IRT_INT) ? "I" : - (ir->type == IRT_FLOAT) ? "F" : - (ir->type == IRT_ANY) ? "*" : - "?")); tracef(k, "("); switch (ir->opcode) diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index f63272a6c..d38ecf1d5 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -8,7 +8,6 @@ struct ir int id; enum ir_opcode opcode; int size; - enum ir_type type; struct ir* left; struct ir* right; union diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 8cf16f952..a836ecc2f 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -123,7 +123,6 @@ extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_instruction_selector(struct procedure* proc); -extern void pass_type_inference(struct procedure* proc); extern void procedure_compile(struct procedure* proc); diff --git a/mach/proto/mcg/pass_typeinference.c b/mach/proto/mcg/pass_typeinference.c deleted file mode 100644 index a3a8335ee..000000000 --- a/mach/proto/mcg/pass_typeinference.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "mcg.h" - -static enum ir_type search_for_type(struct ir* ir, enum ir_type desired) -{ - const struct ir_data* data; - - if (ir->type != IRT_UNSET) - return ir->type; - - data = &ir_data[ir->opcode]; - if (ir->left) - ir->left->type = search_for_type(ir->left, data->lefttype); - if (ir->right) - ir->right->type = search_for_type(ir->right, data->righttype); - - switch (data->returntype) - { - case IRT_ANY: - if (desired == IRT_FLOAT) - ir->opcode++; - return desired; - - case IRT_UNSET: - assert(!((data->lefttype == IRT_ANY) && (data->righttype == IRT_ANY))); - if (((data->lefttype == IRT_ANY) && (ir->left->type == IRT_FLOAT)) || - ((data->righttype == IRT_ANY) && (ir->right->type == IRT_FLOAT))) - { - ir->opcode++; - return IRT_FLOAT; - } - if ((data->lefttype == IRT_ANY) && (ir->left->type == IRT_ANY)) - ir->left->type = IRT_INT; - if ((data->righttype == IRT_ANY) && (ir->right->type == IRT_ANY)) - ir->right->type = IRT_INT; - return IRT_INT; - - default: - return data->returntype; - } -} - -static void push_types_up(struct basicblock* bb) -{ - int i; - - for (i=0; iirs.count; i++) - { - struct ir* ir = bb->irs.item[i]; - ir->type = search_for_type(ir, ir->type); - } -} - -void pass_type_inference(struct procedure* proc) -{ - int i; - - for (i=0; iblocks.count; i++) - push_types_up(proc->blocks.item[i]); -} - -/* vim: set sw=4 ts=4 expandtab : */ - - diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 2adc74c0f..a27aeedf7 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -29,7 +29,6 @@ void procedure_compile(struct procedure* proc) pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); pass_convert_stack_ops(proc); - pass_type_inference(proc); print_blocks('2', proc); diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 3348787c3..9bd39d4b5 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -174,4 +174,4 @@ PATTERNS reg = value:CONST4 emit "ldr %reg, #$value" - cost 4; + cost 8; diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 46be39408..3dd785b5c 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -1,92 +1,76 @@ # Flags: # S: has size (use in CONST1, CONST2, CONST4, CONST8 forms) # V: has no size (use in JUMP, CJUMP, RET forms) -# -# Types: -# I, F: integer, float -# A: any (will be coerced to I or F during IR postprocessing) -# -# Any instruction with an A type must be followed by the corresponding F -# version. # Simple terminals -SA.. CONST -SF.. CONSTF -SA.. REG -SF.. REGF -SI.. LABEL -SI.. BLOCK -V... PAIR -SA.. ANY -SF.. ANYF -S... LOCAL -S... PHI +S CONST +S REG +S LABEL +S BLOCK +V PAIR +S ANY +S LOCAL +S PHI # Magic stack operations -S.A. PUSH -S.F. PUSHF -SA.. POP -SF.. POPF +S PUSH +S POP #... Memory operations -SAI. LOAD -SFI. LOADF -S.IA STORE -S.IF STOREF +S LOAD +S STORE # Arithemetic operations -SIII ADD -SIII SUB -SIII MUL -SIII DIV -SIII MOD -SIII NEG +S ADD +S SUB +S MUL +S DIV +S MOD +S NEG -SFFF ADDF -SFFF SUBF -SFFF MULF -SFFF DIVF -SFFF NEGF +S ADDF +S SUBF +S MULF +S DIVF +S NEGF -SIII AND -SIII OR -SIII EOR -SIII NOT +S AND +S OR +S EOR +S NOT # Conversions -SIII CII1 -SIII CII2 -SIII CII4 -SIII CII8 +S CII1 +S CII2 +S CII4 +S CII8 -SIII CIU1 -SIII CIU2 -SIII CIU4 -SIII CIU8 +S CIU1 +S CIU2 +S CIU4 +S CIU8 # Tristate comparisons -SIII COMPARES -SIII COMPAREU +S COMPARES +S COMPAREU # Boolean comparisons -SIII IFEQ -SIII IFLT -SIII IFLE +S IFEQ +S IFLT +S IFLE # Procedures -VI.. CALL +V CALL # Flow control --- these never return -V.I. JUMP -VIII CJUMPEQ -VIII CJUMPLT -VIII CJUMPLE -V... RET +V JUMP +V CJUMPEQ +V CJUMPLT +V CJUMPLE +V RET # Special -SI.. STACKADJUST -SA.. GETRET -SF.. GETRETF -S.A. SETRET -S.F. SETRETF +S STACKADJUST +S GETRET +S SETRET diff --git a/util/mcgg/ircodes.h b/util/mcgg/ircodes.h index 99dbae7bb..c5bbb9f2d 100644 --- a/util/mcgg/ircodes.h +++ b/util/mcgg/ircodes.h @@ -6,21 +6,10 @@ enum IRF_SIZED = 1, }; -enum ir_type -{ - IRT_UNSET = 0, - IRT_INT, - IRT_FLOAT, - IRT_ANY -}; - struct ir_data { const char* name; int flags; - enum ir_type returntype; - enum ir_type lefttype; - enum ir_type righttype; }; extern const struct ir_data ir_data[]; diff --git a/util/mcgg/ircodes.sh b/util/mcgg/ircodes.sh index e4d289da7..7c9917d12 100755 --- a/util/mcgg/ircodes.sh +++ b/util/mcgg/ircodes.sh @@ -25,13 +25,6 @@ awk -f - $in >$source << "EOF" print "const struct ir_data ir_data[IR__COUNT] = {" } - function char_to_type(c) { - if (c == "I") return "IRT_INT" - if (c == "F") return "IRT_FLOAT" - if (c == "A") return "IRT_ANY" - return "IRT_UNSET" - } - function char_to_flags(c) { if (c == "S") return "IRF_SIZED" return "0" @@ -39,10 +32,7 @@ awk -f - $in >$source << "EOF" /^ *[^# ]+/ { printf("\t{ \"%s\", ", $2) - printf("%s, ", char_to_flags(substr($1, 1, 1))) - printf("%s, ", char_to_type(substr($1, 2, 1))) - printf("%s, ", char_to_type(substr($1, 3, 1))) - printf("%s", char_to_type(substr($1, 4, 1))) + printf("%s", char_to_flags(substr($1, 1, 1))) printf(" },\n") } From 0d246c0d73752e23e2b1660d75cbaf18db9455d4 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 29 Sep 2016 22:06:04 +0200 Subject: [PATCH 042/230] Much better handling of fragments (no run-time code needed to distinguish them from registers) and better handling of individual hops within a paragraph --- no more ghastly hacks to try and distinguish the input from the output. --- mach/proto/mcg/hop.c | 7 +-- mach/proto/mcg/hop.h | 12 +++-- mach/proto/mcg/ir.c | 8 ++-- mach/proto/mcg/ir.h | 4 +- mach/proto/mcg/mcgg_generated_header.h | 3 +- mach/proto/mcg/pass_convertstackops.c | 6 +-- mach/proto/mcg/pass_instructionselection.c | 30 ++++++------ mach/proto/mcg/table | 53 +++++++++++++++------- mach/proto/mcg/treebuilder.c | 4 +- util/mcgg/iburg.c | 30 ++++++++---- util/mcgg/mcgg.h | 3 +- 11 files changed, 97 insertions(+), 63 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 510190c70..35bed381b 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -28,10 +28,11 @@ void hop_add_string_insel(struct hop* hop, const char* string) array_append(&hop->insels, insel); } -void hop_add_reg_insel(struct hop* hop, struct hop* reg) +void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no) { struct insel* insel = new_insel(INSEL_REG); - insel->u.reg = reg; + insel->u.reg.ir = ir; + insel->u.reg.insn_no = insn_no; array_append(&hop->insels, insel); } @@ -72,7 +73,7 @@ void hop_print(char k, struct hop* hop) break; case INSEL_REG: - tracef(k, "%%%d", insel->u.reg->id); + tracef(k, "$%d.%d", insel->u.reg.ir->id, insel->u.reg.insn_no); break; case INSEL_STRING: diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 8f92d898e..e6cc8f809 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -15,7 +15,12 @@ struct insel union { const char* string; - struct hop* reg; + struct + { + struct ir* ir; + int insn_no; + } + reg; struct ir* value; } u; @@ -26,15 +31,13 @@ struct hop int id; int insn_no; struct ir* ir; - struct hop* result; - ARRAYOF(struct hop) params; ARRAYOF(struct insel) insels; }; extern struct hop* new_hop(int insn_no, struct ir* ir); extern void hop_add_string_insel(struct hop* hop, const char* string); -extern void hop_add_reg_insel(struct hop* hop, struct hop* reg); +extern void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no); extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_eoi_insel(struct hop* hop); @@ -42,4 +45,3 @@ extern void hop_print(char k, struct hop* hop); #endif - diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index 4d61bddeb..c4755b275 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -71,14 +71,14 @@ struct ir* ir_walk(struct ir* ir, ir_walker_t* cb, void* user) if (cb(ir, user)) return ir; - if (ir->left && !ir->left->is_sequence) + if (ir->left && !ir->left->is_root) { struct ir* irr = ir_walk(ir->left, cb, user); if (irr) return irr; } - if (ir->right && !ir->right->is_sequence) + if (ir->right && !ir->right->is_root) { struct ir* irr = ir_walk(ir->right, cb, user); if (irr) @@ -126,7 +126,7 @@ static void print_expr(char k, const struct ir* ir) default: if (ir->left) { - if (ir->left->is_sequence) + if (ir->left->is_root) tracef(k, "$%d", ir->left->id); else print_expr(k, ir->left); @@ -134,7 +134,7 @@ static void print_expr(char k, const struct ir* ir) if (ir->right) { tracef(k, ", "); - if (ir->right->is_sequence) + if (ir->right->is_root) tracef(k, "$%d", ir->right->id); else print_expr(k, ir->right); diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index d38ecf1d5..069a76bd5 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -20,9 +20,9 @@ struct ir void* state_label; /* used by the iburg instruction selector */ int insn_no; /* the table rule number for this instruction */ - struct hop* hop; /* only for IRs that root a hardware op */ + ARRAYOF(struct hop) hops; /* only for root IRs */ - bool is_sequence : 1; + bool is_root : 1; bool is_generated : 1; }; diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index fbe0603dd..a3e79afc0 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -6,9 +6,8 @@ static int OP_LABEL(struct ir* ir) { - if (ir->is_generated) + if (ir->is_root && ir->is_generated) { - assert(ir->is_sequence); return ir_to_esn(IR_REG, ir->size); } return ir_to_esn(ir->opcode, ir->size); diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index adbe25068..6f62fe747 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -112,9 +112,9 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) for (i=0; iis_sequence); + assert(ir->is_root); *ir = *ir->left; - ir->is_sequence = true; + ir->is_root = true; } for (i=0; isize, phi, pushes.item[j]); - phi->is_sequence = ir->is_sequence; + phi->is_root = ir->is_root; *ir = *phi; } } diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 13d3d892a..2b0bb96c3 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -19,16 +19,9 @@ void burm_panic_cannot_match(struct ir* ir) exit(1); } -static void emit_reg(struct ir* ir) +static void emit_reg(struct ir* ir, int goal) { - if (ir->hop) - hop_add_reg_insel(current_hop, ir->hop); - else - { - const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no]; - if (insndata->emitter) - insndata->emitter(ir, &emitter_data); - } + hop_add_reg_insel(current_hop, ir, goal); } static void emit_string(const char* data) @@ -36,6 +29,14 @@ static void emit_string(const char* data) hop_add_string_insel(current_hop, data); } +static void emit_fragment(struct ir* ir, int goal) +{ + int insn_no = burm_rule(ir->state_label, goal); + const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; + if (insndata->emitter) + insndata->emitter(ir, &emitter_data); +} + static void emit_value(struct ir* ir) { hop_add_value_insel(current_hop, ir); @@ -43,7 +44,6 @@ static void emit_value(struct ir* ir) static void emit_resultreg(void) { - hop_add_reg_insel(current_hop, current_hop); } static void emit_eoi(void) @@ -54,6 +54,7 @@ static void emit_eoi(void) static const struct burm_emitter_data emitter_data = { &emit_string, + &emit_fragment, &emit_reg, &emit_value, &emit_resultreg, @@ -70,11 +71,10 @@ static void walk_instructions(struct ir* ir, int goal) struct hop* parent_hop = NULL; int i; - ir->insn_no = insn_no; if (!insndata->is_fragment) { parent_hop = current_hop; - current_hop = ir->hop = new_hop(insn_no, ir); + current_hop = new_hop(insn_no, ir); } burm_kids(ir, insn_no, children); @@ -82,10 +82,11 @@ static void walk_instructions(struct ir* ir, int goal) walk_instructions(children[i], nts[i]); ir->is_generated = true; + ir->insn_no = insn_no; tracef('I', "I: $%d %s selected %s %d: %s\n", ir->id, - ir->is_sequence ? "S" : " ", + ir->is_root ? "S" : " ", insndata->is_fragment ? "fragment" : "instruction", insn_no, insndata->name); @@ -96,12 +97,11 @@ static void walk_instructions(struct ir* ir, int goal) insndata->emitter(ir, &emitter_data); hop_print('I', current_hop); - array_append(¤t_bb->hops, current_hop); + array_append(&ir->hops, current_hop); current_hop = parent_hop; } } - static void select_instructions(void) { int i; diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 9bd39d4b5..4126b2f01 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,27 +1,38 @@ REGISTERS - r0 GPR RET0; - r1 GPR RET1; - r2 GPR; - r3 GPR; - r4 GPR; - r5 GPR; - r6 GPR; - r7 GPR; - r8 GPR; - r9 GPR; - r10 GPR; - r11 GPR; + r0 reg4 int ret0; + r1 reg4 int ret1; + r2 reg4 int; + r3 reg4 int; + r4 reg4 int; + r5 reg4 int; + r6 reg4 int; + r7 reg4 int; + r8 reg4 int; + r9 reg4 int; + r10 reg4 int; + r11 reg4 int; - cc CC; + s0 reg4 float; + s1 reg4 float; + s2 reg4 float; + s3 reg4 float; + s4 reg4 float; + s5 reg4 float; + s6 reg4 float; + s7 reg4 float; + s8 reg4 float; + s9 reg4 float; + + cc conditioncode; DECLARATIONS address fragment; aluparam fragment; - reg allocates(GPR); - tristate allocates(CC); - bistate allocates(CC); + reg allocates(reg4); + tristate allocates(conditioncode); + bistate allocates(conditioncode); PATTERNS @@ -158,7 +169,8 @@ PATTERNS aluparam = value:CONST4 emit "#$value"; - aluparam = reg; + aluparam = value:reg + emit "%value"; reg = value:aluparam emit "mov %reg, %value" @@ -175,3 +187,10 @@ PATTERNS reg = value:CONST4 emit "ldr %reg, #$value" cost 8; + +/* FPU operations */ + + reg = ADDF4(left:reg, right:reg) + emit "fadds %reg, %left, %right" + cost 4; + diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index a0ebe0e3f..58f19bdc2 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -76,7 +76,7 @@ static struct ir* appendir(struct ir* ir) int i; assert(current_bb != NULL); - ir->is_sequence = true; + ir->is_root = true; array_append(¤t_bb->irs, ir); ir_print('0', ir); @@ -479,7 +479,7 @@ static void insn_ivalue(int opcode, arith value) case op_dup: { struct ir* v = pop(value); - if (!v->is_sequence) + if (!v->is_root) appendir(v); push(v); push(v); diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index f29c85907..0e8cad407 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -295,7 +295,7 @@ struct regclass* getregclass(const char* id) { struct regclass* p = lookup(id); if (!p || (p->kind != REGCLASS)) - yyerror("'%p' is not the name of a register class"); + yyerror("'%s' is not the name of a register class", id); return p; } @@ -917,18 +917,22 @@ static void print_path(uint32_t path) static const uint32_t PATH_MISSING = 0xffffffff; -static uint32_t find_label(Tree root, const char* name, uint32_t path) +static uint32_t find_label(Tree root, const char* name, uint32_t path, Tree* found) { uint32_t p; if (root->label && (strcmp(root->label, name) == 0)) + { + if (found) + *found = root; return path; + } p = PATH_MISSING; if (root->left && (p == PATH_MISSING)) - p = find_label(root->left, name, path*3 + 1); + p = find_label(root->left, name, path*3 + 1, found); if (root->right && (p == PATH_MISSING)) - p = find_label(root->right, name, path*3 + 2); + p = find_label(root->right, name, path*3 + 2, found); return p; } @@ -963,15 +967,23 @@ static void emitinsndata(Rule rules) const char* label = f->data + 1; if (strcmp(label, r->lhs->name) == 0) - print("%1data->emit_resultreg();\n"); + print("%1data->emit_reg(node, %P%s_NT);\n", label); else { - uint32_t path = find_label(r->pattern, label, 0); - print("%1data->emit_reg("); + Tree node; + uint32_t path = find_label(r->pattern, label, 0, &node); + Nonterm nt = node->op; + if (path == PATH_MISSING) label_not_found(r, label); + + if (nt->is_fragment) + print("%1data->emit_fragment("); + else + print("%1data->emit_reg("); + print_path(path); - print(");\n"); + print(", %P%s_NT);\n", ((Nonterm)node->op)->name); } break; } @@ -979,7 +991,7 @@ static void emitinsndata(Rule rules) case '$': { const char* label = f->data + 1; - uint32_t path = find_label(r->pattern, label, 0); + uint32_t path = find_label(r->pattern, label, 0, NULL); print("%1data->emit_value("); if (path == PATH_MISSING) label_not_found(r, label); diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 004146bb3..0bbe4ae93 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -27,7 +27,8 @@ extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost); struct burm_emitter_data { void (*emit_string)(const char* data); - void (*emit_reg)(struct ir* ir); + void (*emit_fragment)(struct ir* ir, int goal); + void (*emit_reg)(struct ir* ir, int goal); void (*emit_value)(struct ir* ir); void (*emit_resultreg)(void); void (*emit_eoi)(void); From b27758b7de0d4bb20e29a1012824b25af9e13a26 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 29 Sep 2016 22:14:11 +0200 Subject: [PATCH 043/230] Error check fragment rules which don't emit anything. --- util/mcgg/iburg.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 0e8cad407..1fc0a7c22 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -1014,6 +1014,15 @@ static void emitinsndata(Rule rules) print("}\n\n"); } + else + { + /* This instruction has no code; make sure it's not a fragment. */ + if (r->lhs->is_fragment) + { + yylineno = r->lineno; + yyerror("rule is a fragment, but doesn't emit anything"); + } + } r = r->link; } From b32883b0131abaf9c9c0e4eab3672edf5ccd8a69 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 29 Sep 2016 22:32:43 +0200 Subject: [PATCH 044/230] More properly keep track of register classes. --- util/mcgg/gram.y | 1 + util/mcgg/iburg.c | 21 +++++++++++++++++---- util/mcgg/iburg.h | 1 + util/mcgg/mcgg.h | 8 ++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 177f33d72..26a0e9b5b 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "iburg.h" diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 1fc0a7c22..fa3d7d0b1 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -289,6 +289,8 @@ void addregclass(struct reg* reg, const char* id) p->link = *q; *q = p; } + + reg->classes |= 1<<(p->number); } struct regclass* getregclass(const char* id) @@ -437,12 +439,19 @@ static void print(char* fmt, ...) case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break; + + case 'x': + fprintf(outfp, "%x", va_arg(ap, uint32_t)); + break; + case 's': fputs(va_arg(ap, char*), outfp); break; + case 'P': fprintf(outfp, "%s_", prefix); break; + case 'T': { Tree t = va_arg(ap, Tree); @@ -453,15 +462,18 @@ static void print(char* fmt, ...) print("(%T)", t->left); break; } + case 'R': { Rule r = va_arg(ap, Rule); print("%S: %T", r->lhs, r->pattern); break; } + case 'S': fputs(va_arg(ap, Term)->name, outfp); break; + case '1': case '2': case '3': @@ -473,6 +485,7 @@ static void print(char* fmt, ...) putc('\t', outfp); break; } + default: putc(*fmt, outfp); break; @@ -530,14 +543,14 @@ static void emitregisterclasses(struct regclass* rc) static void emitregisters(struct reg* r) { int k = 0; - print("const char* %Pregister_names[] = {\n"); + print("const struct %Pregister_data %Pregister_data[] = {\n"); while (r) { for (; k < r->number; k++) - print("%1NULL,\n"); + print("%1{ 0 },\n"); k++; - print("%1\"%s\",\n", r->name); + print("%1{ \"%s\", %d },\n", r->name, r->classes); r = r->link; } print("};\n\n"); @@ -659,7 +672,7 @@ static void emitdefs(Nonterm nts, int ntnumber) for (p = nts; p; p = p->link) print("#define %P%S_NT %d\n", p, p->number); - print("static const int %Pmax_nt = %d;\n\n", ntnumber); + print("#define %Pmax_nt %d\n\n", ntnumber); print("const char *%Pntname[] = {\n%10,\n"); for (p = nts; p; p = p->link) print("%1\"%S\",\n", p); diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 5709ae13e..7bf8b8a0e 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -20,6 +20,7 @@ struct reg const char* name; /* register name */ Kind kind; /* REG */ int number; /* identifying number */ + uint32_t classes; // bitfield of classes */ struct reg* link; /* next in list */ }; diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 0bbe4ae93..a2f20b4b4 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -46,6 +46,14 @@ struct burm_instruction_data }; extern const struct burm_instruction_data burm_instruction_data[]; + +struct burm_register_data +{ + const char* name; + uint32_t classes; +}; + +extern const struct burm_register_data burm_register_data[]; extern const char* burm_register_class_names[]; #endif From 3a973a19f3ce8b5446d4a50b63cbed06318d875d Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 30 Sep 2016 19:10:30 +0200 Subject: [PATCH 045/230] Move fatal(), warning() and aprintf() into the new data module (because they're really useful). --- mach/proto/mcg/main.c | 33 ------------------- mach/proto/mcg/mcg.h | 3 +- mach/proto/mcg/table | 44 +++++++++++++------------- modules/src/data/astring.c | 27 ++++++++++++++++ modules/src/data/astring.h | 9 ++++++ modules/src/data/diagnostics.c | 38 ++++++++++++++++++++++ modules/src/data/diagnostics.h | 12 +++++++ modules/src/data/imap.c | 58 ++++++++++++++++++++++++++++++++++ modules/src/data/imap.h | 30 ++++++++++++++++++ util/mcgg/iburg.c | 47 ++++++++------------------- 10 files changed, 211 insertions(+), 90 deletions(-) create mode 100644 modules/src/data/astring.c create mode 100644 modules/src/data/astring.h create mode 100644 modules/src/data/diagnostics.c create mode 100644 modules/src/data/diagnostics.h create mode 100644 modules/src/data/imap.c create mode 100644 modules/src/data/imap.h diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index c17b60bb0..5d450bdfc 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -1,38 +1,5 @@ #include "mcg.h" -void fatal(const char* msg, ...) -{ - va_list ap; - va_start(ap, msg); - - vfprintf(stderr, msg, ap); - fprintf(stderr, "\n"); - - va_end(ap); - abort(); -} - -const char* aprintf(const char* fmt, ...) -{ - int n; - char* p; - va_list ap; - - va_start(ap, fmt); - n = vsnprintf(NULL, 0, fmt, ap) + 1; - va_end(ap); - - p = malloc(n); - if (!p) - return NULL; - - va_start(ap, fmt); - vsnprintf(p, n, fmt, ap); - va_end(ap); - - return p; -} - bool tracing(char k) { switch (k) diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index a836ecc2f..176efb535 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -18,6 +18,8 @@ #include "em_ptyp.h" #include "array.h" #include "map.h" +#include "diagnostics.h" +#include "astring.h" #include "ir.h" #include "mcgg.h" #include "hop.h" @@ -88,7 +90,6 @@ struct basicblock bool is_terminated : 1; }; -extern void fatal(const char* s, ...); extern const char* aprintf(const char* fmt, ...); extern void tracef(char k, const char* fmt, ...); extern bool tracing(char k); diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 4126b2f01..eac421ddf 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,28 +1,28 @@ REGISTERS - r0 reg4 int ret0; - r1 reg4 int ret1; - r2 reg4 int; - r3 reg4 int; - r4 reg4 int; - r5 reg4 int; - r6 reg4 int; - r7 reg4 int; - r8 reg4 int; - r9 reg4 int; - r10 reg4 int; - r11 reg4 int; + r0 reg4 i ret0; + r1 reg4 i; + r2 reg4 i; + r3 reg4 i; + r4 reg4 i; + r5 reg4 i; + r6 reg4 i; + r7 reg4 i; + r8 reg4 i; + r9 reg4 i; + r10 reg4 i; + r11 reg4 i; - s0 reg4 float; - s1 reg4 float; - s2 reg4 float; - s3 reg4 float; - s4 reg4 float; - s5 reg4 float; - s6 reg4 float; - s7 reg4 float; - s8 reg4 float; - s9 reg4 float; + s0 reg4 f; + s1 reg4 f; + s2 reg4 f; + s3 reg4 f; + s4 reg4 f; + s5 reg4 f; + s6 reg4 f; + s7 reg4 f; + s8 reg4 f; + s9 reg4 f; cc conditioncode; diff --git a/modules/src/data/astring.c b/modules/src/data/astring.c new file mode 100644 index 000000000..7da06e9fa --- /dev/null +++ b/modules/src/data/astring.c @@ -0,0 +1,27 @@ +#include +#include +#include + +const char* aprintf(const char* fmt, ...) +{ + int n; + char* p; + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + p = malloc(n); + if (!p) + return NULL; + + va_start(ap, fmt); + vsnprintf(p, n, fmt, ap); + va_end(ap); + + return p; +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/astring.h b/modules/src/data/astring.h new file mode 100644 index 000000000..483c0287d --- /dev/null +++ b/modules/src/data/astring.h @@ -0,0 +1,9 @@ +#ifndef ASTRING_H +#define ASTRING_H + +extern const char* aprintf(const char* fmt, ...); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/diagnostics.c b/modules/src/data/diagnostics.c new file mode 100644 index 000000000..32ac6a0ee --- /dev/null +++ b/modules/src/data/diagnostics.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "diagnostics.h" + +const char* program_name = NULL; + +void warning(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + if (program_name) + fprintf(stderr, "%s: ", program_name); + fprintf(stderr, "warning: "); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + + va_end(ap); +} + +void fatal(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + if (program_name) + fprintf(stderr, "%s: ", program_name); + fprintf(stderr, "fatal: "); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + + va_end(ap); + abort(); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/diagnostics.h b/modules/src/data/diagnostics.h new file mode 100644 index 000000000..7c2908fa0 --- /dev/null +++ b/modules/src/data/diagnostics.h @@ -0,0 +1,12 @@ +#ifndef DIAGNOSTICS_H +#define DIAGNOSTICS_H + +extern const char* program_name; + +extern void warning(const char* fmt, ...); +extern void fatal(const char* fmt, ...); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/modules/src/data/imap.c b/modules/src/data/imap.c new file mode 100644 index 000000000..15c66e769 --- /dev/null +++ b/modules/src/data/imap.c @@ -0,0 +1,58 @@ +#include +#include +#include "imap.h" + +static void append(void* mapp, int left, void* right) +{ + struct imap* map = mapp; + struct imap_node* node; + + if (map->count == map->max) + { + int newmax = (map->max == 0) ? 8 : (map->max * 2); + struct imap_node* newarray = realloc(map->item, newmax * sizeof(*newarray)); + + map->max = newmax; + map->item = newarray; + } + + node = &map->item[map->count]; + map->count++; + + node->left = left; + node->right = right; +} + +void imap_put(void* mapp, int left, void* right) +{ + struct imap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct imap_node* node = &map->item[i]; + if (node->left == left) + { + node->right = right; + return; + } + } + + append(map, left, right); +} + +void imap_add(void* mapp, int left, void* right) +{ + struct imap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct imap_node* node = &map->item[i]; + if ((node->left == left) && (node->right == right)) + return; + } + + append(map, left, right); +} + diff --git a/modules/src/data/imap.h b/modules/src/data/imap.h new file mode 100644 index 000000000..022368ec8 --- /dev/null +++ b/modules/src/data/imap.h @@ -0,0 +1,30 @@ +#ifndef IMAP_H +#define IMAP_H + +struct imap_node +{ + int left; + void* right; +}; + +/* Danger, Will Robinson! The type and the macro must be compatible. */ + +struct imap +{ + struct imap_node* item; + int count; + int max; +}; + +#define IMAPOF(RIGHT) \ + struct { \ + struct { int left; RIGHT* right; }* item; \ + int count; \ + int max; \ + } + +extern void imap_put(void* map, int left, void* right); +extern void imap_add(void* map, int left, void* right); + +#endif + diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index fa3d7d0b1..aeb68ae31 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -11,6 +11,7 @@ #include #include "iburg.h" #include "ircodes.h" +#include "astring.h" static char rcsid[] = "$Id$"; @@ -31,7 +32,7 @@ static void print(char* fmt, ...); static void ckreach(Nonterm p); static void registerterminals(void); static void emitclosure(Nonterm nts); -static void emitcost(Tree t, char* v); +static void emitcost(Tree t, const char* v); static void emitcostcalc(Rule r); static void emitdefs(Nonterm nts, int ntnumber); static void emitfuncs(void); @@ -50,7 +51,7 @@ static void emitstate(Term terms, Nonterm start, int ntnumber); static void emitstring(Rule rules); static void emitstruct(Nonterm nts, int ntnumber); static void emitterms(Term terms); -static void emittest(Tree t, char* v, char* suffix); +static void emittest(Tree t, const char* v, const char* suffix); extern int yy_flex_debug; @@ -154,31 +155,9 @@ int main(int argc, char* argv[]) return errcnt > 0; } -/* stringf - format and save a string */ -char* stringf(char* fmt, ...) -{ - int n; - char* p; - va_list ap; - - va_start(ap, fmt); - n = vsnprintf(NULL, 0, fmt, ap) + 1; - va_end(ap); - - p = malloc(n); - if (!p) - return NULL; - - va_start(ap, fmt); - vsnprintf(p, n, fmt, ap); - va_end(ap); - - return p; -} - static void registerterminal(const struct ir_data* data, int iropcode, int size) { - const char* s = (size == 0) ? data->name : stringf("%s%d", data->name, size); + const char* s = (size == 0) ? data->name : aprintf("%s%d", data->name, size); int esn = ir_to_esn(iropcode, size); term(s, esn); @@ -650,16 +629,16 @@ static void emitclosure(Nonterm nts) } /* emitcost - emit cost computation for tree t */ -static void emitcost(Tree t, char* v) +static void emitcost(Tree t, const char* v) { Nonterm p = t->op; if (p->kind == TERM) { if (t->left) - emitcost(t->left, stringf("%s->left", v)); + emitcost(t->left, aprintf("%s->left", v)); if (t->right) - emitcost(t->right, stringf("%s->right", v)); + emitcost(t->right, aprintf("%s->right", v)); } else print("%s->cost[%P%S_NT] + ", v, p); @@ -704,7 +683,7 @@ static void emitheader(void) } /* computekids - compute paths to kids in tree t */ -static char* computekids(Tree t, char* v, char* bp, int* ip) +static char* computekids(Tree t, const char* v, char* bp, int* ip) { Term p = t->op; @@ -715,9 +694,9 @@ static char* computekids(Tree t, char* v, char* bp, int* ip) } else if (p->arity > 0) { - bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip); + bp = computekids(t->left, aprintf("LEFT_CHILD(%s)", v), bp, ip); if (p->arity == 2) - bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip); + bp = computekids(t->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip); } return bp; } @@ -1168,7 +1147,7 @@ static void emitterms(Term terms) } /* emittest - emit clause for testing a match */ -static void emittest(Tree t, char* v, char* suffix) +static void emittest(Tree t, const char* v, const char* suffix) { Term p = t->op; @@ -1177,9 +1156,9 @@ static void emittest(Tree t, char* v, char* suffix) print("%3%s->op == %d%s/* %S */\n", v, p->esn, t->nterms > 1 ? " && " : suffix, p); if (t->left) - emittest(t->left, stringf("%s->left", v), + emittest(t->left, aprintf("%s->left", v), t->right && t->right->nterms ? " && " : suffix); if (t->right) - emittest(t->right, stringf("%s->right", v), suffix); + emittest(t->right, aprintf("%s->right", v), suffix); } } From 4a3a9a98dc30aace079c64b78d476dfed54c7b58 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 1 Oct 2016 12:17:14 +0200 Subject: [PATCH 046/230] It doesn't really make a lot of sense to have BURG nonterminal names different to register classes, so combine them. Refactor the map code. --- mach/proto/mcg/mcg.h | 2 +- mach/proto/mcg/pass_convertstackops.c | 4 +- mach/proto/mcg/table | 160 +++++++++++++------------- modules/src/data/imap.c | 16 +++ modules/src/data/imap.h | 1 + modules/src/data/map.h | 30 ----- modules/src/data/{map.c => pmap.c} | 36 ++++-- modules/src/data/pmap.h | 31 +++++ modules/src/data/smap.c | 74 ++++++++++++ modules/src/data/smap.h | 31 +++++ util/mcgg/gram.y | 18 +-- util/mcgg/iburg.c | 107 +++++++++-------- util/mcgg/iburg.h | 15 ++- 13 files changed, 331 insertions(+), 194 deletions(-) delete mode 100644 modules/src/data/map.h rename modules/src/data/{map.c => pmap.c} (52%) create mode 100644 modules/src/data/pmap.h create mode 100644 modules/src/data/smap.c create mode 100644 modules/src/data/smap.h diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 176efb535..277bc6cf4 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -17,7 +17,7 @@ #include "em_flag.h" #include "em_ptyp.h" #include "array.h" -#include "map.h" +#include "pmap.h" #include "diagnostics.h" #include "astring.h" #include "ir.h" diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index 6f62fe747..285ca1626 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -1,6 +1,6 @@ #include "mcg.h" -static MAPOF(struct basicblock, struct basicblock) graph; +static PMAPOF(struct basicblock, struct basicblock) graph; static ARRAYOF(struct ir) pops; static ARRAYOF(struct ir) pushes; @@ -46,7 +46,7 @@ static bool collect_outputs_cb(struct ir* ir, void* user) struct basicblock* caller = user; if (ir->opcode == IR_BLOCK) - map_addp(&graph, caller, ir->u.bvalue); + pmap_add(&graph, caller, ir->u.bvalue); return false; } diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index eac421ddf..31e51cdb7 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,96 +1,102 @@ REGISTERS - r0 reg4 i ret0; - r1 reg4 i; - r2 reg4 i; - r3 reg4 i; - r4 reg4 i; - r5 reg4 i; - r6 reg4 i; - r7 reg4 i; - r8 reg4 i; - r9 reg4 i; - r10 reg4 i; - r11 reg4 i; + r0 any int ret; + r1 any int; + r2 any int; + r3 any int; + r4 any int; + r5 any int; + r6 any int; + r7 any int; + r8 any int; + r9 any int; + r10 any int; + r11 any int; - s0 reg4 f; - s1 reg4 f; - s2 reg4 f; - s3 reg4 f; - s4 reg4 f; - s5 reg4 f; - s6 reg4 f; - s7 reg4 f; - s8 reg4 f; - s9 reg4 f; + s0 any float; + s1 any float; + s2 any float; + s3 any float; + s4 any float; + s5 any float; + s6 any float; + s7 any float; + s8 any float; + s9 any float; + + cc cc; - cc conditioncode; DECLARATIONS address fragment; aluparam fragment; - reg allocates(reg4); - tristate allocates(conditioncode); - bistate allocates(conditioncode); + PATTERNS /* Special */ - reg; - - reg = REG4; + int; + float; PAIR(BLOCK4, BLOCK4); /* Miscellaneous special things */ - PUSH4(in:reg) + PUSH4(in:int) emit "push %in" cost 4; - reg = POP4 - emit "pop %reg" + int = POP4 + emit "pop %int" cost 4; RET emit "ret" cost 4; - SETRET4(in:reg) + SETRET4(in:ret) emit "mov r0, %in" cost 4; + int = REG4 cost 1; + float = REG4 cost 1; + + any = int cost 1; + int = any cost 1; + any = float cost 1; + float = any cost 1; + /* Memory operations */ - STORE4(addr:address, value:reg) + STORE4(addr:address, value:int) emit "str %value, %addr" cost 4; - reg = LOAD4(addr:address) - emit "ldr %reg, %addr" + int = LOAD4(addr:address) + emit "ldr %int, %addr" cost 4; - reg = LOAD1(addr:address) - emit "ldrb %reg, %addr" + int = LOAD1(addr:address) + emit "ldrb %int, %addr" cost 4; - reg = CIU14(LOAD1(addr:address)) - emit "ldrb %reg, %addr" + int = CIU14(LOAD1(addr:address)) + emit "ldrb %int, %addr" cost 4; - reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) - emit "ldrsb %reg, %addr" + int = CII14(CIU41(CIU14(LOAD1(addr:address)))) + emit "ldrsb %int, %addr" cost 4; /* Locals */ - reg = in:LOCAL4 - emit "add %reg, fp, #$in" + int = in:LOCAL4 + emit "add %int, fp, #$in" cost 4; address = in:LOCAL4 @@ -99,10 +105,10 @@ PATTERNS /* Memory addressing modes */ - address = ADD4(addr:reg, offset:CONST4) + address = ADD4(addr:int, offset:CONST4) emit "[%addr, #$offset]"; - address = addr:reg + address = addr:int emit "[%addr]"; @@ -112,12 +118,7 @@ PATTERNS emit "b $addr" cost 4; - CJUMPEQ(value:tristate, PAIR(true:BLOCK4, false:BLOCK4)) - emit "beq $true" - emit "b $false" - cost 8; - - CJUMPEQ(value:bistate, PAIR(true:BLOCK4, false:BLOCK4)) + CJUMPEQ(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) emit "beq $true" emit "b $false" cost 8; @@ -125,72 +126,67 @@ PATTERNS /* Comparisons */ - tristate = COMPARES4(left:reg, right:aluparam) + cc = COMPARES4(left:int, right:aluparam) emit "cmp %left, %right" cost 4; - bistate = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4) + cc = COMPARES4(COMPARES4(left:int, right:aluparam), CONST4) emit "cmp %left, %right" cost 4; - reg = tristate - emit "mov %reg, #0" - emit "movlt %reg, #-1" - emit "movgt %reg, #1" + int = cc + emit "mov %int, #0" + emit "movlt %int, #-1" + emit "movgt %int, #1" cost 12; - reg = bistate - emit "moveq %reg, #1" - emit "movne %reg, #0" - cost 8; - /* Conversions */ - reg = CII14(CIU41(value:reg)) - emit "sxtb %reg, %value" + int = CII14(CIU41(value:int)) + emit "sxtb %int, %value" cost 4; - reg = CIU41(in:reg) - emit "and %reg, %in, #0xff" + int = CIU41(in:int) + emit "and %int, %in, #0xff" cost 4; /* ALU operations */ - reg = ADD4(left:reg, right:aluparam) - emit "add %reg, %left, %right" + int = ADD4(left:int, right:aluparam) + emit "add %int, %left, %right" cost 4; - reg = ADD4(left:aluparam, right:reg) - emit "add %reg, %right, %left" + int = ADD4(left:aluparam, right:int) + emit "add %int, %right, %left" cost 4; aluparam = value:CONST4 emit "#$value"; - aluparam = value:reg + aluparam = value:int emit "%value"; - reg = value:aluparam - emit "mov %reg, %value" + int = value:aluparam + emit "mov %int, %value" cost 4; - reg = value:LABEL4 - emit "adr %reg, $value" + int = value:LABEL4 + emit "adr %int, $value" cost 4; - reg = value:BLOCK4 - emit "adr %reg, $value" + int = value:BLOCK4 + emit "adr %int, $value" cost 4; - reg = value:CONST4 - emit "ldr %reg, #$value" + any = value:CONST4 + emit "ldr %any, address-containing-$value" cost 8; /* FPU operations */ - reg = ADDF4(left:reg, right:reg) - emit "fadds %reg, %left, %right" + float = ADDF4(left:float, right:float) + emit "fadds %float, %left, %right" cost 4; diff --git a/modules/src/data/imap.c b/modules/src/data/imap.c index 15c66e769..81982a704 100644 --- a/modules/src/data/imap.c +++ b/modules/src/data/imap.c @@ -56,3 +56,19 @@ void imap_add(void* mapp, int left, void* right) append(map, left, right); } +void* imap_get(void* mapp, int left) +{ + struct imap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct imap_node* node = &map->item[i]; + if (node->left == left) + return node->right; + } + + return NULL; +} + + diff --git a/modules/src/data/imap.h b/modules/src/data/imap.h index 022368ec8..cb312e16c 100644 --- a/modules/src/data/imap.h +++ b/modules/src/data/imap.h @@ -25,6 +25,7 @@ struct imap extern void imap_put(void* map, int left, void* right); extern void imap_add(void* map, int left, void* right); +extern void* imap_get(void* map, int left); #endif diff --git a/modules/src/data/map.h b/modules/src/data/map.h deleted file mode 100644 index 859618bd7..000000000 --- a/modules/src/data/map.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MAP_H -#define MAP_H - -struct map_node -{ - void* left; - void* right; -}; - -/* Danger, Will Robinson! The type and the macro must be compatible. */ - -struct map -{ - struct map_node* item; - int count; - int max; -}; - -#define MAPOF(LEFT, RIGHT) \ - struct { \ - struct { LEFT* left; RIGHT* right; }* item; \ - int count; \ - int max; \ - } - -extern void map_putp(void* map, void* left, void* right); -extern void map_addp(void* map, void* left, void* right); - -#endif - diff --git a/modules/src/data/map.c b/modules/src/data/pmap.c similarity index 52% rename from modules/src/data/map.c rename to modules/src/data/pmap.c index d75284762..9ed2d9fed 100644 --- a/modules/src/data/map.c +++ b/modules/src/data/pmap.c @@ -1,16 +1,16 @@ #include #include -#include "map.h" +#include "pmap.h" static void append(void* mapp, void* left, void* right) { - struct map* map = mapp; - struct map_node* node; + struct pmap* map = mapp; + struct pmap_node* node; if (map->count == map->max) { int newmax = (map->max == 0) ? 8 : (map->max * 2); - struct map_node* newarray = realloc(map->item, newmax * sizeof(*newarray)); + struct pmap_node* newarray = realloc(map->item, newmax * sizeof(*newarray)); map->max = newmax; map->item = newarray; @@ -23,14 +23,14 @@ static void append(void* mapp, void* left, void* right) node->right = right; } -void map_putp(void* mapp, void* left, void* right) +void pmap_put(void* mapp, void* left, void* right) { - struct map* map = mapp; + struct pmap* map = mapp; int i; for (i=0; icount; i++) { - struct map_node* node = &map->item[i]; + struct pmap_node* node = &map->item[i]; if (node->left == left) { node->right = right; @@ -41,14 +41,14 @@ void map_putp(void* mapp, void* left, void* right) append(map, left, right); } -void map_addp(void* mapp, void* left, void* right) +void pmap_add(void* mapp, void* left, void* right) { - struct map* map = mapp; + struct pmap* map = mapp; int i; for (i=0; icount; i++) { - struct map_node* node = &map->item[i]; + struct pmap_node* node = &map->item[i]; if ((node->left == left) && (node->right == right)) return; } @@ -56,3 +56,19 @@ void map_addp(void* mapp, void* left, void* right) append(map, left, right); } +void* pmap_get(void* mapp, void* left) +{ + struct pmap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct pmap_node* node = &map->item[i]; + if (node->left == left) + return node->right; + } + + return NULL; +} + + diff --git a/modules/src/data/pmap.h b/modules/src/data/pmap.h new file mode 100644 index 000000000..19986fc12 --- /dev/null +++ b/modules/src/data/pmap.h @@ -0,0 +1,31 @@ +#ifndef PMAP_H +#define PMAP_H + +struct pmap_node +{ + void* left; + void* right; +}; + +/* Danger, Will Robinson! The type and the macro must be compatible. */ + +struct pmap +{ + struct pmap_node* item; + int count; + int max; +}; + +#define PMAPOF(LEFT, RIGHT) \ + struct { \ + struct { LEFT* left; RIGHT* right; }* item; \ + int count; \ + int max; \ + } + +extern void pmap_put(void* map, void* left, void* right); +extern void pmap_add(void* map, void* left, void* right); +extern void* pmap_get(void* map, void* left); + +#endif + diff --git a/modules/src/data/smap.c b/modules/src/data/smap.c new file mode 100644 index 000000000..312241a20 --- /dev/null +++ b/modules/src/data/smap.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include "smap.h" + +static void append(void* mapp, const char* left, void* right) +{ + struct smap* map = mapp; + struct smap_node* node; + + if (map->count == map->max) + { + int newmax = (map->max == 0) ? 8 : (map->max * 2); + struct smap_node* newarray = realloc(map->item, newmax * sizeof(*newarray)); + + map->max = newmax; + map->item = newarray; + } + + node = &map->item[map->count]; + map->count++; + + node->left = left; + node->right = right; +} + +void smap_put(void* mapp, const char* left, void* right) +{ + struct smap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct smap_node* node = &map->item[i]; + if (strcmp(node->left, left) == 0) + { + node->right = right; + return; + } + } + + append(map, left, right); +} + +void smap_add(void* mapp, const char* left, void* right) +{ + struct smap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct smap_node* node = &map->item[i]; + if ((strcmp(node->left, left) == 0) && (node->right == right)) + return; + } + + append(map, left, right); +} + +void* smap_get(void* mapp, const char* left) +{ + struct smap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct smap_node* node = &map->item[i]; + if (strcmp(node->left, left) == 0) + return node->right; + } + + return NULL; +} + diff --git a/modules/src/data/smap.h b/modules/src/data/smap.h new file mode 100644 index 000000000..7ccdb51de --- /dev/null +++ b/modules/src/data/smap.h @@ -0,0 +1,31 @@ +#ifndef SMAP_H +#define SMAP_H + +struct smap_node +{ + const char* left; + void* right; +}; + +/* Danger, Will Robinson! The type and the macro must be compatible. */ + +struct smap +{ + struct smap_node* item; + int count; + int max; +}; + +#define SMAPOF(RIGHT) \ + struct { \ + struct { const char* left; RIGHT* right; }* item; \ + int count; \ + int max; \ + } + +extern void smap_put(void* map, const char* left, void* right); +extern void smap_add(void* map, const char* left, void* right); +extern void* smap_get(void* map, const char* left); + +#endif + diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 26a0e9b5b..94b188398 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -22,7 +22,7 @@ static int nextern = 1; Rule rule; struct reg* reg; struct stringlist* stringlist; - char* stringpair[2]; + struct terminfo terminfo; } %term ALLOCATES @@ -48,7 +48,7 @@ static int nextern = 1; %type pattern %type cfragments %type qfragments -%type labelledid +%type terminfo %type rhs %% @@ -106,14 +106,16 @@ pattern ; rhs - : labelledid { $$ = tree($1[1], $1[0], NULL, NULL); } - | labelledid '(' rhs ')' { $$ = tree($1[1], $1[0], $3, NULL); } - | labelledid '(' rhs ',' rhs ')' { $$ = tree($1[1], $1[0], $3, $5); } + : terminfo { $$ = tree(&$1, NULL, NULL); } + | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); } + | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); } ; -labelledid - : ID { $$[0] = NULL; $$[1] = $1; } - | ID ':' ID { $$[0] = $1; $$[1] = $3; } +terminfo + : ID { $$.name = $1; } + | ID '.' ID { $$.name = $1; $$.regattr = $3; } + | ID ':' ID { $$.label = $1; $$.name = $3; } + | ID ':' ID '.' ID { $$.label = $1; $$.name = $3; $$.regattr = $5; } ; cfragments diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index aeb68ae31..70d4ab080 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -9,9 +9,11 @@ #include #include #include +#include #include "iburg.h" #include "ircodes.h" #include "astring.h" +#include "smap.h" static char rcsid[] = "$Id$"; @@ -21,13 +23,14 @@ static char* prefix = "burm"; static int Tflag = 1; /* tracing */ static int ntnumber = 0; static Nonterm start = 0; -static struct reg* regs = NULL; -static struct regclass* regclasses = NULL; static Term terms; static Nonterm nts; static Rule rules; static int nrules; +static SMAPOF(struct reg) registers; +static SMAPOF(struct regclass) registerclasses; + static void print(char* fmt, ...); static void ckreach(Nonterm p); static void registerterminals(void); @@ -44,8 +47,8 @@ static void emitleaf(Term p, int ntnumber); static void emitnts(Rule rules, int nrules); static void emitpredicatedefinitions(Rule rules); static void emitrecord(char* pre, Rule r, int cost); -static void emitregisterclasses(struct regclass* rc); -static void emitregisters(struct reg* regs); +static void emitregisterclasses(); +static void emitregisters(); static void emitrule(Nonterm nts); static void emitstate(Term terms, Nonterm start, int ntnumber); static void emitstring(Rule rules); @@ -128,12 +131,14 @@ int main(int argc, char* argv[]) if (start) ckreach(start); + #if 0 for (p = nts; p; p = p->link) if (!p->reached) yyerror("can't reach non-terminal `%s'\n", p->name); + #endif - emitregisterclasses(regclasses); - emitregisters(regs); + emitregisterclasses(); + emitregisters(); emitdefs(nts, ntnumber); emitstruct(nts, ntnumber); emitnts(rules, nrules); @@ -230,52 +235,40 @@ static void* install(const char* name) struct reg* makereg(const char* id) { - struct reg* p = lookup(id); - struct reg** q = ®s; + struct reg* p = smap_get(®isters, id); static int number = 1; if (p) yyerror("redefinition of '%s'", id); - p = install(id); - p->kind = REG; + p = calloc(1, sizeof(*p)); + p->name = id; p->number = number++; + smap_put(®isters, id, p); - while (*q && (*q)->number < p->number) - q = &(*q)->link; - assert(*q == 0 || (*q)->number != p->number); - p->link = *q; - *q = p; return p; } void addregclass(struct reg* reg, const char* id) { - struct regclass* p = lookup(id); - struct regclass** q = ®classes; + struct regclass* p = smap_get(®isterclasses, id); static int number = 1; - if (p && (p->kind != REGCLASS)) - yyerror("redefinition of '%s' as something else\n", id); if (!p) { - p = install(id); - p->kind = REGCLASS; + p = calloc(1, sizeof(*p)); + p->name = id; p->number = number++; - - while (*q && (*q)->number < p->number) - q = &(*q)->link; - assert(*q == 0 || (*q)->number != p->number); - p->link = *q; - *q = p; + smap_put(®isterclasses, id, p); } reg->classes |= 1<<(p->number); + nonterm(id, true); } struct regclass* getregclass(const char* id) { - struct regclass* p = lookup(id); - if (!p || (p->kind != REGCLASS)) + struct regclass* p = smap_get(®isterclasses, id); + if (!p) yyerror("'%s' is not the name of a register class", id); return p; } @@ -333,10 +326,10 @@ Term term(const char* id, int esn) } /* tree - create & initialize a tree node with the given fields */ -Tree tree(const char* id, const char* label, Tree left, Tree right) +Tree tree(struct terminfo* ti, Tree left, Tree right) { Tree t = calloc(1, sizeof *t); - Term p = lookup(id); + Term p = lookup(ti->name); int arity = 0; if (left && right) @@ -345,22 +338,22 @@ Tree tree(const char* id, const char* label, Tree left, Tree right) arity = 1; if (p == NULL && arity > 0) { - yyerror("undefined terminal `%s'\n", id); - p = term(id, -1); + yyerror("undefined terminal `%s'\n", ti->name); + p = term(ti->name, -1); } else if (p == NULL && arity == 0) - p = (Term)nonterm(id, false); + p = (Term)nonterm(ti->name, false); else if (p && p->kind == NONTERM && arity > 0) { - yyerror("`%s' is a non-terminal\n", id); - p = term(id, -1); + yyerror("`%s' is a non-terminal\n", ti->name); + p = term(ti->name, -1); } if (p->kind == TERM && p->arity == -1) p->arity = arity; if (p->kind == TERM && arity != p->arity) - yyerror("inconsistent arity for terminal `%s'\n", id); + yyerror("inconsistent arity for terminal `%s'\n", ti->name); t->op = p; - t->label = label; + t->label = ti->label; t->nterms = p->kind == TERM; if (t->left = left) t->nterms += left->nterms; @@ -423,6 +416,10 @@ static void print(char* fmt, ...) fprintf(outfp, "%x", va_arg(ap, uint32_t)); break; + case 'X': + fprintf(outfp, "0x%" PRIx64 "ULL", va_arg(ap, uint64_t)); + break; + case 's': fputs(va_arg(ap, char*), outfp); break; @@ -503,34 +500,34 @@ static void ckreach(Nonterm p) reach(r->pattern); } -static void emitregisterclasses(struct regclass* rc) +static void emitregisterclasses(void) { - int k = 0; + int i; + print("const char* %Pregister_class_names[] = {\n"); - while (rc) + print("%1NULL,\n"); /* register class id 0 is invalid */ + for (i=0; inumber; k++) - print("%1NULL,\n"); - k++; + struct regclass* rc = registerclasses.item[i].right; + assert(rc->number == (i+1)); print("%1\"%s\",\n", rc->name); - rc = rc->link; } print("};\n\n"); } -static void emitregisters(struct reg* r) +static void emitregisters(void) { - int k = 0; - print("const struct %Pregister_data %Pregister_data[] = {\n"); - while (r) - { - for (; k < r->number; k++) - print("%1{ 0 },\n"); - k++; + int i; - print("%1{ \"%s\", %d },\n", r->name, r->classes); - r = r->link; + print("const struct %Pregister_data %Pregister_data[] = {\n"); + print("%1{ 0 },\n"); /* register id 0 is invalid */ + for (i=0; inumber == (i+1)); + + print("%1{ \"%s\", %X },\n", r->name, r->classes); } print("};\n\n"); } diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 7bf8b8a0e..1a4211e91 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -15,21 +15,24 @@ typedef enum typedef struct rule* Rule; typedef struct term* Term; +struct terminfo +{ + const char* name; + const char* label; + const char* regattr; +}; + struct reg { const char* name; /* register name */ - Kind kind; /* REG */ int number; /* identifying number */ - uint32_t classes; // bitfield of classes */ - struct reg* link; /* next in list */ + uint64_t classes; // bitfield of classes */ }; struct regclass { const char* name; /* class name */ - Kind kind; /* REGCLASS */ int number; /* identifying number */ - struct regclass* link; /* next in list */ }; extern struct reg* makereg(const char* name); @@ -72,7 +75,7 @@ struct tree Tree left, right; /* operands */ int nterms; /* number of terminal nodes in this tree */ }; -extern Tree tree(const char* op, const char* label, Tree left, Tree right); +extern Tree tree(struct terminfo* ti, Tree left, Tree right); struct rule { /* rules: */ From 91e277e046479bbbb1b3a76dc980b127fbca409c Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 1 Oct 2016 13:56:52 +0200 Subject: [PATCH 047/230] Predicates work; we now have prefers and requires clauses. Predicates must be functions. Not convinced that semantic types are actually working --- there are still problems with earlier statements leaving things in the wrong registers. --- mach/proto/mcg/hop.c | 4 ++ mach/proto/mcg/ir.h | 1 + mach/proto/mcg/mcgg_generated_header.h | 10 ++++ mach/proto/mcg/pass_instructionselection.c | 5 +- mach/proto/mcg/table | 26 +++++--- util/mcgg/gram.y | 28 +++++---- util/mcgg/iburg.c | 70 ++++++++++++++-------- util/mcgg/iburg.h | 10 +++- util/mcgg/scan.l | 35 +---------- 9 files changed, 112 insertions(+), 77 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 35bed381b..a57d4988a 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -89,6 +89,10 @@ void hop_print(char k, struct hop* hop) tracef(k, "%s", ir->u.bvalue->name); break; + case IR_LABEL: + tracef(k, "%s", ir->u.lvalue); + break; + case IR_LOCAL: case IR_CONST: tracef(k, "0x%d", ir->u.ivalue); diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 069a76bd5..abf4a1792 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -20,6 +20,7 @@ struct ir void* state_label; /* used by the iburg instruction selector */ int insn_no; /* the table rule number for this instruction */ + int goal_no; /* the semantic type of this instruction; not stmt */ ARRAYOF(struct hop) hops; /* only for root IRs */ bool is_root : 1; diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index a3e79afc0..b37fe8cd3 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -20,3 +20,13 @@ static int OP_LABEL(struct ir* ir) extern void burm_panic_cannot_match(struct ir* ir); +static bool burm_predicate_int(struct ir* ir) +{ + return ir->goal_no == 3; +} + +static bool burm_predicate_float(struct ir* ir) +{ + return ir->goal_no == 5; +} + diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 2b0bb96c3..ea13ae52b 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -83,10 +83,13 @@ static void walk_instructions(struct ir* ir, int goal) ir->is_generated = true; ir->insn_no = insn_no; + if (goal != 1) + ir->goal_no = goal; - tracef('I', "I: $%d %s selected %s %d: %s\n", + tracef('I', "I: $%d %s goal %d selected %s %d: %s\n", ir->id, ir->is_root ? "S" : " ", + ir->goal_no, insndata->is_fragment ? "fragment" : "instruction", insn_no, insndata->name); diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 31e51cdb7..c88c68fcb 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -61,13 +61,19 @@ PATTERNS emit "mov r0, %in" cost 4; - int = REG4 cost 1; - float = REG4 cost 1; + int = in:REG4 + prefers int(in) + cost 1; - any = int cost 1; - int = any cost 1; - any = float cost 1; - float = any cost 1; + float = in:REG4 + prefers float(in) + cost 1; + + ret = in:any emit "mov %ret, %in" cost 1; + any = in:int emit "mov %any, %in" cost 1; + int = in:any emit "mov %int, %in" cost 1; + any = in:float emit "mov %any, %in" cost 1; + float = in:any emit "mov %float, %in" cost 1; /* Memory operations */ @@ -180,8 +186,12 @@ PATTERNS emit "adr %int, $value" cost 4; - any = value:CONST4 - emit "ldr %any, address-containing-$value" + int = value:CONST4 + emit "ldr %int, address-containing-$value" + cost 8; + + float = value:CONST4 + emit "vldr %float, address-containing-$value" cost 8; /* FPU operations */ diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 94b188398..e65a6256b 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -23,6 +23,7 @@ static int nextern = 1; struct reg* reg; struct stringlist* stringlist; struct terminfo terminfo; + struct expr* expr; } %term ALLOCATES @@ -30,15 +31,13 @@ static int nextern = 1; %term DECLARATIONS %term EMIT %term FRAGMENT -%term INS -%term OUTS %term PATTERNS %term REGISTERS -%term WHEN +%term PREFERS +%term REQUIRES %token INT %token ID -%token CFRAGMENT %token QFRAGMENT %type allocates @@ -50,6 +49,8 @@ static int nextern = 1; %type qfragments %type terminfo %type rhs +%type predicate +%type predicate_args %% spec @@ -100,7 +101,8 @@ patterns pattern : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } | rhs { $$ = rule("stmt", $1, nextern++); } - | pattern WHEN cfragments { $$ = $1; stringlist_addall(&$$->when, $3); } + | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } + | pattern REQUIRES predicate { $$ = $1; array_append(&$$->requires, $3); } | emit { $$ = $1; } | pattern COST INT { $$ = $1; $$->cost = $3; } ; @@ -118,11 +120,6 @@ terminfo | ID ':' ID '.' ID { $$.label = $1; $$.name = $3; $$.regattr = $5; } ; -cfragments - : /* nothing */ { $$ = calloc(1, sizeof *$$); } - | cfragments CFRAGMENT { $$ = $1; stringlist_add($$, $2); } - ; - emit : pattern EMIT qfragments { $$ = $1; @@ -137,6 +134,16 @@ qfragments | qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); } ; +predicate + : ID '(' predicate_args ')' { $$ = calloc(1, sizeof *$$); $$->name = $1; $$->next = $3; } + ; + +predicate_args + : /* nothing */ + | ID { $$ = calloc(1, sizeof *$$); $$->name = $1; } + | ID ',' predicate_args { $$ = calloc(1, sizeof *$$); $$->name = $1; $$->next = $3; } + ; + %% #include #include @@ -157,6 +164,7 @@ void yyerror(char *fmt, ...) { if (fmt[strlen(fmt)-1] != '\n') fprintf(stderr, "\n"); errcnt++; + exit(1); } void yywarn(char *fmt, ...) { diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 70d4ab080..074198d0c 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -598,7 +598,7 @@ static void emitcase(Term p, int ntnumber) default: assert(0); } - print("%d;\n", r->cost); + print("%d);\n", r->cost); emitrecord("\t\t\t", r, 0); print("%2}\n"); } @@ -859,27 +859,6 @@ static void emitrule(Nonterm nts) print("%1default:\n%2%Passert(0, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n%1}\n%1return 0;\n}\n\n"); } -/* emitpredicates - emit predicates for rules */ -static void emitpredicatedefinitions(Rule r) -{ - while (r) - { - struct stringfragment* f = r->when.first; - if (f) - { - print("/* %R */\n", r); - print("static int %Ppredicate_%d(NODEPTR_TYPE n) {\n", r->ern); - while (f) - { - print("%s", f->data); - f = f->next; - } - print("\n}\n\n"); - } - r = r->link; - } -} - static void print_path(uint32_t path) { int i = 0; @@ -932,6 +911,50 @@ static void label_not_found(Rule rule, const char* label) exit(1); } +/* emitpredicates - emit predicates for rules */ +static void emitpredicatedefinitions(Rule r) +{ + int i; + + while (r) + { + print("/* %R */\n", r); + print("static int %Padjust_cost_%d(NODEPTR_TYPE node, int cost) {\n", r->ern); + + for (i=0; iprefers.count; i++) + { + struct expr* p = r->prefers.item[i]; + bool first = true; + + print("%1if (%Ppredicate_%s(", p->name); + + p = p->next; + while (p) + { + uint32_t path = find_label(r->pattern, p->name, 0, NULL); + if (path == PATH_MISSING) + label_not_found(r, p->name); + + if (!first) + print(", "); + else + first = false; + + print_path(path); + p = p->next; + } + + print(")) cost -= 1;\n"); + } + + print("%1if (cost > %d) return %d;\n", maxcost, maxcost); + print("%1if (cost < 1) return 1;\n"); + print("%1return cost;\n"); + print("}\n\n"); + r = r->link; + } +} + /* emitinsndata - emit the code generation data */ static void emitinsndata(Rule rules) { @@ -1051,8 +1074,7 @@ static void emitinsndata(Rule rules) /* emitcost - emit a cost calculation via a predicate */ static void emitcostcalc(Rule r) { - if (r->when.first) - print("!%Ppredicate_%d(node) ? %d : ", r->ern, maxcost); + print("%Padjust_cost_%d(node, ", r->ern); } /* emitstate - emit state function */ diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 1a4211e91..919f4471d 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -2,6 +2,7 @@ #define BURG_INCLUDED #include "stringlist.h" +#include "array.h" extern char* stringf(char* fmt, ...); @@ -15,6 +16,12 @@ typedef enum typedef struct rule* Rule; typedef struct term* Term; +struct expr +{ + const char* name; + struct expr* next; +}; + struct terminfo { const char* name; @@ -90,7 +97,8 @@ struct rule Rule chain; /* next chain rule with same rhs */ Rule decode; /* next rule with same lhs */ Rule kids; /* next rule with same burm_kids pattern */ - struct stringlist when; /* C predicate string */ + ARRAYOF(struct predicate) prefers; /* C predicates */ + ARRAYOF(struct predicate) requires; /* C predicates */ struct stringlist code; /* compiler output code strings */ }; extern Rule rule(char* id, Tree pattern, int ern); diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 83e0fe3cf..30280c492 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -12,41 +12,11 @@ static int braces = 0; %option yylineno %option debug -%x CSTRING %x QSTRING %x COMMENT %% -"{" { - yylval.string = ""; //stringf("#line %d\n", yylineno); - braces = 1; - BEGIN(CSTRING); - return CFRAGMENT; - } - -"{" { - braces++; - yylval.string = strdup(yytext); - return CFRAGMENT; - } - -"}" { - braces--; - if (braces == 0) - BEGIN(INITIAL); - else - { - yylval.string = strdup(yytext); - return CFRAGMENT; - } - } - -[^{}]+ { - yylval.string = strdup(yytext); - return CFRAGMENT; - } - "\"" BEGIN(QSTRING); "\"" BEGIN(INITIAL); @@ -72,9 +42,8 @@ static int braces = 0; "cost" return COST; "emit" return EMIT; "fragment" return FRAGMENT; -"ins" return INS; -"outs" return OUTS; -"when" return WHEN; +"prefers" return PREFERS; +"requires" return REQUIRES; "//"[^\n]*\n ; From 21898f784a36ee0287e43baa64b8ec45f81b1eae Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 1 Oct 2016 19:10:22 +0200 Subject: [PATCH 048/230] We're going to need some type inference after all, I think. Let's do a little for now and see how it goes. --- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_promotefloatops.c | 100 ++++++++++++++++++++++++++ mach/proto/mcg/procedure.c | 1 + mach/proto/mcg/table | 2 +- util/mcgg/ir.dat | 9 ++- 5 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 mach/proto/mcg/pass_promotefloatops.c diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 277bc6cf4..ddd33aecf 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -124,6 +124,7 @@ extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_instruction_selector(struct procedure* proc); +extern void pass_promote_float_ops(struct procedure* proc); extern void procedure_compile(struct procedure* proc); diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c new file mode 100644 index 000000000..478143b38 --- /dev/null +++ b/mach/proto/mcg/pass_promotefloatops.c @@ -0,0 +1,100 @@ +#include "mcg.h" + +static ARRAYOF(struct ir) pending; +static ARRAYOF(struct ir) promotable; + +static void addall(struct ir* ir) +{ + if (array_appendu(&pending, ir)) + return; + + if (ir->left) + addall(ir->left); + if (ir->right) + addall(ir->right); +} + +static void collect_irs(struct procedure* proc) +{ + int i; + + pending.count = 0; + promotable.count = 0; + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + int j; + + for (j=0; jirs.count; j++) + addall(bb->irs.item[j]); + } +} + +static void promote(struct ir* ir) +{ + switch (ir->opcode) + { + case IR_CONST: + case IR_POP: + case IR_LOAD: + array_appendu(&promotable, ir); + break; + + case IR_PHI: + if (!array_appendu(&promotable, ir)) + { + if (ir->left) + promote(ir->left); + if (ir->right) + promote(ir->right); + } + break; + } +} + +static void search_for_promotable_irs(void) +{ + int i; + + for (i=0; iopcode) + { + case IR_ADDF: + case IR_SUBF: + case IR_MULF: + case IR_DIVF: + case IR_NEGF: + if (ir->left) + promote(ir->left); + if (ir->right) + promote(ir->right); + break; + } + } +} + +static void modify_promotable_irs(void) +{ + int i; + + for (i=0; iopcode != IR_PHI) + ir->opcode++; + } +} + +void pass_promote_float_ops(struct procedure* proc) +{ + collect_irs(proc); + search_for_promotable_irs(); + modify_promotable_irs(); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index a27aeedf7..300882eb9 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -29,6 +29,7 @@ void procedure_compile(struct procedure* proc) pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); pass_convert_stack_ops(proc); + pass_promote_float_ops(proc); print_blocks('2', proc); diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index c88c68fcb..59272c4dd 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -190,7 +190,7 @@ PATTERNS emit "ldr %int, address-containing-$value" cost 8; - float = value:CONST4 + float = value:CONSTF4 emit "vldr %float, address-containing-$value" cost 8; diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 3dd785b5c..b12cf8934 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -3,7 +3,8 @@ # V: has no size (use in JUMP, CJUMP, RET forms) # Simple terminals -S CONST +S CONST # must be followed by float form +S CONSTF S REG S LABEL S BLOCK @@ -14,10 +15,12 @@ S PHI # Magic stack operations S PUSH -S POP +S POP # must be followed by float form +S POPF #... Memory operations -S LOAD +S LOAD # must be followed by float form +S LOADF S STORE # Arithemetic operations From a3cfe6047f8e3f676d999df0ca1c3acc062d77ee Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 1 Oct 2016 22:58:29 +0200 Subject: [PATCH 049/230] More rigorous dealing of IR groups; no need for is_generated and is_root any more (but now passes are required to set IR roots properly when changing instructions). --- mach/proto/mcg/ir.c | 24 ++++-- mach/proto/mcg/ir.h | 5 +- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/mcgg_generated_header.h | 11 +-- mach/proto/mcg/pass_convertstackops.c | 12 ++- mach/proto/mcg/pass_groupirs.c | 95 ++++++++++++++++++++++ mach/proto/mcg/pass_instructionselection.c | 24 ++++-- mach/proto/mcg/procedure.c | 1 + mach/proto/mcg/treebuilder.c | 5 +- modules/src/data/array.c | 22 ++++- modules/src/data/array.h | 1 + 11 files changed, 161 insertions(+), 40 deletions(-) create mode 100644 mach/proto/mcg/pass_groupirs.c diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index c4755b275..d2b64b162 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -68,17 +68,18 @@ struct ir* new_localir(int offset) struct ir* ir_walk(struct ir* ir, ir_walker_t* cb, void* user) { + assert(ir->root); if (cb(ir, user)) return ir; - if (ir->left && !ir->left->is_root) + if (ir->left && (ir->left->root == ir->root)) { struct ir* irr = ir_walk(ir->left, cb, user); if (irr) return irr; } - if (ir->right && !ir->right->is_root) + if (ir->right && (ir->right->root == ir->root)) { struct ir* irr = ir_walk(ir->right, cb, user); if (irr) @@ -106,7 +107,7 @@ static void print_expr(char k, const struct ir* ir) tracef(k, "%s", ir_data[ir->opcode].name); if (ir->size) tracef(k, "%d", ir->size); - tracef(k, "("); + tracef(k, ":%d(", ir->id); switch (ir->opcode) { @@ -123,10 +124,23 @@ static void print_expr(char k, const struct ir* ir) tracef(k, "%s", ir->u.bvalue->name); break; + case IR_PHI: + { + int i; + + for (i=0; iu.phivalue.count; i++) + { + if (i > 0) + tracef(k, ", "); + tracef(k, "$%d", ir->u.phivalue.item[i]->id); + } + break; + } + default: if (ir->left) { - if (ir->left->is_root) + if (ir->left->root == ir->root) tracef(k, "$%d", ir->left->id); else print_expr(k, ir->left); @@ -134,7 +148,7 @@ static void print_expr(char k, const struct ir* ir) if (ir->right) { tracef(k, ", "); - if (ir->right->is_root) + if (ir->right->root == ir->root) tracef(k, "$%d", ir->right->id); else print_expr(k, ir->right); diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index abf4a1792..dc66ff757 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -10,21 +10,20 @@ struct ir int size; struct ir* left; struct ir* right; + struct ir* root; union { arith ivalue; int rvalue; const char* lvalue; struct basicblock* bvalue; + ARRAYOF(struct ir) phivalue; } u; void* state_label; /* used by the iburg instruction selector */ int insn_no; /* the table rule number for this instruction */ int goal_no; /* the semantic type of this instruction; not stmt */ ARRAYOF(struct hop) hops; /* only for root IRs */ - - bool is_root : 1; - bool is_generated : 1; }; extern const char* ir_names[]; diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index ddd33aecf..3db29b86c 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -125,6 +125,7 @@ extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_instruction_selector(struct procedure* proc); extern void pass_promote_float_ops(struct procedure* proc); +extern void pass_group_irs(struct procedure* proc); extern void procedure_compile(struct procedure* proc); diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index b37fe8cd3..eead127f1 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -4,20 +4,13 @@ #define PANIC printf -static int OP_LABEL(struct ir* ir) -{ - if (ir->is_root && ir->is_generated) - { - return ir_to_esn(IR_REG, ir->size); - } - return ir_to_esn(ir->opcode, ir->size); -} - +#define OP_LABEL(p) burm_calculate_label(p) #define LEFT_CHILD(p) ((p)->left) #define RIGHT_CHILD(p) ((p)->right) #define burm_assert(b, s) assert(b) +extern int burm_calculate_label(struct ir* ir); extern void burm_panic_cannot_match(struct ir* ir); static bool burm_predicate_int(struct ir* ir) diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index 285ca1626..c34eddf16 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -112,22 +112,20 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) for (i=0; iis_root); *ir = *ir->left; - ir->is_root = true; } for (i=0; isize, pushir); + struct ir* phi = new_ir0(IR_PHI, ir->size); - for (j=1; jsize, phi, pushes.item[j]); + for (j=0; ju.phivalue, pushes.item[j]); + phi->root = phi; - phi->is_root = ir->is_root; *ir = *phi; + array_insert(&bb->irs, ir, 0); } } } diff --git a/mach/proto/mcg/pass_groupirs.c b/mach/proto/mcg/pass_groupirs.c new file mode 100644 index 000000000..833809b1d --- /dev/null +++ b/mach/proto/mcg/pass_groupirs.c @@ -0,0 +1,95 @@ +#include "mcg.h" + +static ARRAYOF(struct ir) allirs; +static ARRAYOF(struct ir) rootirs; + +static void addall(struct ir* ir) +{ + if (array_appendu(&allirs, ir)) + return; + + if (ir->left) + addall(ir->left); + if (ir->right) + addall(ir->right); +} + +static void collect_irs(struct procedure* proc) +{ + int i; + + allirs.count = rootirs.count = 0; + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + int j; + + for (j=0; jirs.count; j++) + { + struct ir* ir = bb->irs.item[j]; + addall(ir); + array_appendu(&rootirs, ir); + } + } +} + +static void clear_roots(void) +{ + int i; + + for (i=0; iroot = NULL; + } +} + +static void find_roots(void) +{ + int i; + + for (i=0; iroot); + ir->root = ir; + } +} + +static void recursively_mark_root(struct ir* node, struct ir* root) +{ + if (node != root) + { + if (node->root) + return; + node->root = root; + } + + if (node->left) + recursively_mark_root(node->left, root); + if (node->right) + recursively_mark_root(node->right, root); +} + +static void find_non_roots(void) +{ + int i; + + for (i=0; iroot != current_ir) + return ir_to_esn(IR_REG, ir->size); + return ir_to_esn(ir->opcode, ir->size); +} + static void emit_reg(struct ir* ir, int goal) { hop_add_reg_insel(current_hop, ir, goal); @@ -81,14 +89,12 @@ static void walk_instructions(struct ir* ir, int goal) for (i=0; nts[i]; i++) walk_instructions(children[i], nts[i]); - ir->is_generated = true; ir->insn_no = insn_no; if (goal != 1) ir->goal_no = goal; - tracef('I', "I: $%d %s goal %d selected %s %d: %s\n", + tracef('I', "I: $%d goal %d selected %s %d: %s\n", ir->id, - ir->is_root ? "S" : " ", ir->goal_no, insndata->is_fragment ? "fragment" : "instruction", insn_no, @@ -114,15 +120,15 @@ static void select_instructions(void) for (i=0; iirs.count; i++) { int insnno; - struct ir* ir = current_bb->irs.item[i]; - burm_label(ir); + current_ir = current_bb->irs.item[i]; + burm_label(current_ir); - insnno = burm_rule(ir->state_label, 1); + insnno = burm_rule(current_ir->state_label, 1); if (!insnno) - burm_panic_cannot_match(ir); + burm_panic_cannot_match(current_ir); - ir_print('I', ir); - walk_instructions(ir, 1); + ir_print('I', current_ir); + walk_instructions(current_ir, 1); } } diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 300882eb9..dc11e0a43 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -26,6 +26,7 @@ void procedure_compile(struct procedure* proc) print_blocks('1', proc); + pass_group_irs(proc); pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); pass_convert_stack_ops(proc); diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 58f19bdc2..8835c0b46 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1,6 +1,5 @@ #include "mcg.h" -static struct symbol* currentproc; static struct basicblock* current_bb; static int stackptr; @@ -76,7 +75,6 @@ static struct ir* appendir(struct ir* ir) int i; assert(current_bb != NULL); - ir->is_root = true; array_append(¤t_bb->irs, ir); ir_print('0', ir); @@ -479,8 +477,7 @@ static void insn_ivalue(int opcode, arith value) case op_dup: { struct ir* v = pop(value); - if (!v->is_root) - appendir(v); + appendir(v); push(v); push(v); break; diff --git a/modules/src/data/array.c b/modules/src/data/array.c index 8943323cb..bfaaf8e84 100644 --- a/modules/src/data/array.c +++ b/modules/src/data/array.c @@ -1,11 +1,10 @@ #include #include +#include #include "array.h" -void array_append(void* arrayp, void* value) +static void extend(struct array* array) { - struct array* array = arrayp; - if (array->count == array->max) { int newmax = (array->max == 0) ? 8 : (array->max * 2); @@ -14,7 +13,13 @@ void array_append(void* arrayp, void* value) array->max = newmax; array->item = newarray; } +} +void array_append(void* arrayp, void* value) +{ + struct array* array = arrayp; + + extend(array); array->item[array->count] = value; array->count++; } @@ -40,6 +45,17 @@ bool array_appendu(void* arrayp, void* value) return false; } +void array_insert(void* arrayp, void* value, int before) +{ + struct array* array = arrayp; + + extend(array); + memmove(&array->item[before+1], &array->item[before], + (array->count-before) * sizeof(*array)); + array->item[before] = value; + array->count++; +} + void array_remove(void* arrayp, void* value) { struct array* array = arrayp; diff --git a/modules/src/data/array.h b/modules/src/data/array.h index 601873571..63951ff5d 100644 --- a/modules/src/data/array.h +++ b/modules/src/data/array.h @@ -19,6 +19,7 @@ struct array extern void array_append(void* array, void* value); extern bool array_appendu(void* array, void* value); +extern void array_insert(void* array, void* value, int before); extern void array_remove(void* array, void* value); extern bool array_contains(void* array, void* value); From 3474e202748fd84b7a168fcf633077dc6c6e17d0 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 1 Oct 2016 23:13:39 +0200 Subject: [PATCH 050/230] Deal with malformed mes instructions emitted by ego. --- mach/proto/mcg/parse_em.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 7c0015184..4508d594c 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -328,11 +328,18 @@ static void parse_mes(void) case 3: /* register variable */ { - arith offset = mes_get_cst(); - int size = mes_get_cst(); - int type = mes_get_cst(); - int priority = mes_get_cst(); - tb_regvar(offset, size, type, priority); + /* ego will sometimes generate 'mes 3' pseudos with no actual + * parameters. Detect and ignore these. */ + + EM_getinstr(&em); + if (em.em_type == EM_MESARG) + { + arith offset = em.em_cst; + int size = mes_get_cst(); + int type = mes_get_cst(); + int priority = mes_get_cst(); + tb_regvar(offset, size, type, priority); + } break; } } From 73d7e89c323bde2eab024fc88fb5701391145892 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 1 Oct 2016 23:41:03 +0200 Subject: [PATCH 051/230] Show expression trees correctly. --- mach/proto/mcg/ir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index d2b64b162..0aea3ea50 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -140,7 +140,7 @@ static void print_expr(char k, const struct ir* ir) default: if (ir->left) { - if (ir->left->root == ir->root) + if (ir->left->root != ir->root) tracef(k, "$%d", ir->left->id); else print_expr(k, ir->left); @@ -148,7 +148,7 @@ static void print_expr(char k, const struct ir* ir) if (ir->right) { tracef(k, ", "); - if (ir->right->root == ir->root) + if (ir->right->root != ir->root) tracef(k, "$%d", ir->right->id); else print_expr(k, ir->right); From 65e75be42d22f05f2b151219d66d11c50a251543 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 1 Oct 2016 23:41:35 +0200 Subject: [PATCH 052/230] Fix edge case where leftover pushes would occasionally cause infinite loops in the analysis. --- mach/proto/mcg/pass_convertstackops.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index c34eddf16..f5764484a 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -107,6 +107,11 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) } } + /* If we didn't actually find anything, give up. */ + + if ((pushes.count == 0) || (pops.count == 0)) + return; + /* Okay, now we can wire them all up. */ for (i=0; i Date: Sat, 1 Oct 2016 23:41:45 +0200 Subject: [PATCH 053/230] Make betterer. --- mach/proto/mcg/table | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 59272c4dd..6d3e231d9 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -61,6 +61,10 @@ PATTERNS emit "mov r0, %in" cost 4; + STACKADJUST4(delta:aluparam) + emit "add sp, sp, %delta" + cost 4; + int = in:REG4 prefers int(in) cost 1; @@ -82,6 +86,10 @@ PATTERNS emit "str %value, %addr" cost 4; + STORE1(addr:address, value:int) + emit "strb %value, %addr" + cost 4; + int = LOAD4(addr:address) emit "ldr %int, %addr" cost 4; @@ -114,10 +122,14 @@ PATTERNS address = ADD4(addr:int, offset:CONST4) emit "[%addr, #$offset]"; + address = ADD4(addr1:int, addr2:int) + emit "[%addr1, %addr2]"; + address = addr:int emit "[%addr]"; + /* Branches */ JUMP(addr:BLOCK4) @@ -129,6 +141,15 @@ PATTERNS emit "b $false" cost 8; + CJUMPLE(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) + emit "ble $true" + emit "b $false" + cost 8; + + CALL(dest:LABEL4) + emit "bl $dest" + cost 4; + /* Comparisons */ @@ -168,6 +189,15 @@ PATTERNS emit "add %int, %right, %left" cost 4; + int = MOD4(left:int, right:int) + emit "udiv %int, %left, %right" + emit "mls %int, %int, %right, %left" + cost 8; + + int = DIV4(left:int, right:aluparam) + emit "div %int, %left, %right" + cost 4; + aluparam = value:CONST4 emit "#$value"; From b298c27c6368d54d5eb5e1be76e8e6ea28ebaa2e Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 2 Oct 2016 00:30:33 +0200 Subject: [PATCH 054/230] Refactor mcg.h as it's getting a bit big; keep track of register variables. --- mach/proto/mcg/mcg.h | 14 +++----------- mach/proto/mcg/parse_em.c | 2 +- mach/proto/mcg/procedure.h | 22 ++++++++++++++++++++++ mach/proto/mcg/treebuilder.c | 7 +++++-- 4 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 mach/proto/mcg/procedure.h diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 3db29b86c..78560499b 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -17,12 +17,14 @@ #include "em_flag.h" #include "em_ptyp.h" #include "array.h" +#include "imap.h" #include "pmap.h" #include "diagnostics.h" #include "astring.h" #include "ir.h" #include "mcgg.h" #include "hop.h" +#include "procedure.h" extern char em_pseu[][4]; extern char em_mnem[][4]; @@ -71,14 +73,6 @@ struct em } u; }; -struct procedure -{ - const char* name; - struct basicblock* root_bb; - size_t nlocals; - ARRAYOF(struct basicblock) blocks; -}; - struct basicblock { const char* name; @@ -118,7 +112,7 @@ extern void bb_print(char k, struct basicblock* block); extern void tb_filestart(void); extern void tb_fileend(void); extern void tb_procedure(struct procedure* proc); -extern void tb_regvar(arith offset, int size, int type, int priority); +extern void tb_regvar(struct procedure* proc, arith offset, int size, int type, int priority); extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); @@ -127,8 +121,6 @@ extern void pass_instruction_selector(struct procedure* proc); extern void pass_promote_float_ops(struct procedure* proc); extern void pass_group_irs(struct procedure* proc); -extern void procedure_compile(struct procedure* proc); - #endif /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 4508d594c..12ea25589 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -338,7 +338,7 @@ static void parse_mes(void) int size = mes_get_cst(); int type = mes_get_cst(); int priority = mes_get_cst(); - tb_regvar(offset, size, type, priority); + tb_regvar(current_proc, offset, size, type, priority); } break; } diff --git a/mach/proto/mcg/procedure.h b/mach/proto/mcg/procedure.h new file mode 100644 index 000000000..de11c5458 --- /dev/null +++ b/mach/proto/mcg/procedure.h @@ -0,0 +1,22 @@ +#ifndef PROCEDURE_H +#define PROCEDURE_H + +struct local +{ + bool is_register; +}; + +struct procedure +{ + const char* name; + struct basicblock* root_bb; + size_t nlocals; + ARRAYOF(struct basicblock) blocks; + IMAPOF(struct local) locals; +}; + +extern void procedure_compile(struct procedure* proc); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 8835c0b46..f4c481457 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -107,9 +107,12 @@ void tb_fileend(void) { } -void tb_regvar(arith offset, int size, int type, int priority) +void tb_regvar(struct procedure* procedure, arith offset, int size, int type, int priority) { - /* ignored */ + struct local* local = calloc(1, sizeof(*local)); + local->size = size; + local->is_register = true; + imap_put(&procedure->locals, offset, local); } static struct ir* address_of_external(const char* label, arith offset) From bf73fcdb64c36f97e36440ee4307f544100b5b23 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 2 Oct 2016 14:44:21 +0200 Subject: [PATCH 055/230] Add inl and del opcodes. --- mach/proto/mcg/treebuilder.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index f4c481457..e8675e613 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -340,6 +340,24 @@ static struct ir* extract_block_refs(struct basicblock* bb) return outir; } +static void change_by(struct ir* address, int amount) +{ + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address, + new_ir2( + IR_ADD, EM_wordsize, + new_ir1( + IR_LOAD, EM_wordsize, + address + ), + new_wordir(amount) + ) + ) + ); +} + static void insn_ivalue(int opcode, arith value) { switch (opcode) @@ -387,6 +405,14 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_inl: + change_by(new_localir(value), 1); + break; + + case op_del: + change_by(new_localir(value), -1); + break; + case op_loc: push( new_wordir(value) From 79d4ab1d96ff2f3deaf3bd707f299c9e05d9bfc7 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 2 Oct 2016 16:08:46 +0200 Subject: [PATCH 056/230] Add zrl opcode. Keep track of local sizes as well as offsets. --- mach/proto/mcg/procedure.h | 3 +++ mach/proto/mcg/treebuilder.c | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/mach/proto/mcg/procedure.h b/mach/proto/mcg/procedure.h index de11c5458..2414db050 100644 --- a/mach/proto/mcg/procedure.h +++ b/mach/proto/mcg/procedure.h @@ -3,6 +3,8 @@ struct local { + int size; + int offset; bool is_register; }; @@ -16,6 +18,7 @@ struct procedure }; extern void procedure_compile(struct procedure* proc); +extern void procedure_update_bb_graph(struct procedure* proc); #endif diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index e8675e613..c99bb7edd 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -111,6 +111,7 @@ void tb_regvar(struct procedure* procedure, arith offset, int size, int type, in { struct local* local = calloc(1, sizeof(*local)); local->size = size; + local->offset = offset; local->is_register = true; imap_put(&procedure->locals, offset, local); } @@ -413,6 +414,16 @@ static void insn_ivalue(int opcode, arith value) change_by(new_localir(value), -1); break; + case op_zrl: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + new_localir(value), + new_wordir(0) + ) + ); + break; + case op_loc: push( new_wordir(value) From b11f96e8fe5a6a5e3025676f79deea303111a7c9 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 2 Oct 2016 17:24:31 +0200 Subject: [PATCH 057/230] Add array push/pop; fix ghastly memory overrun bug. --- modules/src/data/array.c | 22 ++++++++++++++++++---- modules/src/data/array.h | 4 ++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/modules/src/data/array.c b/modules/src/data/array.c index bfaaf8e84..13c0b6cf6 100644 --- a/modules/src/data/array.c +++ b/modules/src/data/array.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "array.h" static void extend(struct array* array) @@ -8,7 +9,7 @@ static void extend(struct array* array) if (array->count == array->max) { int newmax = (array->max == 0) ? 8 : (array->max * 2); - void** newarray = realloc(array->item, newmax * sizeof(void*)); + struct array* newarray = realloc(array->item, newmax * sizeof(*newarray)); array->max = newmax; array->item = newarray; @@ -24,16 +25,21 @@ void array_append(void* arrayp, void* value) array->count++; } -bool array_contains(void* arrayp, void* value) +int array_indexof(void* arrayp, void* value) { struct array* array = arrayp; int i; for (i=0; icount; i++) if (array->item[i] == value) - return true; + return i; - return false; + return -1; +} + +bool array_contains(void* arrayp, void* value) +{ + return (array_indexof(arrayp, value) != -1); } bool array_appendu(void* arrayp, void* value) @@ -76,5 +82,13 @@ void array_remove(void* arrayp, void* value) } } +void* array_pop(void* arrayp) +{ + struct array* array = arrayp; + + assert(array->count > 0); + return array->item[array->count--]; +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/modules/src/data/array.h b/modules/src/data/array.h index 63951ff5d..8762d7e6d 100644 --- a/modules/src/data/array.h +++ b/modules/src/data/array.h @@ -22,6 +22,10 @@ extern bool array_appendu(void* array, void* value); extern void array_insert(void* array, void* value, int before); extern void array_remove(void* array, void* value); extern bool array_contains(void* array, void* value); +extern int array_indexof(void* array, void* value); + +#define array_push(a, v) array_append(a, v) +extern void* array_pop(void* array); #endif From c079e974928bf9f983fe8c1ebfaae80def45a6f8 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 2 Oct 2016 17:50:34 +0200 Subject: [PATCH 058/230] Perform SSA conversion of locals. Much, *much* better code now, at least inasmuch as it looks better before register allocation. Basic blocks now know their own successors and predecessors (after a certain point in the IR processing). --- mach/proto/mcg/basicblock.c | 6 +- mach/proto/mcg/basicblock.h | 25 ++ mach/proto/mcg/ir.c | 2 +- mach/proto/mcg/main.c | 5 + mach/proto/mcg/mcg.h | 18 +- mach/proto/mcg/pass_convertstackops.c | 62 ++--- mach/proto/mcg/pass_ssa.c | 340 ++++++++++++++++++++++++++ mach/proto/mcg/procedure.c | 56 ++++- mach/proto/mcg/table | 13 + util/mcgg/ir.dat | 1 + 10 files changed, 458 insertions(+), 70 deletions(-) create mode 100644 mach/proto/mcg/basicblock.h create mode 100644 mach/proto/mcg/pass_ssa.c diff --git a/mach/proto/mcg/basicblock.c b/mach/proto/mcg/basicblock.c index e44f553ee..5a30d9a90 100644 --- a/mach/proto/mcg/basicblock.c +++ b/mach/proto/mcg/basicblock.c @@ -24,7 +24,7 @@ struct basicblock* bb_get(const char* name) p = str2idf((char*) name, 0); if (!p->block) { - p->block = calloc(sizeof(struct basicblock), 1); + p->block = calloc(1, sizeof(*p->block)); p->block->name = name; } return p->block; @@ -39,8 +39,4 @@ void bb_alias(struct basicblock* block, const char* name) p->block = block; } -void bb_print(char k, struct basicblock* block) -{ -} - /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h new file mode 100644 index 000000000..8f36e5eee --- /dev/null +++ b/mach/proto/mcg/basicblock.h @@ -0,0 +1,25 @@ +#ifndef BASICBLOCK_H +#define BASICBLOCK_H + +struct basicblock +{ + const char* name; + ARRAYOF(struct em) ems; + ARRAYOF(struct ir) irs; + ARRAYOF(struct hop) hops; + + ARRAYOF(struct basicblock) prevs; + ARRAYOF(struct basicblock) nexts; + int order; /* used by SSA code */ + + bool is_fake : 1; + bool is_root : 1; + bool is_terminated : 1; +}; + +extern void bb_init(void); +extern struct basicblock* bb_get(const char* name); +extern void bb_alias(struct basicblock* block, const char* name); + +#endif + diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index 0aea3ea50..de3ec396f 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -107,7 +107,7 @@ static void print_expr(char k, const struct ir* ir) tracef(k, "%s", ir_data[ir->opcode].name); if (ir->size) tracef(k, "%d", ir->size); - tracef(k, ":%d(", ir->id); + tracef(k, "("); switch (ir->opcode) { diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 5d450bdfc..bf722f4f9 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -5,10 +5,15 @@ bool tracing(char k) switch (k) { case 0: return true; + case 'S': return true; case 'E': return false; + case 'G': return true; case '0': return false; case '1': return false; case '2': return false; + case '3': return false; + case '4': return false; + case '5': return false; case 'I': return true; default: return true; } diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 78560499b..ba23e2d4f 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -24,6 +24,7 @@ #include "ir.h" #include "mcgg.h" #include "hop.h" +#include "basicblock.h" #include "procedure.h" extern char em_pseu[][4]; @@ -73,17 +74,6 @@ struct em } u; }; -struct basicblock -{ - const char* name; - ARRAYOF(struct em) ems; - ARRAYOF(struct ir) irs; - ARRAYOF(struct hop) hops; - bool is_fake : 1; - bool is_root : 1; - bool is_terminated : 1; -}; - extern const char* aprintf(const char* fmt, ...); extern void tracef(char k, const char* fmt, ...); extern bool tracing(char k); @@ -104,11 +94,6 @@ extern void data_block(const uint8_t* data, size_t size, bool is_ro); extern void data_offset(const char* label, arith offset, bool is_ro); extern void data_bss(arith size, int init); -extern void bb_init(void); -extern struct basicblock* bb_get(const char* name); -extern void bb_alias(struct basicblock* block, const char* name); -extern void bb_print(char k, struct basicblock* block); - extern void tb_filestart(void); extern void tb_fileend(void); extern void tb_procedure(struct procedure* proc); @@ -120,6 +105,7 @@ extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_instruction_selector(struct procedure* proc); extern void pass_promote_float_ops(struct procedure* proc); extern void pass_group_irs(struct procedure* proc); +extern void pass_convert_locals_to_ssa(struct procedure* proc); #endif diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index f5764484a..d555b58ba 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -41,28 +41,6 @@ static struct ir* get_first_pop(struct basicblock* bb) return NULL; } -static bool collect_outputs_cb(struct ir* ir, void* user) -{ - struct basicblock* caller = user; - - if (ir->opcode == IR_BLOCK) - pmap_add(&graph, caller, ir->u.bvalue); - return false; -} - -static void make_bb_graph(struct procedure* proc) -{ - int i, j; - - graph.count = 0; - for (i=0; iblocks.count; i++) - { - struct basicblock* bb = proc->blocks.item[i]; - for (j=0; jirs.count; j++) - ir_walk(bb->irs.item[j], collect_outputs_cb, bb); - } -} - static void convert_block(struct procedure* proc, struct basicblock* bb) { int i, j; @@ -78,32 +56,26 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) /* Abort unless *every* successor block of this one starts with a pop * of the same size... */ - for (i=0; inexts.count; i++) { - if (graph.item[i].left == bb) - { - struct basicblock* outbb = graph.item[i].right; + struct basicblock* outbb = bb->nexts.item[i]; - ir = get_first_pop(outbb); + ir = get_first_pop(outbb); + if (!ir || (ir->size != lastpush->size)) + return; + array_appendu(&pops, ir); + + /* Also abort unless *every* predecessor block of the one we've + * just found *also* ends in a push of the same size. */ + + for (j=0; jprevs.count; j++) + { + struct basicblock* inbb = outbb->prevs.item[j]; + + ir = get_last_push(inbb); if (!ir || (ir->size != lastpush->size)) return; - array_appendu(&pops, ir); - - /* Also abort unless *every* predecessor block of the one we've - * just found *also* ends in a push of the same size. */ - - for (j=0; jsize != lastpush->size)) - return; - array_appendu(&pushes, ir); - } - } + array_appendu(&pushes, ir); } } @@ -139,8 +111,6 @@ void pass_convert_stack_ops(struct procedure* proc) { int i; - make_bb_graph(proc); - for (i=0; iblocks.count; i++) convert_block(proc, proc->blocks.item[i]); } diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c new file mode 100644 index 000000000..87a0b973e --- /dev/null +++ b/mach/proto/mcg/pass_ssa.c @@ -0,0 +1,340 @@ +#include "mcg.h" + +static struct basicblock* entry; +static ARRAYOF(struct basicblock) postorder; +static PMAPOF(struct basicblock, struct basicblock) dominators; +static PMAPOF(struct basicblock, struct basicblock) dominancefrontiers; + +static struct local* current_local; +static ARRAYOF(struct basicblock) defining; +static ARRAYOF(struct basicblock) needsphis; +static ARRAYOF(struct ir) definitions; +static ARRAYOF(struct basicblock) rewritten; + +static void recursively_walk_blocks(struct basicblock* bb); + +static void recursively_walk_graph_postorder(struct basicblock* bb) +{ + static ARRAYOF(struct basicblock) pending; + int i; + + if (array_contains(&postorder, bb) || array_contains(&pending, bb)) + return; + + array_appendu(&pending, bb); + + i = 0; + for (i=0; inexts.count; i++) + recursively_walk_graph_postorder(bb->nexts.item[i]); + + array_remove(&pending, bb); + bb->order = postorder.count; + array_appendu(&postorder, bb); +} + +static void walk_graph_postorder() +{ + int i; + + postorder.count = 0; + recursively_walk_graph_postorder(entry); + + for (i=0; iname); + } +} + +static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2) +{ + while (p1 != p2) + { + while (p1->order < p2->order) + p1 = pmap_get(&dominators, p1); + + while (p2->order < p1->order) + p2 = pmap_get(&dominators, p2); + } + + return p1; +} + +static void calculate_dominance_graph(void) +{ + /* This is the algorithm described here: + * + * Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy. + * "A simple, fast dominance algorithm." + * Software Practice & Experience 4.1-10 (2001): 1-8. + * + * https://www.cs.rice.edu/~keith/EMBED/dom.pdf + */ + + int i, j; + bool changed; + + dominators.count = 0; + + /* The entry block dominates itself. */ + + pmap_put(&dominators, entry, entry); + + do + { + changed = false; + + for (i = postorder.count-2; i >= 0; i--) + { + struct basicblock* b = postorder.item[i]; + struct basicblock* new_idom = NULL; + for (j=0; jprevs.count; j++) + { + struct basicblock* p = b->prevs.item[j]; + + if (!new_idom) + new_idom = p; + else if (pmap_get(&dominators, p)) + new_idom = intersect(p, new_idom); + } + + if (pmap_get(&dominators, b) != new_idom) + { + pmap_put(&dominators, b, new_idom); + changed = true; + } + } + } + while (changed); + + for (i=0; i %s\n", + dominators.item[i].left->name, + dominators.item[i].right->name); + } +} + +static void calculate_dominance_frontier_graph(void) +{ + /* This is the algorithm described here: + * + * Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy. + * "A simple, fast dominance algorithm." + * Software Practice & Experience 4.1-10 (2001): 1-8. + * + * https://www.cs.rice.edu/~keith/EMBED/dom.pdf + */ + + int i, j; + + dominancefrontiers.count = 0; + + for (i=0; iprevs.count >= 2) + { + for (j=0; jprevs.count; j++) + { + struct basicblock* runner = b->prevs.item[j]; + while (runner != dominator) + { + tracef('S', "S: %s is in %s's dominance frontier\n", + b->name, runner->name); + pmap_add(&dominancefrontiers, runner, b); + runner = pmap_get(&dominators, runner); + } + } + } + } + +} + +static bool is_local(struct ir* ir) +{ + return ((ir->opcode == IR_LOAD) && + (ir->left->opcode == IR_LOCAL) && + (ir->left->u.ivalue == current_local->offset)); +} + +static bool rewrite_loads_cb(struct ir* ir, void* user) +{ + struct ir* definition = user; + + /* Rewrite in place where possible. */ + + if (ir->left && is_local(ir->left)) + ir->left = definition; + if (ir->right && is_local(ir->right)) + ir->right = definition; + + /* Otherwise, go via a IR_REG (which should, with luck, turn into no code). */ + if (is_local(ir)) + { + ir->opcode = IR_NOP; + ir->left = definition; + ir->right = NULL; + } + + return false; +} + +/* Walks the tree, rewriting IRs to push new definitions downwards. */ + +static void recursively_rewrite_tree(struct basicblock* bb) +{ + int i; + int defcount = definitions.count; + + if (array_contains(&rewritten, bb)) + return; + array_appendu(&rewritten, bb); + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + + if (definitions.count > 0) + { + ir_walk(ir, rewrite_loads_cb, definitions.item[definitions.count-1]); + } + + if (((ir->opcode == IR_STORE) && + (ir->left->opcode == IR_LOCAL) && + (ir->left->u.ivalue == current_local->offset) + ) || + ((i == 0) && + (ir->opcode == IR_PHI) && + array_contains(&needsphis, bb))) + { + /* This is a definition. */ + + if (ir->opcode == IR_STORE) + { + ir->opcode = IR_NOP; + ir->left = ir->right; + ir->right = NULL; + } + array_push(&definitions, ir); + } + } + + for (i=0; inexts.count; i++) + { + struct basicblock* nextbb = bb->nexts.item[i]; + struct ir* ir = nextbb->irs.item[0]; + + if ((definitions.count > 0) && + (ir->opcode == IR_PHI) && + array_contains(&needsphis, nextbb)) + { + array_appendu(&ir->u.phivalue, definitions.item[definitions.count-1]); + } + + recursively_rewrite_tree(nextbb); + } + + definitions.count = defcount; +} + +static void ssa_convert(void) +{ + int i, j; + + /* If this is a parameter, synthesise a load/store at the beginning of the + * program to force it into a register. (Unless it's written to it'll + * always be read from the frame.) */ + + if (current_local->offset >= 0) + { + struct ir* ir = new_ir2( + IR_STORE, current_local->size, + new_localir(current_local->offset), + new_ir1( + IR_LOAD, current_local->size, + new_localir(current_local->offset) + ) + ); + + ir->root = ir; + ir->left->root = ir; + ir->right->root = ir; + ir->right->left->root = ir; + array_insert(&entry->irs, ir, 0); + } + + defining.count = 0; + needsphis.count = 0; + + /* Find everwhere where the variable is *defined*. */ + + for (i=0; iirs.count; j++) + { + struct ir* ir = bb->irs.item[j]; + if ((ir->opcode == IR_STORE) && + (ir->left->opcode == IR_LOCAL) && + (ir->left->u.ivalue == current_local->offset)) + { + array_appendu(&defining, bb); + } + } + } + + /* Every block which is in one of the defining block's dominance frontiers + * requires a phi. Remember that adding a phi also adds a definition. */ + + for (i=0; ioffset, dominates->name); + } + } + + /* Add empty phi nodes. */ + + for (i=0; isize); + ir->root = ir; + array_insert(&bb->irs, ir, 0); + } + + /* Now do the rewriting by walking the tree, pushing definitions down the tree. */ + + definitions.count = 0; + rewritten.count = 0; + recursively_rewrite_tree(entry); +} + +void pass_convert_locals_to_ssa(struct procedure* proc) +{ + int i; + + entry = proc->blocks.item[0]; + walk_graph_postorder(); + assert(postorder.count == proc->blocks.count); + calculate_dominance_graph(); + calculate_dominance_frontier_graph(); + + for (i=0; ilocals.count; i++) + { + current_local = proc->locals.item[i].right; + if (current_local->is_register) + ssa_convert(); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index dc11e0a43..5ea0372b9 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -27,15 +27,67 @@ void procedure_compile(struct procedure* proc) print_blocks('1', proc); pass_group_irs(proc); + /* Passes from here on must preserve IR grouping */ + pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); - pass_convert_stack_ops(proc); - pass_promote_float_ops(proc); + + procedure_update_bb_graph(proc); + /* Passes from here on can't alter the BB graph */ print_blocks('2', proc); + pass_convert_stack_ops(proc); + print_blocks('3', proc); + pass_convert_locals_to_ssa(proc); + print_blocks('4', proc); + pass_promote_float_ops(proc); + print_blocks('5', proc); + pass_instruction_selector(proc); } +static bool collect_outputs_cb(struct ir* ir, void* user) +{ + struct basicblock* caller = user; + + if (ir->opcode == IR_BLOCK) + { + array_appendu(&caller->nexts, ir->u.bvalue); + array_appendu(&ir->u.bvalue->prevs, caller); + } + return false; +} + +void procedure_update_bb_graph(struct procedure* proc) +{ + int i, j; + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + bb->prevs.count = bb->nexts.count = 0; + } + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + for (j=0; jirs.count; j++) + ir_walk(bb->irs.item[j], collect_outputs_cb, bb); + } + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + + for (j=0; jnexts.count; j++) + { + tracef('G', "G: graph %s -> %s\n", + bb->name, + bb->nexts.item[j]->name); + } + } +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 6d3e231d9..d523cfb09 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -39,6 +39,7 @@ PATTERNS int; float; + any; PAIR(BLOCK4, BLOCK4); @@ -69,6 +70,13 @@ PATTERNS prefers int(in) cost 1; + int = NOP4(in:int) + emit "mov %int, %in" + cost 1; + + any = PHI4 + cost 0; + float = in:REG4 prefers float(in) cost 1; @@ -146,6 +154,11 @@ PATTERNS emit "b $false" cost 8; + CJUMPLT(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) + emit "blt $true" + emit "b $false" + cost 8; + CALL(dest:LABEL4) emit "bl $dest" cost 4; diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index b12cf8934..baa4617a6 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -6,6 +6,7 @@ S CONST # must be followed by float form S CONSTF S REG +S NOP S LABEL S BLOCK V PAIR From 3aa30e50d1ed3d6f02d72873974e59989299d672 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 2 Oct 2016 21:51:25 +0200 Subject: [PATCH 059/230] Come up with a syntax for register constraints. --- mach/proto/mcg/table | 137 ++++++++++++++++++++----------------------- util/mcgg/gram.y | 52 ++++++++++++---- util/mcgg/iburg.c | 1 - util/mcgg/iburg.h | 21 ++++++- util/mcgg/scan.l | 5 +- 5 files changed, 129 insertions(+), 87 deletions(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index d523cfb09..4292dd8e0 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -29,6 +29,9 @@ REGISTERS DECLARATIONS + reg; + cc; + address fragment; aluparam fragment; @@ -37,88 +40,75 @@ PATTERNS /* Special */ - int; - float; - any; + reg; PAIR(BLOCK4, BLOCK4); /* Miscellaneous special things */ - PUSH4(in:int) + PUSH4(in:reg) emit "push %in" cost 4; - int = POP4 - emit "pop %int" + reg = POP4 + emit "pop %reg" cost 4; RET emit "ret" cost 4; - SETRET4(in:ret) - emit "mov r0, %in" + SETRET4(in:reg) + with ret reg cost 4; STACKADJUST4(delta:aluparam) emit "add sp, sp, %delta" cost 4; - int = in:REG4 - prefers int(in) + reg = in:REG4 + with (reg == in) cost 1; - int = NOP4(in:int) - emit "mov %int, %in" + reg = NOP4(in:reg) + with (reg == in) cost 1; - any = PHI4 - cost 0; - - float = in:REG4 - prefers float(in) - cost 1; - - ret = in:any emit "mov %ret, %in" cost 1; - any = in:int emit "mov %any, %in" cost 1; - int = in:any emit "mov %int, %in" cost 1; - any = in:float emit "mov %any, %in" cost 1; - float = in:any emit "mov %float, %in" cost 1; - /* Memory operations */ - STORE4(addr:address, value:int) + STORE4(addr:address, value:reg) + with int value emit "str %value, %addr" cost 4; - STORE1(addr:address, value:int) + STORE1(addr:address, value:reg) + with int value emit "strb %value, %addr" cost 4; - int = LOAD4(addr:address) - emit "ldr %int, %addr" + reg = LOAD4(addr:address) + emit "ldr %reg, %addr" cost 4; - int = LOAD1(addr:address) - emit "ldrb %int, %addr" + reg = LOAD1(addr:address) + emit "ldrb %reg, %addr" cost 4; - int = CIU14(LOAD1(addr:address)) - emit "ldrb %int, %addr" + reg = CIU14(LOAD1(addr:address)) + emit "ldrb %reg, %addr" cost 4; - int = CII14(CIU41(CIU14(LOAD1(addr:address)))) - emit "ldrsb %int, %addr" + reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) + emit "ldrsb %reg, %addr" cost 4; /* Locals */ - int = in:LOCAL4 - emit "add %int, fp, #$in" + reg = in:LOCAL4 + emit "add %reg, fp, #$in" cost 4; address = in:LOCAL4 @@ -127,13 +117,16 @@ PATTERNS /* Memory addressing modes */ - address = ADD4(addr:int, offset:CONST4) + address = ADD4(addr:reg, offset:CONST4) + with int addr emit "[%addr, #$offset]"; - address = ADD4(addr1:int, addr2:int) + address = ADD4(addr1:reg, addr2:reg) + with int addr1, int addr2 emit "[%addr1, %addr2]"; - address = addr:int + address = addr:reg + with int addr emit "[%addr]"; @@ -166,80 +159,80 @@ PATTERNS /* Comparisons */ - cc = COMPARES4(left:int, right:aluparam) + cc = COMPARES4(left:reg, right:aluparam) emit "cmp %left, %right" cost 4; - cc = COMPARES4(COMPARES4(left:int, right:aluparam), CONST4) + cc = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4) emit "cmp %left, %right" cost 4; - int = cc - emit "mov %int, #0" - emit "movlt %int, #-1" - emit "movgt %int, #1" + reg = cc + emit "mov %reg, #0" + emit "movlt %reg, #-1" + emit "movgt %reg, #1" cost 12; /* Conversions */ - int = CII14(CIU41(value:int)) - emit "sxtb %int, %value" + reg = CII14(CIU41(value:reg)) + emit "sxtb %reg, %value" cost 4; - int = CIU41(in:int) - emit "and %int, %in, #0xff" + reg = CIU41(in:reg) + emit "and %reg, %in, #0xff" cost 4; /* ALU operations */ - int = ADD4(left:int, right:aluparam) - emit "add %int, %left, %right" + reg = ADD4(left:reg, right:aluparam) + emit "add %reg, %left, %right" cost 4; - int = ADD4(left:aluparam, right:int) - emit "add %int, %right, %left" + reg = ADD4(left:aluparam, right:reg) + emit "add %reg, %right, %left" cost 4; - int = MOD4(left:int, right:int) - emit "udiv %int, %left, %right" - emit "mls %int, %int, %right, %left" + reg = MOD4(left:reg, right:reg) + emit "udiv %reg, %left, %right" + emit "mls %reg, %reg, %right, %left" cost 8; - int = DIV4(left:int, right:aluparam) - emit "div %int, %left, %right" + reg = DIV4(left:reg, right:aluparam) + emit "div %reg, %left, %right" cost 4; aluparam = value:CONST4 emit "#$value"; - aluparam = value:int + aluparam = value:reg emit "%value"; - int = value:aluparam - emit "mov %int, %value" + reg = value:aluparam + emit "mov %reg, %value" cost 4; - int = value:LABEL4 - emit "adr %int, $value" + reg = value:LABEL4 + emit "adr %reg, $value" cost 4; - int = value:BLOCK4 - emit "adr %int, $value" + reg = value:BLOCK4 + emit "adr %reg, $value" cost 4; - int = value:CONST4 - emit "ldr %int, address-containing-$value" + reg = value:CONST4 + emit "ldr %reg, address-containing-$value" cost 8; - float = value:CONSTF4 - emit "vldr %float, address-containing-$value" + reg = value:CONSTF4 + emit "vldr %reg, address-containing-$value" cost 8; /* FPU operations */ - float = ADDF4(left:float, right:float) - emit "fadds %float, %left, %right" + reg = ADDF4(left:reg, right:reg) + emit "fadds %reg, %left, %right" cost 4; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index e65a6256b..9927d1598 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -24,28 +24,34 @@ static int nextern = 1; struct stringlist* stringlist; struct terminfo terminfo; struct expr* expr; + struct constraint* constraint; } %term ALLOCATES %term COST %term DECLARATIONS %term EMIT +%term EQUALS %term FRAGMENT +%term NOTEQUALS %term PATTERNS -%term REGISTERS %term PREFERS -%term REQUIRES +%term REGISTERS +%term WHEN +%term WITH %token INT %token ID %token QFRAGMENT %type allocates +%type constraint +%type constraints %type declaration %type register -%type emit +%type pattern_constraints +%type pattern_emit %type pattern -%type cfragments %type qfragments %type terminfo %type rhs @@ -102,9 +108,10 @@ pattern : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } | rhs { $$ = rule("stmt", $1, nextern++); } | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } - | pattern REQUIRES predicate { $$ = $1; array_append(&$$->requires, $3); } - | emit { $$ = $1; } + | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); } | pattern COST INT { $$ = $1; $$->cost = $3; } + | pattern_constraints { $$ = $1; } + | pattern_emit { $$ = $1; } ; rhs @@ -115,12 +122,10 @@ rhs terminfo : ID { $$.name = $1; } - | ID '.' ID { $$.name = $1; $$.regattr = $3; } | ID ':' ID { $$.label = $1; $$.name = $3; } - | ID ':' ID '.' ID { $$.label = $1; $$.name = $3; $$.regattr = $5; } ; -emit +pattern_emit : pattern EMIT qfragments { $$ = $1; if (!$$->lhs->is_fragment) @@ -129,6 +134,33 @@ emit } ; +pattern_constraints + : pattern WITH constraints { + struct constraint* c = $3; + $$ = $1; + while (c) + { + array_append(&$$->constraints, c); + c = c->next; + } + } + ; + +constraints + : constraint { $$ = $1; } + | constraints ',' constraint { $$ = $3; $$->next = $1; } + ; + +constraint + : '(' constraint ')' { $$ = $2; } + | ID ID { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_ATTR; $$->left = $1; $$->right = $2; } + | ID EQUALS ID { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_EQUALS; $$->left = $1; $$->right = $3; } + | ID NOTEQUALS ID { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_NOTEQUALS; $$->left = $1; $$->right = $3; } + ; + qfragments : /* nothing */ { $$ = calloc(1, sizeof *$$); } | qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); } @@ -139,7 +171,7 @@ predicate ; predicate_args - : /* nothing */ + : /* nothing */ { $$ = NULL; } | ID { $$ = calloc(1, sizeof *$$); $$->name = $1; } | ID ',' predicate_args { $$ = calloc(1, sizeof *$$); $$->name = $1; $$->next = $3; } ; diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 074198d0c..2fb6e2cab 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -262,7 +262,6 @@ void addregclass(struct reg* reg, const char* id) } reg->classes |= 1<<(p->number); - nonterm(id, true); } struct regclass* getregclass(const char* id) diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 919f4471d..24700e5e4 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -16,6 +16,21 @@ typedef enum typedef struct rule* Rule; typedef struct term* Term; +enum +{ + CONSTRAINT_ATTR, + CONSTRAINT_EQUALS, + CONSTRAINT_NOTEQUALS +}; + +struct constraint +{ + int type; + const char* left; + const char* right; + struct constraint* next; +}; + struct expr { const char* name; @@ -26,7 +41,6 @@ struct terminfo { const char* name; const char* label; - const char* regattr; }; struct reg @@ -97,8 +111,9 @@ struct rule Rule chain; /* next chain rule with same rhs */ Rule decode; /* next rule with same lhs */ Rule kids; /* next rule with same burm_kids pattern */ - ARRAYOF(struct predicate) prefers; /* C predicates */ - ARRAYOF(struct predicate) requires; /* C predicates */ + ARRAYOF(struct expr) prefers; /* C predicates */ + ARRAYOF(struct expr) requires; /* C predicates */ + ARRAYOF(struct constraint) constraints; /* register constraints */ struct stringlist code; /* compiler output code strings */ }; extern Rule rule(char* id, Tree pattern, int ern); diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 30280c492..2d04f52c0 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -43,7 +43,10 @@ static int braces = 0; "emit" return EMIT; "fragment" return FRAGMENT; "prefers" return PREFERS; -"requires" return REQUIRES; +"when" return WHEN; +"with" return WITH; +"==" return EQUALS; +"!=" return NOTEQUALS; "//"[^\n]*\n ; From 288ee562035e0c36509540748bdf5b62711e2baf Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 2 Oct 2016 23:25:54 +0200 Subject: [PATCH 060/230] Get quite a long way towards basic output-register equality constraints (needed to make special nodes like NOP work properly). Realise that the way I'm dealing with the instruction selector is all wrong; I need to physically copy chunks of tree to give to burg (so I can terminate them correctly). --- mach/proto/mcg/hop.c | 13 +- mach/proto/mcg/hop.h | 12 +- mach/proto/mcg/ir.h | 2 +- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_instructionselection.c | 34 +++- mach/proto/mcg/table | 1 + mach/proto/mcg/vreg.c | 10 ++ mach/proto/mcg/vreg.h | 12 ++ util/mcgg/iburg.c | 182 +++++++++++++-------- util/mcgg/mcgg.h | 4 +- 10 files changed, 177 insertions(+), 94 deletions(-) create mode 100644 mach/proto/mcg/vreg.c create mode 100644 mach/proto/mcg/vreg.h diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index a57d4988a..e4552e04e 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -28,11 +28,10 @@ void hop_add_string_insel(struct hop* hop, const char* string) array_append(&hop->insels, insel); } -void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no) +void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg) { - struct insel* insel = new_insel(INSEL_REG); - insel->u.reg.ir = ir; - insel->u.reg.insn_no = insn_no; + struct insel* insel = new_insel(INSEL_VREG); + insel->u.vreg = vreg; array_append(&hop->insels, insel); } @@ -61,7 +60,7 @@ void hop_print(char k, struct hop* hop) if (soi) { - tracef(k, "%c: %d: ", k, hop->id); + tracef(k, "%c: %d from $%d: ", k, hop->id, hop->ir->id); soi = false; } @@ -72,8 +71,8 @@ void hop_print(char k, struct hop* hop) soi = true; break; - case INSEL_REG: - tracef(k, "$%d.%d", insel->u.reg.ir->id, insel->u.reg.insn_no); + case INSEL_VREG: + tracef(k, "%%%d", insel->u.vreg->id); break; case INSEL_STRING: diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index e6cc8f809..3e2f9d6e7 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -4,7 +4,7 @@ enum insel_type { INSEL_STRING, - INSEL_REG, + INSEL_VREG, INSEL_VALUE, INSEL_EOI }; @@ -15,12 +15,7 @@ struct insel union { const char* string; - struct - { - struct ir* ir; - int insn_no; - } - reg; + struct vreg* vreg; struct ir* value; } u; @@ -32,12 +27,13 @@ struct hop int insn_no; struct ir* ir; ARRAYOF(struct insel) insels; + struct vreg* output; }; extern struct hop* new_hop(int insn_no, struct ir* ir); extern void hop_add_string_insel(struct hop* hop, const char* string); -extern void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no); +extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_eoi_insel(struct hop* hop); diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index dc66ff757..ce90fcbde 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -23,7 +23,7 @@ struct ir void* state_label; /* used by the iburg instruction selector */ int insn_no; /* the table rule number for this instruction */ int goal_no; /* the semantic type of this instruction; not stmt */ - ARRAYOF(struct hop) hops; /* only for root IRs */ + IMAPOF(struct hop) hops; /* only for root IRs; by goal */ }; extern const char* ir_names[]; diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index ba23e2d4f..a5fa1102c 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -24,6 +24,7 @@ #include "ir.h" #include "mcgg.h" #include "hop.h" +#include "vreg.h" #include "basicblock.h" #include "procedure.h" diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 2cb070dde..a1f80a855 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -29,7 +29,9 @@ int burm_calculate_label(struct ir* ir) static void emit_reg(struct ir* ir, int goal) { - hop_add_reg_insel(current_hop, ir, goal); + struct hop* hop = imap_get(¤t_ir->hops, goal); + + hop_add_vreg_insel(current_hop, hop->output); } static void emit_string(const char* data) @@ -50,23 +52,30 @@ static void emit_value(struct ir* ir) hop_add_value_insel(current_hop, ir); } -static void emit_resultreg(void) -{ -} - static void emit_eoi(void) { hop_add_eoi_insel(current_hop); } +static void emit_constraint_equals(struct ir* ir, int goal) +{ + struct hop* hop; + + if (!goal) + goal = 2; + hop = imap_get(¤t_ir->hops, goal); + + current_hop->output = hop->output; +} + static const struct burm_emitter_data emitter_data = { &emit_string, &emit_fragment, &emit_reg, &emit_value, - &emit_resultreg, - &emit_eoi + &emit_eoi, + &emit_constraint_equals }; @@ -83,6 +92,11 @@ static void walk_instructions(struct ir* ir, int goal) { parent_hop = current_hop; current_hop = new_hop(insn_no, ir); + if (goal != 1) + { + current_hop->output = new_vreg(); + imap_add(¤t_ir->hops, goal, current_hop); + } } burm_kids(ir, insn_no, children); @@ -102,8 +116,10 @@ static void walk_instructions(struct ir* ir, int goal) if (!insndata->is_fragment) { - if (insndata->emitter) - insndata->emitter(ir, &emitter_data); + /* This may cause the vregs to be reassigned for this instruction (and + * fragments contained within it). */ + + insndata->emitter(ir, &emitter_data); hop_print('I', current_hop); array_append(&ir->hops, current_hop); diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 4292dd8e0..0db5f6a99 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -69,6 +69,7 @@ PATTERNS reg = in:REG4 with (reg == in) + emit "reg %reg" cost 1; reg = NOP4(in:reg) diff --git a/mach/proto/mcg/vreg.c b/mach/proto/mcg/vreg.c new file mode 100644 index 000000000..636475de7 --- /dev/null +++ b/mach/proto/mcg/vreg.c @@ -0,0 +1,10 @@ +#include "mcg.h" + +static int vreg_count = 1; + +struct vreg* new_vreg(void) +{ + struct vreg* vreg = calloc(1, sizeof *vreg); + vreg->id = vreg_count++; + return vreg; +} diff --git a/mach/proto/mcg/vreg.h b/mach/proto/mcg/vreg.h new file mode 100644 index 000000000..ef92fd224 --- /dev/null +++ b/mach/proto/mcg/vreg.h @@ -0,0 +1,12 @@ +#ifndef VREG_H +#define VREG_H + +struct vreg +{ + int id; +}; + +extern struct vreg* new_vreg(void); + +#endif + diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 2fb6e2cab..937a0df8e 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -954,6 +954,49 @@ static void emitpredicatedefinitions(Rule r) } } +static void invalid_equals_constraint(Rule rule) +{ + yylineno = rule->lineno; + yyerror("left hand side of an equality constraint must be the output register"); + exit(1); +} + +static void emit_ir_expr(Rule rule, const char* label) +{ + if (strcmp(label, rule->lhs->name) == 0) + print("node, %P%s_NT", label); + else + { + Tree node; + uint32_t path = find_label(rule->pattern, label, 0, &node); + Nonterm nt = node->op; + + if (path == PATH_MISSING) + label_not_found(rule, label); + + print_path(path); + if (nt->kind == NONTERM) + print(", %P%s_NT", ((Nonterm)node->op)->name); + else + print(", 0"); + } +} + +static void emit_constraint(Rule rule, struct constraint* c) +{ + switch (c->type) + { + case CONSTRAINT_EQUALS: + if (strcmp(c->left, rule->lhs->name) != 0) + invalid_equals_constraint(rule); + + print("%1data->emit_constraint_equals("); + emit_ir_expr(rule, c->right); + print(");\n"); + break; + } +} + /* emitinsndata - emit the code generation data */ static void emitinsndata(Rule rules) { @@ -964,68 +1007,8 @@ static void emitinsndata(Rule rules) while (r) { struct stringfragment* f = r->code.first; - if (f) - { - print("/* %R */\n", r); - print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern); - while (f) - { - switch (f->data[0]) - { - case '%': - { - const char* label = f->data + 1; - - if (strcmp(label, r->lhs->name) == 0) - print("%1data->emit_reg(node, %P%s_NT);\n", label); - else - { - Tree node; - uint32_t path = find_label(r->pattern, label, 0, &node); - Nonterm nt = node->op; - - if (path == PATH_MISSING) - label_not_found(r, label); - - if (nt->is_fragment) - print("%1data->emit_fragment("); - else - print("%1data->emit_reg("); - - print_path(path); - print(", %P%s_NT);\n", ((Nonterm)node->op)->name); - } - break; - } - - case '$': - { - const char* label = f->data + 1; - uint32_t path = find_label(r->pattern, label, 0, NULL); - print("%1data->emit_value("); - if (path == PATH_MISSING) - label_not_found(r, label); - print_path(path); - print(");\n"); - break; - } - - case '\n': - assert(f->data[1] == 0); - print("%1data->emit_eoi();\n"); - break; - - default: - print("%1data->emit_string(\"%s\");\n", f->data); - } - - f = f->next; - } - - print("}\n\n"); - } - else + if (!f) { /* This instruction has no code; make sure it's not a fragment. */ if (r->lhs->is_fragment) @@ -1035,6 +1018,77 @@ static void emitinsndata(Rule rules) } } + print("/* %R */\n", r); + print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern); + + /* Constraints come first, because they may cause vreg reassignment, which + * we want to happen before the instruction emission. */ + + { + int i; + + for (i=0; iconstraints.count; i++) + { + struct constraint* c = r->constraints.item[i]; + emit_constraint(r, c); + } + } + + while (f) + { + switch (f->data[0]) + { + case '%': + { + const char* label = f->data + 1; + + if (strcmp(label, r->lhs->name) == 0) + print("%1data->emit_reg(node, %P%s_NT);\n", label); + else + { + Tree node; + uint32_t path = find_label(r->pattern, label, 0, &node); + Nonterm nt = node->op; + + if (path == PATH_MISSING) + label_not_found(r, label); + + if (nt->is_fragment) + print("%1data->emit_fragment("); + else + print("%1data->emit_reg("); + + print_path(path); + print(", %P%s_NT);\n", ((Nonterm)node->op)->name); + } + break; + } + + case '$': + { + const char* label = f->data + 1; + uint32_t path = find_label(r->pattern, label, 0, NULL); + print("%1data->emit_value("); + if (path == PATH_MISSING) + label_not_found(r, label); + print_path(path); + print(");\n"); + break; + } + + case '\n': + assert(f->data[1] == 0); + print("%1data->emit_eoi();\n"); + break; + + default: + print("%1data->emit_string(\"%s\");\n", f->data); + } + + f = f->next; + } + + print("}\n\n"); r = r->link; } @@ -1051,11 +1105,7 @@ static void emitinsndata(Rule rules) print("%2\"%R\",\n", r); - print("%2"); - if (r->code.first) - print("&%Pemitter_%d,\n", r->ern); - else - print("NULL,\n"); + print("%2&%Pemitter_%d,\n", r->ern); if (r->lhs->allocate) print("%2%d,\n", r->lhs->allocate->number); diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index a2f20b4b4..1d806852b 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -12,7 +12,6 @@ ((size) == 0) ? 0 : \ (size-1))) - #define STATE_TYPE void* typedef struct ir* NODEPTR_TYPE; @@ -30,9 +29,8 @@ struct burm_emitter_data void (*emit_fragment)(struct ir* ir, int goal); void (*emit_reg)(struct ir* ir, int goal); void (*emit_value)(struct ir* ir); - void (*emit_resultreg)(void); void (*emit_eoi)(void); - void (*emit_usereg)(struct ir* ir); + void (*emit_constraint_equals)(struct ir* rightir, int rightgoal); }; typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data); From 68f98cbad7e10d642bc7557276474c7987a9e98c Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 3 Oct 2016 20:52:36 +0200 Subject: [PATCH 061/230] Instruction selection now happens on a shadow tree, rather than on the IR tree itself. Currently it's semantically the same but the implementation is cleaner. --- mach/proto/mcg/ir.h | 3 - mach/proto/mcg/mcgg_generated_header.h | 17 +---- mach/proto/mcg/pass_instructionselection.c | 82 +++++++++++++--------- mach/proto/mcg/pass_ssa.c | 2 + mach/proto/mcg/table | 4 +- util/mcgg/ir.dat | 6 +- util/mcgg/mcgg.h | 31 +++++--- 7 files changed, 79 insertions(+), 66 deletions(-) diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index ce90fcbde..52c5dc7d2 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -20,9 +20,6 @@ struct ir ARRAYOF(struct ir) phivalue; } u; - void* state_label; /* used by the iburg instruction selector */ - int insn_no; /* the table rule number for this instruction */ - int goal_no; /* the semantic type of this instruction; not stmt */ IMAPOF(struct hop) hops; /* only for root IRs; by goal */ }; diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index eead127f1..f190a9867 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -4,22 +4,7 @@ #define PANIC printf -#define OP_LABEL(p) burm_calculate_label(p) -#define LEFT_CHILD(p) ((p)->left) -#define RIGHT_CHILD(p) ((p)->right) - #define burm_assert(b, s) assert(b) -extern int burm_calculate_label(struct ir* ir); -extern void burm_panic_cannot_match(struct ir* ir); - -static bool burm_predicate_int(struct ir* ir) -{ - return ir->goal_no == 3; -} - -static bool burm_predicate_float(struct ir* ir) -{ - return ir->goal_no == 5; -} +extern void burm_panic_cannot_match(NODEPTR_TYPE node); diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index a1f80a855..5c92aae02 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -6,28 +6,21 @@ static struct ir* current_ir; static const struct burm_emitter_data emitter_data; -void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) { +void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) { const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; //tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p, // insndata->name, cost, bestcost); } -void burm_panic_cannot_match(struct ir* ir) +void burm_panic_cannot_match(struct burm_node* node) { fprintf(stderr, "could not find any patterns to match:\n"); - ir_print(0, ir); + ir_print(0, node->ir); fprintf(stderr, "aborting!\n"); exit(1); } -int burm_calculate_label(struct ir* ir) -{ - if (ir->root != current_ir) - return ir_to_esn(IR_REG, ir->size); - return ir_to_esn(ir->opcode, ir->size); -} - -static void emit_reg(struct ir* ir, int goal) +static void emit_reg(struct burm_node* node, int goal) { struct hop* hop = imap_get(¤t_ir->hops, goal); @@ -39,17 +32,17 @@ static void emit_string(const char* data) hop_add_string_insel(current_hop, data); } -static void emit_fragment(struct ir* ir, int goal) +static void emit_fragment(struct burm_node* node, int goal) { - int insn_no = burm_rule(ir->state_label, goal); + int insn_no = burm_rule(node->state_label, goal); const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; if (insndata->emitter) - insndata->emitter(ir, &emitter_data); + insndata->emitter(node, &emitter_data); } -static void emit_value(struct ir* ir) +static void emit_value(struct burm_node* node) { - hop_add_value_insel(current_hop, ir); + hop_add_value_insel(current_hop, node->ir); } static void emit_eoi(void) @@ -57,15 +50,17 @@ static void emit_eoi(void) hop_add_eoi_insel(current_hop); } -static void emit_constraint_equals(struct ir* ir, int goal) +static void emit_constraint_equals(struct burm_node* node, int goal) { +#if 0 struct hop* hop; if (!goal) - goal = 2; + goal = ir->goal_no; hop = imap_get(¤t_ir->hops, goal); current_hop->output = hop->output; +#endif } static const struct burm_emitter_data emitter_data = @@ -79,13 +74,14 @@ static const struct burm_emitter_data emitter_data = }; -static void walk_instructions(struct ir* ir, int goal) +static void walk_instructions(struct burm_node* node, int goal) { - struct ir* children[10]; - int insn_no = burm_rule(ir->state_label, goal); + struct burm_node* children[10]; + int insn_no = burm_rule(node->state_label, goal); const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; const short* nts = burm_nts[insn_no]; struct hop* parent_hop = NULL; + struct ir* ir = node->ir; int i; if (!insndata->is_fragment) @@ -99,17 +95,13 @@ static void walk_instructions(struct ir* ir, int goal) } } - burm_kids(ir, insn_no, children); + burm_kids(node, insn_no, children); for (i=0; nts[i]; i++) walk_instructions(children[i], nts[i]); - ir->insn_no = insn_no; - if (goal != 1) - ir->goal_no = goal; - tracef('I', "I: $%d goal %d selected %s %d: %s\n", ir->id, - ir->goal_no, + goal, insndata->is_fragment ? "fragment" : "instruction", insn_no, insndata->name); @@ -119,7 +111,7 @@ static void walk_instructions(struct ir* ir, int goal) /* This may cause the vregs to be reassigned for this instruction (and * fragments contained within it). */ - insndata->emitter(ir, &emitter_data); + insndata->emitter(node, &emitter_data); hop_print('I', current_hop); array_append(&ir->hops, current_hop); @@ -127,6 +119,27 @@ static void walk_instructions(struct ir* ir, int goal) } } +static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir) +{ + struct burm_node* node = calloc(1, sizeof(*node)); + node->ir = ir; + + if (ir->root == root) + { + node->label = ir_to_esn(ir->opcode, ir->size); + + if (ir->left) + node->left = build_shadow_tree(root, ir->left); + + if (ir->right) + node->right = build_shadow_tree(root, ir->right); + } + else + node->label = ir_to_esn(IR_REG, 0); + + return node; +} + static void select_instructions(void) { int i; @@ -135,16 +148,19 @@ static void select_instructions(void) for (i=0; iirs.count; i++) { + struct burm_node* shadow; int insnno; - current_ir = current_bb->irs.item[i]; - burm_label(current_ir); - insnno = burm_rule(current_ir->state_label, 1); + current_ir = current_bb->irs.item[i]; + shadow = build_shadow_tree(current_ir, current_ir); + burm_label(shadow); + + insnno = burm_rule(shadow->state_label, 1); if (!insnno) - burm_panic_cannot_match(current_ir); + burm_panic_cannot_match(shadow); ir_print('I', current_ir); - walk_instructions(current_ir, 1); + walk_instructions(shadow, 1); } } diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 87a0b973e..265ade1f5 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -174,6 +174,7 @@ static bool rewrite_loads_cb(struct ir* ir, void* user) if (is_local(ir)) { ir->opcode = IR_NOP; + ir->size = 0; ir->left = definition; ir->right = NULL; } @@ -214,6 +215,7 @@ static void recursively_rewrite_tree(struct basicblock* bb) if (ir->opcode == IR_STORE) { ir->opcode = IR_NOP; + ir->size = 0; ir->left = ir->right; ir->right = NULL; } diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 0db5f6a99..5f589d122 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -67,12 +67,12 @@ PATTERNS emit "add sp, sp, %delta" cost 4; - reg = in:REG4 + reg = in:REG with (reg == in) emit "reg %reg" cost 1; - reg = NOP4(in:reg) + reg = NOP(in:reg) with (reg == in) cost 1; diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index baa4617a6..50c2e44ed 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -5,14 +5,14 @@ # Simple terminals S CONST # must be followed by float form S CONSTF -S REG -S NOP +V REG +V NOP S LABEL S BLOCK V PAIR S ANY S LOCAL -S PHI +V PHI # Magic stack operations S PUSH diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 1d806852b..9180113a7 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -13,27 +13,40 @@ (size-1))) #define STATE_TYPE void* -typedef struct ir* NODEPTR_TYPE; #define STATE_LABEL(p) ((p)->state_label) +#define OP_LABEL(p) ((p)->label) +#define LEFT_CHILD(p) ((p)->left) +#define RIGHT_CHILD(p) ((p)->right) -extern void* burm_label(struct ir* ir); +struct burm_node +{ + int label; + void* state_label; + struct burm_node* left; + struct burm_node* right; + struct ir* ir; +}; + +typedef struct burm_node* NODEPTR_TYPE; + +extern void* burm_label(NODEPTR_TYPE node); extern int burm_rule(void* state, int goalnt); extern const short *burm_nts[]; -extern struct ir** burm_kids(struct ir* p, int eruleno, struct ir* kids[]); -extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost); +extern NODEPTR_TYPE* burm_kids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]); +extern void burm_trace(NODEPTR_TYPE p, int ruleno, int cost, int bestcost); struct burm_emitter_data { void (*emit_string)(const char* data); - void (*emit_fragment)(struct ir* ir, int goal); - void (*emit_reg)(struct ir* ir, int goal); - void (*emit_value)(struct ir* ir); + void (*emit_fragment)(NODEPTR_TYPE node, int goal); + void (*emit_reg)(NODEPTR_TYPE node, int goal); + void (*emit_value)(NODEPTR_TYPE node); void (*emit_eoi)(void); - void (*emit_constraint_equals)(struct ir* rightir, int rightgoal); + void (*emit_constraint_equals)(NODEPTR_TYPE node, int goal); }; -typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data); +typedef void burm_emitter_t(NODEPTR_TYPE node, const struct burm_emitter_data* data); struct burm_instruction_data { From bd28bddb92d81ae200a9dcb6162fcfe8c47c8bc8 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 00:16:06 +0200 Subject: [PATCH 062/230] Massive rewrite of how emitters and the instruction selector works, after I realised that the existing approach wasn't working. Now, hopefully, tracks the instruction trees generated during selection properly. --- mach/proto/mcg/ir.h | 1 + mach/proto/mcg/pass_instructionselection.c | 147 ++++++++++++--------- mach/proto/mcg/table | 26 +++- util/mcgg/gram.y | 25 ++-- util/mcgg/iburg.c | 126 +++++++----------- util/mcgg/mcgg.h | 10 +- 6 files changed, 175 insertions(+), 160 deletions(-) diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 52c5dc7d2..ea84e1ae3 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -20,6 +20,7 @@ struct ir ARRAYOF(struct ir) phivalue; } u; + struct vreg* result; /* vreg containing IR result */ IMAPOF(struct hop) hops; /* only for root IRs; by goal */ }; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 5c92aae02..20a93c697 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -1,10 +1,22 @@ #include "mcg.h" +#define MAX_CHILDREN 10 + +struct insn +{ + struct ir* ir; + struct hop* hop; + const struct burm_instruction_data* insndata; + int num_children; + struct insn* children[MAX_CHILDREN]; +}; + static struct basicblock* current_bb; static struct hop* current_hop; static struct ir* current_ir; +static struct insn* current_insn; -static const struct burm_emitter_data emitter_data; +static void emit(struct insn* insn); void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) { const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; @@ -20,11 +32,23 @@ void burm_panic_cannot_match(struct burm_node* node) exit(1); } -static void emit_reg(struct burm_node* node, int goal) +static void emit_return_reg(void) { - struct hop* hop = imap_get(¤t_ir->hops, goal); + hop_add_vreg_insel(current_hop, current_hop->output); +} - hop_add_vreg_insel(current_hop, hop->output); +static void emit_reg(int child) +{ + struct insn* insn = current_insn->children[child]; + struct vreg* vreg; + + if (insn->hop) + vreg = insn->hop->output; + else + vreg = insn->ir->result; + + if (vreg) + hop_add_vreg_insel(current_hop, vreg); } static void emit_string(const char* data) @@ -32,17 +56,14 @@ static void emit_string(const char* data) hop_add_string_insel(current_hop, data); } -static void emit_fragment(struct burm_node* node, int goal) +static void emit_fragment(int child) { - int insn_no = burm_rule(node->state_label, goal); - const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; - if (insndata->emitter) - insndata->emitter(node, &emitter_data); + emit(current_insn->children[child]); } -static void emit_value(struct burm_node* node) +static void emit_value(int child) { - hop_add_value_insel(current_hop, node->ir); + hop_add_value_insel(current_hop, current_insn->children[child]->ir); } static void emit_eoi(void) @@ -50,73 +71,75 @@ static void emit_eoi(void) hop_add_eoi_insel(current_hop); } -static void emit_constraint_equals(struct burm_node* node, int goal) -{ -#if 0 - struct hop* hop; - - if (!goal) - goal = ir->goal_no; - hop = imap_get(¤t_ir->hops, goal); - - current_hop->output = hop->output; -#endif -} - static const struct burm_emitter_data emitter_data = { &emit_string, &emit_fragment, + &emit_return_reg, &emit_reg, &emit_value, &emit_eoi, - &emit_constraint_equals }; - -static void walk_instructions(struct burm_node* node, int goal) +static void emit(struct insn* insn) { - struct burm_node* children[10]; - int insn_no = burm_rule(node->state_label, goal); - const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; - const short* nts = burm_nts[insn_no]; - struct hop* parent_hop = NULL; - struct ir* ir = node->ir; + struct insn* old = current_insn; + current_insn = insn; + + insn->insndata->emitter(&emitter_data); + + current_insn = old; +} + +static struct insn* walk_instructions(struct burm_node* node, int goal) +{ + struct insn* insn = calloc(1, sizeof(*insn)); int i; - - if (!insndata->is_fragment) + + insn->ir = node->ir; + insn->num_children = 0; + + if (goal) { - parent_hop = current_hop; - current_hop = new_hop(insn_no, ir); - if (goal != 1) + int insn_no = burm_rule(node->state_label, goal); + const short* nts = burm_nts[insn_no]; + struct burm_node* children[MAX_CHILDREN] = {0}; + + insn->insndata = &burm_instruction_data[insn_no]; + + burm_kids(node, insn_no, children); + + i = 0; + for (;;) { - current_hop->output = new_vreg(); - imap_add(¤t_ir->hops, goal, current_hop); + if (!children[i]) + break; + + insn->children[i] = walk_instructions(children[i], nts[i]); + insn->num_children++; + i++; + } + + tracef('I', "I: $%d goal %d %s selected %d: %s\n", + node->ir->id, + goal, + insn->insndata->is_fragment ? "fragment" : "instruction", + insn_no, + insn->insndata->name); + + if (!insn->insndata->is_fragment) + { + insn->hop = current_hop = new_hop(0, insn->ir); + insn->hop->output = new_vreg(); + emit(insn); + hop_print('I', current_hop); + + if (goal != 1) + insn->ir->result = insn->hop->output; } } - burm_kids(node, insn_no, children); - for (i=0; nts[i]; i++) - walk_instructions(children[i], nts[i]); - - tracef('I', "I: $%d goal %d selected %s %d: %s\n", - ir->id, - goal, - insndata->is_fragment ? "fragment" : "instruction", - insn_no, - insndata->name); - - if (!insndata->is_fragment) - { - /* This may cause the vregs to be reassigned for this instruction (and - * fragments contained within it). */ - - insndata->emitter(node, &emitter_data); - - hop_print('I', current_hop); - array_append(&ir->hops, current_hop); - current_hop = parent_hop; - } + return insn; } static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 5f589d122..0fa07b6bc 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -52,6 +52,7 @@ PATTERNS cost 4; reg = POP4 + with int reg emit "pop %reg" cost 4; @@ -68,12 +69,11 @@ PATTERNS cost 4; reg = in:REG - with (reg == in) - emit "reg %reg" + emit "mov %reg, %in" cost 1; reg = NOP(in:reg) - with (reg == in) + emit "mov %reg, %in" cost 1; @@ -90,18 +90,22 @@ PATTERNS cost 4; reg = LOAD4(addr:address) + with int reg emit "ldr %reg, %addr" cost 4; reg = LOAD1(addr:address) + with int reg emit "ldrb %reg, %addr" cost 4; reg = CIU14(LOAD1(addr:address)) + with int reg emit "ldrb %reg, %addr" cost 4; reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) + with int reg emit "ldrsb %reg, %addr" cost 4; @@ -109,6 +113,7 @@ PATTERNS /* Locals */ reg = in:LOCAL4 + with int reg emit "add %reg, fp, #$in" cost 4; @@ -161,14 +166,17 @@ PATTERNS /* Comparisons */ cc = COMPARES4(left:reg, right:aluparam) + with cc cc emit "cmp %left, %right" cost 4; cc = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4) + with cc cc emit "cmp %left, %right" cost 4; reg = cc + with int reg emit "mov %reg, #0" emit "movlt %reg, #-1" emit "movgt %reg, #1" @@ -178,10 +186,12 @@ PATTERNS /* Conversions */ reg = CII14(CIU41(value:reg)) + with int reg emit "sxtb %reg, %value" cost 4; reg = CIU41(in:reg) + with int reg emit "and %reg, %in, #0xff" cost 4; @@ -189,19 +199,23 @@ PATTERNS /* ALU operations */ reg = ADD4(left:reg, right:aluparam) + with int reg emit "add %reg, %left, %right" cost 4; reg = ADD4(left:aluparam, right:reg) + with int reg emit "add %reg, %right, %left" cost 4; reg = MOD4(left:reg, right:reg) + with int reg emit "udiv %reg, %left, %right" emit "mls %reg, %reg, %right, %left" cost 8; reg = DIV4(left:reg, right:aluparam) + with int reg emit "div %reg, %left, %right" cost 4; @@ -212,28 +226,34 @@ PATTERNS emit "%value"; reg = value:aluparam + with int reg emit "mov %reg, %value" cost 4; reg = value:LABEL4 + with int reg emit "adr %reg, $value" cost 4; reg = value:BLOCK4 + with int reg emit "adr %reg, $value" cost 4; reg = value:CONST4 + with int reg emit "ldr %reg, address-containing-$value" cost 8; reg = value:CONSTF4 + with int reg emit "vldr %reg, address-containing-$value" cost 8; /* FPU operations */ reg = ADDF4(left:reg, right:reg) + with int reg emit "fadds %reg, %left, %right" cost 4; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 9927d1598..5dc23a8be 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -28,6 +28,7 @@ static int nextern = 1; } %term ALLOCATES +%term COPY %term COST %term DECLARATIONS %term EMIT @@ -105,24 +106,24 @@ patterns ; pattern - : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } - | rhs { $$ = rule("stmt", $1, nextern++); } - | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } - | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); } - | pattern COST INT { $$ = $1; $$->cost = $3; } - | pattern_constraints { $$ = $1; } - | pattern_emit { $$ = $1; } + : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } + | rhs { $$ = rule("stmt", $1, nextern++); } + | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } + | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); } + | pattern COST INT { $$ = $1; $$->cost = $3; } + | pattern_constraints { $$ = $1; } + | pattern_emit { $$ = $1; } ; rhs - : terminfo { $$ = tree(&$1, NULL, NULL); } - | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); } - | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); } + : terminfo { $$ = tree(&$1, NULL, NULL); } + | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); } + | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); } ; terminfo - : ID { $$.name = $1; } - | ID ':' ID { $$.label = $1; $$.name = $3; } + : ID { $$.name = $1; } + | ID ':' ID { $$.label = $1; $$.name = $3; } ; pattern_emit diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 937a0df8e..af3106a8c 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -679,20 +679,22 @@ static void emitheader(void) } /* computekids - compute paths to kids in tree t */ -static char* computekids(Tree t, const char* v, char* bp, int* ip) +static char* computekids(Tree node, const char* v, char* bp, int* ip) { - Term p = t->op; + Term t = node->op; - if (p->kind == NONTERM) + if (!node->left && !node->right) { sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v); bp += strlen(bp); } - else if (p->arity > 0) + + if (t->kind == TERM) { - bp = computekids(t->left, aprintf("LEFT_CHILD(%s)", v), bp, ip); - if (p->arity == 2) - bp = computekids(t->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip); + if (t->arity >= 1) + bp = computekids(node->left, aprintf("LEFT_CHILD(%s)", v), bp, ip); + if (t->arity == 2) + bp = computekids(node->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip); } return bp; } @@ -910,6 +912,27 @@ static void label_not_found(Rule rule, const char* label) exit(1); } +static bool find_child_index(Tree node, const char* name, int* index, Tree* found) +{ + /* This must return the same ordering as the burm_kids() function uses. */ + + if (node->label && strcmp(node->label, name) == 0) + { + if (found) + *found = node; + return true; + } + + if (!node->left && !node->right) + (*index)++; + + if (node->left && find_child_index(node->left, name, index, found)) + return true; + if (node->right && find_child_index(node->right, name, index, found)) + return true; + return false; +} + /* emitpredicates - emit predicates for rules */ static void emitpredicatedefinitions(Rule r) { @@ -954,49 +977,6 @@ static void emitpredicatedefinitions(Rule r) } } -static void invalid_equals_constraint(Rule rule) -{ - yylineno = rule->lineno; - yyerror("left hand side of an equality constraint must be the output register"); - exit(1); -} - -static void emit_ir_expr(Rule rule, const char* label) -{ - if (strcmp(label, rule->lhs->name) == 0) - print("node, %P%s_NT", label); - else - { - Tree node; - uint32_t path = find_label(rule->pattern, label, 0, &node); - Nonterm nt = node->op; - - if (path == PATH_MISSING) - label_not_found(rule, label); - - print_path(path); - if (nt->kind == NONTERM) - print(", %P%s_NT", ((Nonterm)node->op)->name); - else - print(", 0"); - } -} - -static void emit_constraint(Rule rule, struct constraint* c) -{ - switch (c->type) - { - case CONSTRAINT_EQUALS: - if (strcmp(c->left, rule->lhs->name) != 0) - invalid_equals_constraint(rule); - - print("%1data->emit_constraint_equals("); - emit_ir_expr(rule, c->right); - print(");\n"); - break; - } -} - /* emitinsndata - emit the code generation data */ static void emitinsndata(Rule rules) { @@ -1007,6 +987,7 @@ static void emitinsndata(Rule rules) while (r) { struct stringfragment* f = r->code.first; + yylineno = r->lineno; if (!f) { @@ -1019,20 +1000,7 @@ static void emitinsndata(Rule rules) } print("/* %R */\n", r); - print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern); - - /* Constraints come first, because they may cause vreg reassignment, which - * we want to happen before the instruction emission. */ - - { - int i; - - for (i=0; iconstraints.count; i++) - { - struct constraint* c = r->constraints.item[i]; - emit_constraint(r, c); - } - } + print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern); while (f) { @@ -1043,23 +1011,26 @@ static void emitinsndata(Rule rules) const char* label = f->data + 1; if (strcmp(label, r->lhs->name) == 0) - print("%1data->emit_reg(node, %P%s_NT);\n", label); + print("%1data->emit_return_reg();\n", label); else { Tree node; - uint32_t path = find_label(r->pattern, label, 0, &node); + int index = 0; + if (!find_child_index(r->pattern, label, &index, &node)) + label_not_found(r, label); Nonterm nt = node->op; - if (path == PATH_MISSING) - label_not_found(r, label); - - if (nt->is_fragment) - print("%1data->emit_fragment("); + if (nt->kind == NONTERM) + { + if (nt->is_fragment) + print("%1data->emit_fragment("); + else + print("%1data->emit_reg("); + } else print("%1data->emit_reg("); - print_path(path); - print(", %P%s_NT);\n", ((Nonterm)node->op)->name); + print("%d);\n", index); } break; } @@ -1067,12 +1038,11 @@ static void emitinsndata(Rule rules) case '$': { const char* label = f->data + 1; - uint32_t path = find_label(r->pattern, label, 0, NULL); - print("%1data->emit_value("); - if (path == PATH_MISSING) + int index = 0; + if (!find_child_index(r->pattern, label, &index, NULL)) label_not_found(r, label); - print_path(path); - print(");\n"); + + print("%1data->emit_value(%d);\n", index); break; } diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 9180113a7..a3ff0197b 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -39,14 +39,14 @@ extern void burm_trace(NODEPTR_TYPE p, int ruleno, int cost, int bestcost); struct burm_emitter_data { void (*emit_string)(const char* data); - void (*emit_fragment)(NODEPTR_TYPE node, int goal); - void (*emit_reg)(NODEPTR_TYPE node, int goal); - void (*emit_value)(NODEPTR_TYPE node); + void (*emit_fragment)(int child); + void (*emit_return_reg)(void); + void (*emit_reg)(int child); + void (*emit_value)(int child); void (*emit_eoi)(void); - void (*emit_constraint_equals)(NODEPTR_TYPE node, int goal); }; -typedef void burm_emitter_t(NODEPTR_TYPE node, const struct burm_emitter_data* data); +typedef void burm_emitter_t(const struct burm_emitter_data* data); struct burm_instruction_data { From e13ff5be315820ac593656788f6b1060ba1032fc Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 21:29:03 +0200 Subject: [PATCH 063/230] Don't allocate new vregs for REG and NOP --- a bit hacky, but suppresses stray movs very effectively. --- mach/proto/mcg/pass_instructionselection.c | 18 +++++++++++++++++- mach/proto/mcg/table | 2 -- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 20a93c697..48ede30df 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -129,8 +129,24 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) if (!insn->insndata->is_fragment) { + struct vreg* vreg = NULL; + + switch (node->label) + { + case ir_to_esn(IR_REG, 0): + vreg = node->ir->result; + break; + + case ir_to_esn(IR_NOP, 0): + vreg = node->left->ir->result; + break; + + default: + vreg = new_vreg(); + } + insn->hop = current_hop = new_hop(0, insn->ir); - insn->hop->output = new_vreg(); + insn->hop->output = vreg; emit(insn); hop_print('I', current_hop); diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 0fa07b6bc..4d892c069 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -69,11 +69,9 @@ PATTERNS cost 4; reg = in:REG - emit "mov %reg, %in" cost 1; reg = NOP(in:reg) - emit "mov %reg, %in" cost 1; From 8d4186130d6078c04f7b6bf0a399eb21fa76c7f1 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 21:32:28 +0200 Subject: [PATCH 064/230] Oops --- hadn't updated the nts array for the new child order. --- util/mcgg/iburg.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index af3106a8c..3eb703bcf 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -779,9 +779,12 @@ static char* computents(Tree t, char* bp) if (t) { Nonterm p = t->op; - if (p->kind == NONTERM) + if (!t->left && !t->right) { - sprintf(bp, "%s_%s_NT, ", prefix, p->name); + if (p->kind == NONTERM) + sprintf(bp, "%s_%s_NT, ", prefix, p->name); + else + sprintf(bp, "0, "); bp += strlen(bp); } else From c6f576f758246e6bfa9df873fe1fc7f05d9fc1e5 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 21:58:31 +0200 Subject: [PATCH 065/230] Bodge in enough phi support to let the instruction generator complete on basic programs. --- mach/proto/mcg/basicblock.h | 2 ++ mach/proto/mcg/pass_instructionselection.c | 29 ++++++++++++++++------ mach/proto/mcg/table | 1 + 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h index 8f36e5eee..7fb654a6d 100644 --- a/mach/proto/mcg/basicblock.h +++ b/mach/proto/mcg/basicblock.h @@ -12,6 +12,8 @@ struct basicblock ARRAYOF(struct basicblock) nexts; int order; /* used by SSA code */ + ARRAYOF(struct vreg) liveins; + bool is_fake : 1; bool is_root : 1; bool is_terminated : 1; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 48ede30df..5f965c9bc 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -191,15 +191,30 @@ static void select_instructions(void) int insnno; current_ir = current_bb->irs.item[i]; - shadow = build_shadow_tree(current_ir, current_ir); - burm_label(shadow); - insnno = burm_rule(shadow->state_label, 1); - if (!insnno) - burm_panic_cannot_match(shadow); + if (current_ir->opcode == IR_PHI) + { + int j; - ir_print('I', current_ir); - walk_instructions(shadow, 1); + current_ir->result = new_vreg(); + array_append(¤t_bb->liveins, current_ir->result); + tracef('I', "I: %d is phi:", current_ir->result->id); + for (j=0; ju.phivalue.count; j++) + tracef('I', " $%d", current_ir->u.phivalue.item[j]->id); + tracef('I', "\n"); + } + else + { + shadow = build_shadow_tree(current_ir, current_ir); + burm_label(shadow); + + insnno = burm_rule(shadow->state_label, 1); + if (!insnno) + burm_panic_cannot_match(shadow); + + ir_print('I', current_ir); + walk_instructions(shadow, 1); + } } } diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 4d892c069..c333a6310 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -62,6 +62,7 @@ PATTERNS SETRET4(in:reg) with ret reg + emit "mov r0, %in" cost 4; STACKADJUST4(delta:aluparam) From ac063a6f5404a4a35176c6d97b809b36d4f0f26f Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 22:35:08 +0200 Subject: [PATCH 066/230] Remove unused variable (reduce memory usage by 1/10). --- mach/proto/mcg/ir.h | 1 - 1 file changed, 1 deletion(-) diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index ea84e1ae3..a7920b512 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -21,7 +21,6 @@ struct ir } u; struct vreg* result; /* vreg containing IR result */ - IMAPOF(struct hop) hops; /* only for root IRs; by goal */ }; extern const char* ir_names[]; From 249855ed235b8bacbe6798ee49cde9acca62be99 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 22:36:01 +0200 Subject: [PATCH 067/230] Fix the horror of the startup code; now uses getopt and stuff and the debug flags can be set as an option. --- mach/proto/mcg/main.c | 48 +++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index bf722f4f9..eca8a14ec 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -1,22 +1,14 @@ #include "mcg.h" +#include + +static const char* tracechars = NULL; bool tracing(char k) { - switch (k) - { - case 0: return true; - case 'S': return true; - case 'E': return false; - case 'G': return true; - case '0': return false; - case '1': return false; - case '2': return false; - case '3': return false; - case '4': return false; - case '5': return false; - case 'I': return true; - default: return true; - } + if (!tracechars) + return false; + + return index(tracechars, k); } void tracef(char k, const char* fmt, ...) @@ -38,12 +30,32 @@ static bool find_procedures_cb(struct symbol* symbol, void* user) return false; } -int main(int argc, char* argv[]) +int main(int argc, char* const argv[]) { + program_name = argv[0]; + + opterr = 1; + for (;;) + { + int c = getopt(argc, argv, "-d:"); + if (c == -1) + break; + + switch (c) + { + case 'd': + tracechars = optarg; + break; + + case 1: + fatal("unexpected argument '%s'", optarg); + } + } + symbol_init(); - if (!EM_open(argv[1])) - fatal("Couldn't open input file: %s", EM_error); + if (!EM_open(NULL)) + fatal("couldn't open stdin: %s", EM_error); /* Reads in the EM, outputs the data sections, parses any code and * generates IR trees. */ From 8fedf5a0a8a777ae9b1ddba9d357da9b19d5ef04 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 23:28:16 +0200 Subject: [PATCH 068/230] Added support for the op_bXX conditional branch instructions. --- mach/proto/mcg/parse_em.c | 6 ++++++ mach/proto/mcg/treebuilder.c | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 12ea25589..167910ad4 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -158,6 +158,12 @@ static void queue_insn_ilabel(int opcode, int label) case op_zle: case op_zgt: case op_zge: + case op_beq: + case op_bne: + case op_blt: + case op_ble: + case op_bgt: + case op_bge: { struct basicblock* bb = bb_get(NULL); queue_insn_block(em.em_opcode, left, bb); diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index c99bb7edd..5e9ee1233 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -270,6 +270,14 @@ static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLT); break; case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLE); break; + case op_beq: simple_branch2(opcode, EM_wordsize, leftbb, rightbb, IR_CJUMPEQ); break; + case op_blt: simple_branch2(opcode, EM_wordsize, leftbb, rightbb, IR_CJUMPLT); break; + case op_ble: simple_branch2(opcode, EM_wordsize, leftbb, rightbb, IR_CJUMPLE); break; + + case op_bne: simple_branch2(opcode, EM_wordsize, rightbb, leftbb, IR_CJUMPEQ); break; + case op_bge: simple_branch2(opcode, EM_wordsize, rightbb, leftbb, IR_CJUMPLT); break; + case op_bgt: simple_branch2(opcode, EM_wordsize, rightbb, leftbb, IR_CJUMPLE); break; + case op_bra: { materialise_stack(); From ac62c34e1975c56055af20a1ee4d42455ece3bde Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 23:42:00 +0200 Subject: [PATCH 069/230] Add a pass to do critical edge splitting. --- mach/proto/mcg/mcg.h | 7 +- mach/proto/mcg/pass_splitcriticaledges.c | 91 ++++++++++++++++++++++++ mach/proto/mcg/procedure.c | 22 +++++- 3 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 mach/proto/mcg/pass_splitcriticaledges.c diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index a5fa1102c..dc70028c9 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -100,13 +100,14 @@ extern void tb_fileend(void); extern void tb_procedure(struct procedure* proc); extern void tb_regvar(struct procedure* proc, arith offset, int size, int type, int priority); +extern void pass_convert_locals_to_ssa(struct procedure* proc); extern void pass_convert_stack_ops(struct procedure* proc); -extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); +extern void pass_group_irs(struct procedure* proc); extern void pass_instruction_selector(struct procedure* proc); extern void pass_promote_float_ops(struct procedure* proc); -extern void pass_group_irs(struct procedure* proc); -extern void pass_convert_locals_to_ssa(struct procedure* proc); +extern void pass_remove_dead_blocks(struct procedure* proc); +extern void pass_split_critical_edges(struct procedure* proc); #endif diff --git a/mach/proto/mcg/pass_splitcriticaledges.c b/mach/proto/mcg/pass_splitcriticaledges.c new file mode 100644 index 000000000..a7fa63ee9 --- /dev/null +++ b/mach/proto/mcg/pass_splitcriticaledges.c @@ -0,0 +1,91 @@ +#include "mcg.h" + +/* Insert empty nodes at certain places in the basic block graph so that when + * we convert out of SSA form, we have somewhere to insert copies. This is + * necessary for correctness in certain circumstances. The best explanation of + * why I've found is here, starting at the bottom of page 23. + * + * Briggs, Preston, et al. + * "Practical improvements to the construction and destruction of static single assignment form." + * Software-Practice and experience 28.8 (1998): 859-882. + * + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.749 + */ + +static struct procedure* current_proc; + +struct rewrite_params +{ + struct basicblock* find; + struct basicblock* replace; +}; + +static bool find_replace_cb(struct ir* ir, void* user) +{ + struct rewrite_params* rwp = user; + + if ((ir->opcode == IR_BLOCK) && (ir->u.bvalue == rwp->find)) + ir->u.bvalue = rwp->replace; + + return false; +} + +static void split_edge(struct basicblock* source, struct basicblock* sink) +{ + int i; + struct rewrite_params rwp; + struct basicblock* bb = bb_get(NULL); + + array_append(&bb->irs, + new_ir1( + IR_JUMP, 0, + new_bbir(sink) + ) + ); + + rwp.find = sink; + rwp.replace = bb; + + for (i=0; iirs.count; i++) + ir_walk(source->irs.item[i], find_replace_cb, &rwp); + + array_remove(&source->nexts, sink); + array_append(&source->nexts, bb); + + array_append(&bb->prevs, source); + array_append(&bb->nexts, sink); + + array_remove(&sink->prevs, source); + array_append(&sink->prevs, bb); + + array_append(¤t_proc->blocks, bb); +} + +static void consider_edges_leading_to(struct basicblock* bb) +{ + if (bb->prevs.count > 1) + { + int i; + + for (i=0; iprevs.count; i++) + { + struct basicblock* prev = bb->prevs.item[i]; + if (prev->nexts.count > 1) + split_edge(prev, bb); + } + } +} + +void pass_split_critical_edges(struct procedure* proc) +{ + int i; + + current_proc = proc; + + for (i=0; iblocks.count; i++) + consider_edges_leading_to(proc->blocks.item[i]); +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 5ea0372b9..8fbccd5d6 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -15,7 +15,23 @@ static void print_blocks(char k, struct procedure* proc) bb->is_fake ? "FAKE " : "", bb->name); - for (int j=0; jirs.count; j++) + if (bb->prevs.count > 0) + { + tracef(k, "%c: FROM:", k); + for (j=0; jprevs.count; j++) + tracef(k, " %s", bb->prevs.item[j]->name); + tracef(k, "\n"); + } + + if (bb->nexts.count > 0) + { + tracef(k, "%c: TO:", k); + for (j=0; jnexts.count; j++) + tracef(k, " %s", bb->nexts.item[j]->name); + tracef(k, "\n"); + } + + for (j=0; jirs.count; j++) ir_print(k, bb->irs.item[j]); } } @@ -40,8 +56,10 @@ void procedure_compile(struct procedure* proc) print_blocks('3', proc); pass_convert_locals_to_ssa(proc); print_blocks('4', proc); - pass_promote_float_ops(proc); + pass_split_critical_edges(proc); print_blocks('5', proc); + pass_promote_float_ops(proc); + print_blocks('6', proc); pass_instruction_selector(proc); From 92502901a71b4f049731f7cd463fbcd3d7158bf2 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 5 Oct 2016 21:00:28 +0200 Subject: [PATCH 070/230] Better management of register data. Add struct hreg. --- mach/proto/mcg/mcg.h | 2 +- mach/proto/mcg/pass_splitcriticaledges.c | 1 - mach/proto/mcg/reg.c | 32 ++++++++++ mach/proto/mcg/reg.h | 26 ++++++++ mach/proto/mcg/table | 44 +++++++------- mach/proto/mcg/vreg.c | 10 --- mach/proto/mcg/vreg.h | 12 ---- util/mcgg/gram.y | 4 +- util/mcgg/iburg.c | 77 ++++++++++++++---------- util/mcgg/iburg.h | 10 +-- util/mcgg/mcgg.h | 10 ++- 11 files changed, 141 insertions(+), 87 deletions(-) create mode 100644 mach/proto/mcg/reg.c create mode 100644 mach/proto/mcg/reg.h delete mode 100644 mach/proto/mcg/vreg.c delete mode 100644 mach/proto/mcg/vreg.h diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index dc70028c9..07da36467 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -24,7 +24,7 @@ #include "ir.h" #include "mcgg.h" #include "hop.h" -#include "vreg.h" +#include "reg.h" #include "basicblock.h" #include "procedure.h" diff --git a/mach/proto/mcg/pass_splitcriticaledges.c b/mach/proto/mcg/pass_splitcriticaledges.c index a7fa63ee9..9237be750 100644 --- a/mach/proto/mcg/pass_splitcriticaledges.c +++ b/mach/proto/mcg/pass_splitcriticaledges.c @@ -88,4 +88,3 @@ void pass_split_critical_edges(struct procedure* proc) /* vim: set sw=4 ts=4 expandtab : */ - diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c new file mode 100644 index 000000000..c4cf71058 --- /dev/null +++ b/mach/proto/mcg/reg.c @@ -0,0 +1,32 @@ +#include "mcg.h" + +static int vreg_count = 1; + +struct vreg* new_vreg(void) +{ + struct vreg* vreg = calloc(1, sizeof *vreg); + vreg->id = vreg_count++; + return vreg; +} + +struct hreg* new_hreg(struct burm_register_data* brd) +{ + struct hreg* hreg = calloc(1, sizeof *hreg); + hreg->name = brd->name; + hreg->attrs = brd->attrs; + hreg->is_stacked = false; + return hreg; +} + +struct hreg* new_stacked_hreg(int offset, uint32_t attrs) +{ + struct hreg* hreg = calloc(1, sizeof *hreg); + hreg->name = aprintf("stacked_%d", offset); + hreg->attrs = attrs; + hreg->is_stacked = true; + hreg->offset = offset; + return hreg; +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h new file mode 100644 index 000000000..62bbb6900 --- /dev/null +++ b/mach/proto/mcg/reg.h @@ -0,0 +1,26 @@ +#ifndef REG_H +#define REG_H + +#define WITH_ATTR(a) (1<<(a)) + +struct hreg +{ + const char* name; + uint32_t attrs; + bool is_stacked; + int offset; +}; + +struct vreg +{ + int id; +}; + +extern struct vreg* new_vreg(void); + +extern struct hreg* new_hreg(struct burm_register_data* brd); +extern struct hreg* new_stacked_hreg(int offset, uint32_t attrs); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index c333a6310..8ff3b2416 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,28 +1,28 @@ REGISTERS - r0 any int ret; - r1 any int; - r2 any int; - r3 any int; - r4 any int; - r5 any int; - r6 any int; - r7 any int; - r8 any int; - r9 any int; - r10 any int; - r11 any int; + r0 bytes4 int ret; + r1 bytes4 int; + r2 bytes4 int; + r3 bytes4 int; + r4 bytes4 int; + r5 bytes4 int; + r6 bytes4 int; + r7 bytes4 int; + r8 bytes4 int; + r9 bytes4 int; + r10 bytes4 int; + r11 bytes4 int; - s0 any float; - s1 any float; - s2 any float; - s3 any float; - s4 any float; - s5 any float; - s6 any float; - s7 any float; - s8 any float; - s9 any float; + s0 bytes4 float; + s1 bytes4 float; + s2 bytes4 float; + s3 bytes4 float; + s4 bytes4 float; + s5 bytes4 float; + s6 bytes4 float; + s7 bytes4 float; + s8 bytes4 float; + s9 bytes4 float; cc cc; diff --git a/mach/proto/mcg/vreg.c b/mach/proto/mcg/vreg.c deleted file mode 100644 index 636475de7..000000000 --- a/mach/proto/mcg/vreg.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "mcg.h" - -static int vreg_count = 1; - -struct vreg* new_vreg(void) -{ - struct vreg* vreg = calloc(1, sizeof *vreg); - vreg->id = vreg_count++; - return vreg; -} diff --git a/mach/proto/mcg/vreg.h b/mach/proto/mcg/vreg.h deleted file mode 100644 index ef92fd224..000000000 --- a/mach/proto/mcg/vreg.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef VREG_H -#define VREG_H - -struct vreg -{ - int id; -}; - -extern struct vreg* new_vreg(void); - -#endif - diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 5dc23a8be..a7ba08d70 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -74,7 +74,7 @@ registers register : ID { $$ = makereg($1); } - | register ID { $$ = $1; addregclass($1, $2); } + | register ID { $$ = $1; addregattr($1, $2); } ; declarations @@ -95,7 +95,7 @@ allocates $$ = $1; if ($$->allocate) yyerror("pattern type is defined to already allocate a register"); - $$->allocate = getregclass($4); + $$->allocate = getregattr($4); } ; diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 3eb703bcf..b9ecd2cd2 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -29,11 +29,12 @@ static Rule rules; static int nrules; static SMAPOF(struct reg) registers; -static SMAPOF(struct regclass) registerclasses; +static SMAPOF(struct regattr) registerattrs; static void print(char* fmt, ...); static void ckreach(Nonterm p); static void registerterminals(void); +static struct regattr* makeregattr(const char* id); static void emitclosure(Nonterm nts); static void emitcost(Tree t, const char* v); static void emitcostcalc(Rule r); @@ -47,7 +48,7 @@ static void emitleaf(Term p, int ntnumber); static void emitnts(Rule rules, int nrules); static void emitpredicatedefinitions(Rule rules); static void emitrecord(char* pre, Rule r, int cost); -static void emitregisterclasses(); +static void emitregisterattrs(); static void emitregisters(); static void emitrule(Nonterm nts); static void emitstate(Term terms, Nonterm start, int ntnumber); @@ -125,6 +126,10 @@ int main(int argc, char* argv[]) registerterminals(); start = nonterm("stmt", true); + makeregattr("bytes1"); + makeregattr("bytes2"); + makeregattr("bytes4"); + makeregattr("bytes8"); yyin = infp; yyparse(); @@ -137,7 +142,7 @@ int main(int argc, char* argv[]) yyerror("can't reach non-terminal `%s'\n", p->name); #endif - emitregisterclasses(); + emitregisterattrs(); emitregisters(); emitdefs(nts, ntnumber); emitstruct(nts, ntnumber); @@ -194,7 +199,7 @@ struct entry struct term t; struct nonterm nt; struct reg r; - struct regclass rc; + struct regattr rc; } sym; struct entry* link; } * table[211]; @@ -236,7 +241,7 @@ static void* install(const char* name) struct reg* makereg(const char* id) { struct reg* p = smap_get(®isters, id); - static int number = 1; + static int number = 0; if (p) yyerror("redefinition of '%s'", id); @@ -248,25 +253,34 @@ struct reg* makereg(const char* id) return p; } -void addregclass(struct reg* reg, const char* id) +struct regattr* makeregattr(const char* id) { - struct regclass* p = smap_get(®isterclasses, id); - static int number = 1; + struct regattr* p = smap_get(®isterattrs, id); + static int number = 0; - if (!p) - { - p = calloc(1, sizeof(*p)); - p->name = id; - p->number = number++; - smap_put(®isterclasses, id, p); - } + if (p) + yyerror("redefinition of '%s'", id); + p = calloc(1, sizeof(*p)); + p->name = id; + p->number = number++; + smap_put(®isterattrs, id, p); - reg->classes |= 1<<(p->number); + return p; } -struct regclass* getregclass(const char* id) +void addregattr(struct reg* reg, const char* id) { - struct regclass* p = smap_get(®isterclasses, id); + struct regattr* p = smap_get(®isterattrs, id); + + if (!p) + p = makeregattr(id); + + reg->attrs |= 1<<(p->number); +} + +struct regattr* getregattr(const char* id) +{ + struct regattr* p = smap_get(®isterattrs, id); if (!p) yyerror("'%s' is not the name of a register class", id); return p; @@ -318,9 +332,6 @@ Term term(const char* id, int esn) p->name, p->esn); p->link = *q; *q = p; - - if (esn != -1) - print("enum { %s = %d };\n", id, esn); return p; } @@ -415,10 +426,6 @@ static void print(char* fmt, ...) fprintf(outfp, "%x", va_arg(ap, uint32_t)); break; - case 'X': - fprintf(outfp, "0x%" PRIx64 "ULL", va_arg(ap, uint64_t)); - break; - case 's': fputs(va_arg(ap, char*), outfp); break; @@ -499,16 +506,15 @@ static void ckreach(Nonterm p) reach(r->pattern); } -static void emitregisterclasses(void) +static void emitregisterattrs(void) { int i; print("const char* %Pregister_class_names[] = {\n"); - print("%1NULL,\n"); /* register class id 0 is invalid */ - for (i=0; inumber == (i+1)); + struct regattr* rc = registerattrs.item[i].right; + assert(rc->number == i); print("%1\"%s\",\n", rc->name); } @@ -520,14 +526,14 @@ static void emitregisters(void) int i; print("const struct %Pregister_data %Pregister_data[] = {\n"); - print("%1{ 0 },\n"); /* register id 0 is invalid */ for (i=0; inumber == (i+1)); + assert(r->number == i); - print("%1{ \"%s\", %X },\n", r->name, r->classes); + print("%1{ \"%s\", 0x%x },\n", r->name, r->attrs); } + print("%1{ NULL }\n"); print("};\n\n"); } @@ -1168,6 +1174,11 @@ static void emitterms(Term terms) Term p; int k; + print("enum {\n"); + for (k = 0, p = terms; p; p = p->link) + print("%1%S = %d,\n", p, p->esn); + print("};\n\n"); + print("static const char %Parity[] = {\n"); for (k = 0, p = terms; p; p = p->link) { diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 24700e5e4..60e51d7b4 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -47,18 +47,18 @@ struct reg { const char* name; /* register name */ int number; /* identifying number */ - uint64_t classes; // bitfield of classes */ + uint32_t attrs; /* bitfield of register attributes */ }; -struct regclass +struct regattr { const char* name; /* class name */ int number; /* identifying number */ }; extern struct reg* makereg(const char* name); -extern void addregclass(struct reg* reg, const char* regclass); -extern struct regclass* getregclass(const char* name); +extern void addregattr(struct reg* reg, const char* regattr); +extern struct regattr* getregattr(const char* name); struct term { /* terminals: */ @@ -82,7 +82,7 @@ struct nonterm Rule chain; /* chain rules w/non-terminal on rhs */ Nonterm link; /* next terminal in number order */ bool is_fragment; /* these instructions are all fragments */ - struct regclass* allocate; /* allocate this kind of register */ + struct regattr* allocate; /* allocate this kind of register */ }; extern void* lookup(const char* name); extern Nonterm nonterm(const char* id, bool allocate); diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index a3ff0197b..65dc26f54 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -61,12 +61,20 @@ extern const struct burm_instruction_data burm_instruction_data[]; struct burm_register_data { const char* name; - uint32_t classes; + uint32_t attrs; }; extern const struct burm_register_data burm_register_data[]; extern const char* burm_register_class_names[]; +enum +{ + REGATTR_BYTES1 = 0, + REGATTR_BYTES2, + REGATTR_BYTES4, + REGATTR_BYTES8 +}; + #endif /* vim: set sw=4 ts=4 expandtab : */ From 7a6fc7a72b26184d3aa8be43337807a2aa129ed9 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 5 Oct 2016 21:07:29 +0200 Subject: [PATCH 071/230] Made sure that all files end in vim magic. --- mach/proto/mcg/basicblock.h | 2 ++ mach/proto/mcg/hop.c | 2 ++ mach/proto/mcg/hop.h | 3 +++ mach/proto/mcg/ir.h | 1 + mach/proto/mcg/mcgg_generated_footer.h | 2 ++ mach/proto/mcg/mcgg_generated_header.h | 2 ++ mach/proto/mcg/registerallocator.c | 2 ++ mach/proto/mcg/symbol.c | 2 ++ mach/proto/mcg/table | 2 ++ 9 files changed, 18 insertions(+) create mode 100644 mach/proto/mcg/registerallocator.c diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h index 7fb654a6d..7935c9ede 100644 --- a/mach/proto/mcg/basicblock.h +++ b/mach/proto/mcg/basicblock.h @@ -25,3 +25,5 @@ extern void bb_alias(struct basicblock* block, const char* name); #endif +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index e4552e04e..a11b99792 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -106,3 +106,5 @@ void hop_print(char k, struct hop* hop) tracef(k, "\n", k); } +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 3e2f9d6e7..d802ed01a 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -28,6 +28,7 @@ struct hop struct ir* ir; ARRAYOF(struct insel) insels; struct vreg* output; + PMAPOF(struct vreg, struct hreg) registers; }; extern struct hop* new_hop(int insn_no, struct ir* ir); @@ -41,3 +42,5 @@ extern void hop_print(char k, struct hop* hop); #endif +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index a7920b512..a12b9642c 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -46,3 +46,4 @@ extern void ir_print(char k, const struct ir* ir); #endif +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/mcgg_generated_footer.h b/mach/proto/mcg/mcgg_generated_footer.h index 11b40205a..6de0c5277 100644 --- a/mach/proto/mcg/mcgg_generated_footer.h +++ b/mach/proto/mcg/mcgg_generated_footer.h @@ -51,3 +51,5 @@ int main(void) { } #endif +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index f190a9867..8ca4c4b34 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -8,3 +8,5 @@ extern void burm_panic_cannot_match(NODEPTR_TYPE node); +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/registerallocator.c b/mach/proto/mcg/registerallocator.c new file mode 100644 index 000000000..84db0ea7d --- /dev/null +++ b/mach/proto/mcg/registerallocator.c @@ -0,0 +1,2 @@ +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/symbol.c b/mach/proto/mcg/symbol.c index 6012b91f3..26e01e020 100644 --- a/mach/proto/mcg/symbol.c +++ b/mach/proto/mcg/symbol.c @@ -58,3 +58,5 @@ struct symbol* symbol_walk(symbol_walker_t* cb, void* user) return NULL; } +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 8ff3b2416..8ab4a4d51 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -256,3 +256,5 @@ PATTERNS emit "fadds %reg, %left, %right" cost 4; +/* vim: set sw=4 ts=4 expandtab : */ + From 88fb231d6e9c227a2a98fb54ec5ad021281498ff Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 5 Oct 2016 22:56:25 +0200 Subject: [PATCH 072/230] Better constraint syntax; mcgg now passes register usage information up to mcg; mcg can track individual hop inputs and outputs (needed for live range analysis!); the register allocator now puts the basic blocks into the right order in preparation for live range analysis. --- mach/proto/mcg/hop.c | 11 +- mach/proto/mcg/hop.h | 3 + mach/proto/mcg/mcg.h | 2 + mach/proto/mcg/pass_instructionselection.c | 31 ++++- mach/proto/mcg/procedure.c | 3 +- mach/proto/mcg/registerallocator.c | 32 +++++ mach/proto/mcg/table | 144 ++++++++------------- util/mcgg/gram.y | 19 +-- util/mcgg/iburg.c | 105 +++++++++++++-- util/mcgg/iburg.h | 9 +- util/mcgg/mcgg.h | 8 +- 11 files changed, 240 insertions(+), 127 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index a11b99792..352ad9b2b 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -50,7 +50,7 @@ void hop_add_eoi_insel(struct hop* hop) void hop_print(char k, struct hop* hop) { - int i; + int i, j; bool soi = true; i = 0; @@ -60,7 +60,14 @@ void hop_print(char k, struct hop* hop) if (soi) { - tracef(k, "%c: %d from $%d: ", k, hop->id, hop->ir->id); + tracef(k, "%c: %d from $%d:", k, hop->id, hop->ir->id); + + for (j=0; jins.count; j++) + tracef(k, " <%%%d", hop->ins.item[j]->id); + for (j=0; jouts.count; j++) + tracef(k, " >%%%d", hop->outs.item[j]->id); + tracef(k, " "); + soi = false; } diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index d802ed01a..66903cbfe 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -28,6 +28,9 @@ struct hop struct ir* ir; ARRAYOF(struct insel) insels; struct vreg* output; + + ARRAYOF(struct vreg) ins; + ARRAYOF(struct vreg) outs; PMAPOF(struct vreg, struct hreg) registers; }; diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 07da36467..601249f07 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -109,6 +109,8 @@ extern void pass_promote_float_ops(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_split_critical_edges(struct procedure* proc); +extern void register_allocator(struct procedure* proc); + #endif /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 5f965c9bc..ca7589e86 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -37,15 +37,19 @@ static void emit_return_reg(void) hop_add_vreg_insel(current_hop, current_hop->output); } -static void emit_reg(int child) +static struct vreg* find_vreg_of_child(int child) { struct insn* insn = current_insn->children[child]; - struct vreg* vreg; if (insn->hop) - vreg = insn->hop->output; + return insn->hop->output; else - vreg = insn->ir->result; + return insn->ir->result; +} + +static void emit_reg(int child) +{ + struct vreg* vreg = find_vreg_of_child(child); if (vreg) hop_add_vreg_insel(current_hop, vreg); @@ -71,6 +75,18 @@ static void emit_eoi(void) hop_add_eoi_insel(current_hop); } +static void constrain_input_reg(int child, int attr) +{ + struct vreg* vreg = find_vreg_of_child(child); + + if (vreg) + array_appendu(¤t_hop->ins, vreg); +} + +static void constrain_output_reg(int attr) +{ +} + static const struct burm_emitter_data emitter_data = { &emit_string, @@ -79,6 +95,8 @@ static const struct burm_emitter_data emitter_data = &emit_reg, &emit_value, &emit_eoi, + &constrain_input_reg, + &constrain_output_reg }; static void emit(struct insn* insn) @@ -142,11 +160,16 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) break; default: + /* FIXME: some instructions don't emit anything, so + * allocating a register for them is a waste of time. */ vreg = new_vreg(); } insn->hop = current_hop = new_hop(0, insn->ir); insn->hop->output = vreg; + if (vreg) + array_appendu(¤t_hop->outs, vreg); + emit(insn); hop_print('I', current_hop); diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 8fbccd5d6..8d0f83953 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -61,8 +61,9 @@ void procedure_compile(struct procedure* proc) pass_promote_float_ops(proc); print_blocks('6', proc); - pass_instruction_selector(proc); + + register_allocator(proc); } static bool collect_outputs_cb(struct ir* ir, void* user) diff --git a/mach/proto/mcg/registerallocator.c b/mach/proto/mcg/registerallocator.c index 84db0ea7d..eae72fac6 100644 --- a/mach/proto/mcg/registerallocator.c +++ b/mach/proto/mcg/registerallocator.c @@ -1,2 +1,34 @@ +#include "mcg.h" + +static ARRAYOF(struct basicblock) blocks; + +static void recursively_walk_blocks(struct basicblock* bb) +{ + int i; + + if (array_appendu(&blocks, bb)) + return; + tracef('R', "R: considering block %s\n", bb->name); + + for (i=0; inexts.count; i++) + recursively_walk_blocks(bb->nexts.item[i]); +} + +static void order_blocks(struct procedure* proc) +{ + /* Put them into preorder; this ensures that when we do the allocation, + * we do all of a block's predecessors before the block (except for + * backward edges). */ + + blocks.count = 0; + recursively_walk_blocks(proc->blocks.item[0]); + assert(blocks.count == proc->blocks.count); +} + +void register_allocator(struct procedure* proc) +{ + order_blocks(proc); +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 8ab4a4d51..f3f359f4b 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -29,7 +29,6 @@ REGISTERS DECLARATIONS - reg; cc; address fragment; @@ -40,28 +39,24 @@ PATTERNS /* Special */ - reg; - PAIR(BLOCK4, BLOCK4); /* Miscellaneous special things */ - PUSH4(in:reg) + PUSH4(in:(int)reg) emit "push %in" cost 4; - reg = POP4 - with int reg - emit "pop %reg" + out:(int)reg = POP4 + emit "pop %out" cost 4; RET emit "ret" cost 4; - SETRET4(in:reg) - with ret reg + SETRET4(in:(ret)reg) emit "mov r0, %in" cost 4; @@ -69,51 +64,38 @@ PATTERNS emit "add sp, sp, %delta" cost 4; - reg = in:REG - cost 1; - - reg = NOP(in:reg) - cost 1; - /* Memory operations */ - STORE4(addr:address, value:reg) - with int value + STORE4(addr:address, value:(int)reg) emit "str %value, %addr" cost 4; - STORE1(addr:address, value:reg) - with int value + STORE1(addr:address, value:(int)reg) emit "strb %value, %addr" cost 4; - reg = LOAD4(addr:address) - with int reg - emit "ldr %reg, %addr" + out:(int)reg = LOAD4(addr:address) + emit "ldr %out, %addr" cost 4; - reg = LOAD1(addr:address) - with int reg - emit "ldrb %reg, %addr" + out:(int)reg = LOAD1(addr:address) + emit "ldrb %out, %addr" cost 4; - reg = CIU14(LOAD1(addr:address)) - with int reg - emit "ldrb %reg, %addr" + out:(int)reg = CIU14(LOAD1(addr:address)) + emit "ldrb %out, %addr" cost 4; - reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) - with int reg - emit "ldrsb %reg, %addr" + out:(int)reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) + emit "ldrsb %out, %addr" cost 4; /* Locals */ - reg = in:LOCAL4 - with int reg - emit "add %reg, fp, #$in" + out:(int)reg = in:LOCAL4 + emit "add %out, fp, #$in" cost 4; address = in:LOCAL4 @@ -122,16 +104,13 @@ PATTERNS /* Memory addressing modes */ - address = ADD4(addr:reg, offset:CONST4) - with int addr + address = ADD4(addr:(int)reg, offset:CONST4) emit "[%addr, #$offset]"; - address = ADD4(addr1:reg, addr2:reg) - with int addr1, int addr2 + address = ADD4(addr1:(int)reg, addr2:(int)reg) emit "[%addr1, %addr2]"; - address = addr:reg - with int addr + address = addr:(int)reg emit "[%addr]"; @@ -142,17 +121,17 @@ PATTERNS emit "b $addr" cost 4; - CJUMPEQ(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) + CJUMPEQ(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4)) emit "beq $true" emit "b $false" cost 8; - CJUMPLE(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) + CJUMPLE(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4)) emit "ble $true" emit "b $false" cost 8; - CJUMPLT(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) + CJUMPLT(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4)) emit "blt $true" emit "b $false" cost 8; @@ -164,96 +143,81 @@ PATTERNS /* Comparisons */ - cc = COMPARES4(left:reg, right:aluparam) - with cc cc + (cc)cc = COMPARES4(left:(int)reg, right:aluparam) emit "cmp %left, %right" cost 4; - cc = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4) - with cc cc + (cc)cc = COMPARES4(COMPARES4(left:(int)reg, right:aluparam), CONST4) emit "cmp %left, %right" cost 4; - reg = cc - with int reg - emit "mov %reg, #0" - emit "movlt %reg, #-1" - emit "movgt %reg, #1" + out:(int)reg = (cc)cc + emit "mov %out, #0" + emit "movlt %out, #-1" + emit "movgt %out, #1" cost 12; /* Conversions */ - reg = CII14(CIU41(value:reg)) - with int reg - emit "sxtb %reg, %value" + out:(int)reg = CII14(CIU41(value:(int)reg)) + emit "sxtb %out, %value" cost 4; - reg = CIU41(in:reg) - with int reg - emit "and %reg, %in, #0xff" + out:(int)reg = CIU41(in:(int)reg) + emit "and %out, %in, #0xff" cost 4; /* ALU operations */ - reg = ADD4(left:reg, right:aluparam) - with int reg - emit "add %reg, %left, %right" + out:(int)reg = ADD4(left:(int)reg, right:aluparam) + emit "add %out, %left, %right" cost 4; - reg = ADD4(left:aluparam, right:reg) - with int reg - emit "add %reg, %right, %left" + out:(int)reg = ADD4(left:aluparam, right:(int)reg) + emit "add %out, %right, %left" cost 4; - reg = MOD4(left:reg, right:reg) - with int reg - emit "udiv %reg, %left, %right" - emit "mls %reg, %reg, %right, %left" + out:(int)reg = MOD4(left:(int)reg, right:(int)reg) + emit "udiv %out, %left, %right" + emit "mls %out, %out, %right, %left" cost 8; - reg = DIV4(left:reg, right:aluparam) - with int reg - emit "div %reg, %left, %right" + out:(int)reg = DIV4(left:(int)reg, right:aluparam) + emit "div %out, %left, %right" cost 4; aluparam = value:CONST4 emit "#$value"; - aluparam = value:reg + aluparam = value:(int)reg emit "%value"; - reg = value:aluparam - with int reg - emit "mov %reg, %value" + out:(int)reg = value:aluparam + emit "mov %out, %value" cost 4; - reg = value:LABEL4 - with int reg - emit "adr %reg, $value" + out:(int)reg = value:LABEL4 + emit "adr %out, $value" cost 4; - reg = value:BLOCK4 - with int reg - emit "adr %reg, $value" + out:(int)reg = value:BLOCK4 + emit "adr %out, $value" cost 4; - reg = value:CONST4 - with int reg - emit "ldr %reg, address-containing-$value" + out:(int)reg = value:CONST4 + emit "ldr %out, address-containing-$value" cost 8; - reg = value:CONSTF4 - with int reg - emit "vldr %reg, address-containing-$value" + out:(int)reg = value:CONSTF4 + emit "vldr %out, address-containing-$value" cost 8; /* FPU operations */ - reg = ADDF4(left:reg, right:reg) - with int reg - emit "fadds %reg, %left, %right" + out:(float)reg = ADDF4(left:(float)reg, right:(float)reg) + emit "fadds %out, %left, %right" cost 4; /* vim: set sw=4 ts=4 expandtab : */ diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index a7ba08d70..fbd191052 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -11,8 +11,6 @@ extern int yylex(void); -static int nextern = 1; - %} %union { int n; @@ -86,17 +84,6 @@ declarations declaration : ID { $$ = nonterm($1, true); } | declaration FRAGMENT { $$ = $1; $$->is_fragment = true; } - | allocates { $$ = $1; } - ; - -allocates - : declaration ALLOCATES '(' ID ')' - { - $$ = $1; - if ($$->allocate) - yyerror("pattern type is defined to already allocate a register"); - $$->allocate = getregattr($4); - } ; patterns @@ -106,8 +93,8 @@ patterns ; pattern - : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } - | rhs { $$ = rule("stmt", $1, nextern++); } + : terminfo '=' rhs { nonterm($1.name, false); $$ = rule(&$1, $3); } + | rhs { $$ = rule(NULL, $1); } | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); } | pattern COST INT { $$ = $1; $$->cost = $3; } @@ -123,7 +110,9 @@ rhs terminfo : ID { $$.name = $1; } + | '(' ID ')' ID { $$.attr = $2; $$.name = $4; } | ID ':' ID { $$.label = $1; $$.name = $3; } + | ID ':' '(' ID ')' ID { $$.label = $1; $$.attr = $4; $$.name = $6; } ; pattern_emit diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index b9ecd2cd2..5683b6cc4 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -14,6 +14,7 @@ #include "ircodes.h" #include "astring.h" #include "smap.h" +#include "mcgg.h" static char rcsid[] = "$Id$"; @@ -131,6 +132,20 @@ int main(int argc, char* argv[]) makeregattr("bytes4"); makeregattr("bytes8"); + /* Define some standard terms. */ + + { + const static struct terminfo reg = { "reg", NULL, "" }; + const static struct terminfo REG = { "REG", NULL, NULL }; + const static struct terminfo NOP = { "NOP", NULL, NULL }; + + nonterm("reg", true); + + rule(NULL, tree(®, NULL, NULL))->cost = 1; + rule(®, tree(®, NULL, NULL))->cost = 1; + rule(®, tree(&NOP, tree(®, NULL, NULL), NULL))->cost = 1; + } + yyin = infp; yyparse(); @@ -336,7 +351,7 @@ Term term(const char* id, int esn) } /* tree - create & initialize a tree node with the given fields */ -Tree tree(struct terminfo* ti, Tree left, Tree right) +Tree tree(const struct terminfo* ti, Tree left, Tree right) { Tree t = calloc(1, sizeof *t); Term p = lookup(ti->name); @@ -363,31 +378,57 @@ Tree tree(struct terminfo* ti, Tree left, Tree right) if (p->kind == TERM && arity != p->arity) yyerror("inconsistent arity for terminal `%s'\n", ti->name); t->op = p; - t->label = ti->label; t->nterms = p->kind == TERM; if (t->left = left) t->nterms += left->nterms; if (t->right = right) t->nterms += right->nterms; + + /* Special rules that have no output register attribute use "" as the + * attribute name; these can't be made by the grammar. */ + + t->label = ti->label; + if ((p->kind == TERM) && (ti->attr)) + yyerror("can't specify an input register attribute for terminal '%s'", ti->name); + if (p->kind == NONTERM) + { + Nonterm nt = (Nonterm)p; + if (nt->is_fragment && ti->attr) + yyerror("can't specify an input register attribute for fragment '%s'", ti->name); + if (!nt->is_fragment && !ti->attr) + yyerror("must specify an input register attribute for non-fragment '%s'", ti->name); + + if (ti->attr && ti->attr[0]) + { + nt->attr = smap_get(®isterattrs, ti->attr); + if (!nt->attr) + yyerror("'%s' doesn't seem to be a known register attribute", ti->attr); + } + } return t; } /* rule - create & initialize a rule with the given fields */ -Rule rule(char* id, Tree pattern, int ern) +Rule rule(const struct terminfo* ti, Tree pattern) { + static int number = 1; + static const struct terminfo stmt = { "stmt", NULL, NULL }; Rule r = calloc(1, sizeof *r); Rule *q; Term p = pattern->op; + if (!ti) + ti = &stmt; + nrules++; r->lineno = yylineno; - r->lhs = nonterm(id, false); + r->lhs = nonterm(ti->name, false); r->packed = ++r->lhs->lhscount; for (q = &r->lhs->rules; *q; q = &(*q)->decode) ; *q = r; r->pattern = pattern; - r->ern = ern; + r->ern = number++; if (p->kind == TERM) { r->next = p->rules; @@ -405,6 +446,23 @@ Rule rule(char* id, Tree pattern, int ern) yyerror("duplicate external rule number `%d'\n", r->ern); r->link = *q; *q = r; + + r->label = ti->label; + if (r->lhs->is_fragment && ti->attr) + yyerror("can't specify an output register attribute for a fragment"); + if (!r->lhs->is_fragment && !ti->attr && (r->lhs->number != NONTERM_STMT)) + yyerror("must specify an output register attribute for non-fragments"); + + /* Special rules that have no output register attribute use "" as the + * attribute name; these can't be made by the grammar. */ + + if (ti->attr && ti->attr[0]) + { + r->attr = smap_get(®isterattrs, ti->attr); + if (!r->attr) + yyerror("'%s' doesn't seem to be a known register attribute", ti->attr); + } + return r; } @@ -986,6 +1044,28 @@ static void emitpredicatedefinitions(Rule r) } } +static void emit_input_regs(Tree node, int* index) +{ + /* This must return the same ordering as the burm_kids() function uses. */ + + Nonterm nt = node->op; + if ((nt->kind == NONTERM) && !nt->is_fragment && !node->left && !node->right) + { + uint32_t attr = 0; + if (nt->attr->number) + attr = 1<attr->number; + print("%1data->constrain_input_reg(%d, 0x%x);\n", *index, attr); + } + + if (!node->left && !node->right) + (*index)++; + + if (node->left) + emit_input_regs(node->left, index); + if (node->right) + emit_input_regs(node->right, index); +} + /* emitinsndata - emit the code generation data */ static void emitinsndata(Rule rules) { @@ -1011,6 +1091,14 @@ static void emitinsndata(Rule rules) print("/* %R */\n", r); print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern); + if (r->attr) + print("%1data->constrain_output_reg(0x%x);\n", 1<attr->number); + + { + int index = 0; + emit_input_regs(r->pattern, &index); + } + while (f) { switch (f->data[0]) @@ -1019,7 +1107,7 @@ static void emitinsndata(Rule rules) { const char* label = f->data + 1; - if (strcmp(label, r->lhs->name) == 0) + if (r->label && (strcmp(label, r->label) == 0)) print("%1data->emit_return_reg();\n", label); else { @@ -1086,11 +1174,6 @@ static void emitinsndata(Rule rules) print("%2&%Pemitter_%d,\n", r->ern); - if (r->lhs->allocate) - print("%2%d,\n", r->lhs->allocate->number); - else - print("%20,\n"); - print("%2%s,\n", r->lhs->is_fragment ? "true" : "false"); print("%1},\n"); diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 60e51d7b4..48981722b 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -41,6 +41,7 @@ struct terminfo { const char* name; const char* label; + const char* attr; }; struct reg @@ -82,7 +83,7 @@ struct nonterm Rule chain; /* chain rules w/non-terminal on rhs */ Nonterm link; /* next terminal in number order */ bool is_fragment; /* these instructions are all fragments */ - struct regattr* allocate; /* allocate this kind of register */ + struct regattr* attr; /* input register attribute */ }; extern void* lookup(const char* name); extern Nonterm nonterm(const char* id, bool allocate); @@ -96,7 +97,7 @@ struct tree Tree left, right; /* operands */ int nterms; /* number of terminal nodes in this tree */ }; -extern Tree tree(struct terminfo* ti, Tree left, Tree right); +extern Tree tree(const struct terminfo* ti, Tree left, Tree right); struct rule { /* rules: */ @@ -106,6 +107,8 @@ struct rule int ern; /* external rule number */ int packed; /* packed external rule number */ int cost; /* associated cost */ + const char* label; /* label for LHS */ + struct regattr* attr; /* register attribute of result */ Rule link; /* next rule in ern order */ Rule next; /* next rule with same pattern root */ Rule chain; /* next chain rule with same rhs */ @@ -116,7 +119,7 @@ struct rule ARRAYOF(struct constraint) constraints; /* register constraints */ struct stringlist code; /* compiler output code strings */ }; -extern Rule rule(char* id, Tree pattern, int ern); +extern Rule rule(const struct terminfo* ti, Tree pattern); extern int maxcost; /* maximum cost */ /* gram.y: */ diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 65dc26f54..14353c0e3 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -44,6 +44,8 @@ struct burm_emitter_data void (*emit_reg)(int child); void (*emit_value)(int child); void (*emit_eoi)(void); + void (*constrain_input_reg)(int child, int attr); + void (*constrain_output_reg)(int attr); }; typedef void burm_emitter_t(const struct burm_emitter_data* data); @@ -52,7 +54,6 @@ struct burm_instruction_data { const char* name; burm_emitter_t* emitter; - int allocate; bool is_fragment; }; @@ -75,6 +76,11 @@ enum REGATTR_BYTES8 }; +enum +{ + NONTERM_STMT = 1 +}; + #endif /* vim: set sw=4 ts=4 expandtab : */ From d95c75dfd7635c3d85855e10ced212a3dc9299ff Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 5 Oct 2016 23:24:29 +0200 Subject: [PATCH 073/230] Allowing an input filename on the command line makes debuggers happy. (Then we don't need to redirect stdin.) --- mach/proto/mcg/main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index eca8a14ec..9c863b8ad 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -32,6 +32,8 @@ static bool find_procedures_cb(struct symbol* symbol, void* user) int main(int argc, char* const argv[]) { + const char* inputfile = NULL; + program_name = argv[0]; opterr = 1; @@ -48,14 +50,17 @@ int main(int argc, char* const argv[]) break; case 1: - fatal("unexpected argument '%s'", optarg); + if (inputfile) + fatal("unexpected argument '%s'", optarg); + inputfile = optarg; } } symbol_init(); - if (!EM_open(NULL)) - fatal("couldn't open stdin: %s", EM_error); + if (!EM_open(inputfile)) + fatal("couldn't open '%s': %s", + inputfile ? inputfile : "", EM_error); /* Reads in the EM, outputs the data sections, parses any code and * generates IR trees. */ From 21034c0d65fa00bcd0eba94c416408f5f461a07b Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 5 Oct 2016 23:52:54 +0200 Subject: [PATCH 074/230] No, dammit, for register allocation I need to walk the blocks in *dominance* order. Since the dominance tree has changed when I fiddled with the graph, I need to recompute it, so factor it out of the SSA pass. Code is uglier than I'd like but at least the RET statement goes last in the generated code now. --- mach/proto/mcg/basicblock.h | 2 +- mach/proto/mcg/dominance.c | 123 +++++++++++++++++++++++++++++ mach/proto/mcg/dominance.h | 13 +++ mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_ssa.c | 110 +------------------------- mach/proto/mcg/registerallocator.c | 31 ++++---- 6 files changed, 154 insertions(+), 126 deletions(-) create mode 100644 mach/proto/mcg/dominance.c create mode 100644 mach/proto/mcg/dominance.h diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h index 7935c9ede..75aa38e84 100644 --- a/mach/proto/mcg/basicblock.h +++ b/mach/proto/mcg/basicblock.h @@ -10,7 +10,7 @@ struct basicblock ARRAYOF(struct basicblock) prevs; ARRAYOF(struct basicblock) nexts; - int order; /* used by SSA code */ + int order; /* used by dominance graph code */ ARRAYOF(struct vreg) liveins; diff --git a/mach/proto/mcg/dominance.c b/mach/proto/mcg/dominance.c new file mode 100644 index 000000000..9843f376c --- /dev/null +++ b/mach/proto/mcg/dominance.c @@ -0,0 +1,123 @@ +#include "mcg.h" + +struct array postorder; +struct array preorder; +struct pmap dominators; + +static void recursively_walk_blocks(struct basicblock* bb); + +static void recursively_walk_graph(struct basicblock* bb) +{ + static ARRAYOF(struct basicblock) pending; + int i; + + if (array_contains(&postorder, bb) || array_contains(&pending, bb)) + return; + + array_appendu(&preorder, bb); + array_appendu(&pending, bb); + + i = 0; + for (i=0; inexts.count; i++) + recursively_walk_graph(bb->nexts.item[i]); + + array_remove(&pending, bb); + bb->order = postorder.count; + array_appendu(&postorder, bb); +} + +static void walk_graph_postorder(struct basicblock* entry) +{ + int i; + + preorder.count = 0; + postorder.count = 0; + recursively_walk_graph(entry); + + for (i=0; iname); + } +} + +static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2) +{ + while (p1 != p2) + { + while (p1->order < p2->order) + p1 = pmap_get(&dominators, p1); + + while (p2->order < p1->order) + p2 = pmap_get(&dominators, p2); + } + + return p1; +} + +void calculate_dominance_graph(struct procedure* proc) +{ + /* This is the algorithm described here: + * + * Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy. + * "A simple, fast dominance algorithm." + * Software Practice & Experience 4.1-10 (2001): 1-8. + * + * https://www.cs.rice.edu/~keith/EMBED/dom.pdf + */ + + int i, j; + bool changed; + struct basicblock* entry = proc->blocks.item[0]; + + entry = proc->blocks.item[0]; + walk_graph_postorder(entry); + assert(postorder.count == proc->blocks.count); + + dominators.count = 0; + + /* The entry block dominates itself. */ + + pmap_put(&dominators, entry, entry); + + do + { + changed = false; + + for (i = postorder.count-2; i >= 0; i--) + { + struct basicblock* b = postorder.item[i]; + struct basicblock* new_idom = NULL; + for (j=0; jprevs.count; j++) + { + struct basicblock* p = b->prevs.item[j]; + + /* Skip unprocessed blocks. */ + if (!pmap_get(&dominators, p)) + continue; + + if (!new_idom) + new_idom = p; + else if (pmap_get(&dominators, p)) + new_idom = intersect(p, new_idom); + } + + if (pmap_get(&dominators, b) != new_idom) + { + pmap_put(&dominators, b, new_idom); + changed = true; + } + } + } + while (changed); + + for (i=0; i %s\n", + ((struct basicblock*)dominators.item[i].left)->name, + ((struct basicblock*)dominators.item[i].right)->name); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/dominance.h b/mach/proto/mcg/dominance.h new file mode 100644 index 000000000..ee5d39b68 --- /dev/null +++ b/mach/proto/mcg/dominance.h @@ -0,0 +1,13 @@ +#ifndef DOMINANCE_H +#define DOMINANCE_H + +extern struct array postorder; +extern struct array preorder; +extern struct pmap dominators; + +extern void calculate_dominance_graph(struct procedure* proc); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 601249f07..1fdb7d96c 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -27,6 +27,7 @@ #include "reg.h" #include "basicblock.h" #include "procedure.h" +#include "dominance.h" extern char em_pseu[][4]; extern char em_mnem[][4]; diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 265ade1f5..2a030b132 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -1,8 +1,6 @@ #include "mcg.h" static struct basicblock* entry; -static ARRAYOF(struct basicblock) postorder; -static PMAPOF(struct basicblock, struct basicblock) dominators; static PMAPOF(struct basicblock, struct basicblock) dominancefrontiers; static struct local* current_local; @@ -11,110 +9,6 @@ static ARRAYOF(struct basicblock) needsphis; static ARRAYOF(struct ir) definitions; static ARRAYOF(struct basicblock) rewritten; -static void recursively_walk_blocks(struct basicblock* bb); - -static void recursively_walk_graph_postorder(struct basicblock* bb) -{ - static ARRAYOF(struct basicblock) pending; - int i; - - if (array_contains(&postorder, bb) || array_contains(&pending, bb)) - return; - - array_appendu(&pending, bb); - - i = 0; - for (i=0; inexts.count; i++) - recursively_walk_graph_postorder(bb->nexts.item[i]); - - array_remove(&pending, bb); - bb->order = postorder.count; - array_appendu(&postorder, bb); -} - -static void walk_graph_postorder() -{ - int i; - - postorder.count = 0; - recursively_walk_graph_postorder(entry); - - for (i=0; iname); - } -} - -static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2) -{ - while (p1 != p2) - { - while (p1->order < p2->order) - p1 = pmap_get(&dominators, p1); - - while (p2->order < p1->order) - p2 = pmap_get(&dominators, p2); - } - - return p1; -} - -static void calculate_dominance_graph(void) -{ - /* This is the algorithm described here: - * - * Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy. - * "A simple, fast dominance algorithm." - * Software Practice & Experience 4.1-10 (2001): 1-8. - * - * https://www.cs.rice.edu/~keith/EMBED/dom.pdf - */ - - int i, j; - bool changed; - - dominators.count = 0; - - /* The entry block dominates itself. */ - - pmap_put(&dominators, entry, entry); - - do - { - changed = false; - - for (i = postorder.count-2; i >= 0; i--) - { - struct basicblock* b = postorder.item[i]; - struct basicblock* new_idom = NULL; - for (j=0; jprevs.count; j++) - { - struct basicblock* p = b->prevs.item[j]; - - if (!new_idom) - new_idom = p; - else if (pmap_get(&dominators, p)) - new_idom = intersect(p, new_idom); - } - - if (pmap_get(&dominators, b) != new_idom) - { - pmap_put(&dominators, b, new_idom); - changed = true; - } - } - } - while (changed); - - for (i=0; i %s\n", - dominators.item[i].left->name, - dominators.item[i].right->name); - } -} - static void calculate_dominance_frontier_graph(void) { /* This is the algorithm described here: @@ -324,9 +218,7 @@ void pass_convert_locals_to_ssa(struct procedure* proc) int i; entry = proc->blocks.item[0]; - walk_graph_postorder(); - assert(postorder.count == proc->blocks.count); - calculate_dominance_graph(); + calculate_dominance_graph(proc); calculate_dominance_frontier_graph(); for (i=0; ilocals.count; i++) diff --git a/mach/proto/mcg/registerallocator.c b/mach/proto/mcg/registerallocator.c index eae72fac6..664245826 100644 --- a/mach/proto/mcg/registerallocator.c +++ b/mach/proto/mcg/registerallocator.c @@ -2,32 +2,31 @@ static ARRAYOF(struct basicblock) blocks; -static void recursively_walk_blocks(struct basicblock* bb) +static void recursively_walk_dominance_graph(struct basicblock* bb) { int i; - if (array_appendu(&blocks, bb)) - return; + array_append(&blocks, bb); tracef('R', "R: considering block %s\n", bb->name); - for (i=0; inexts.count; i++) - recursively_walk_blocks(bb->nexts.item[i]); -} - -static void order_blocks(struct procedure* proc) -{ - /* Put them into preorder; this ensures that when we do the allocation, - * we do all of a block's predecessors before the block (except for - * backward edges). */ + /* Skip the entry block (which is its own dominator). */ - blocks.count = 0; - recursively_walk_blocks(proc->blocks.item[0]); - assert(blocks.count == proc->blocks.count); + for (i=1; iblocks.item[0]); + assert(blocks.count == proc->blocks.count); } /* vim: set sw=4 ts=4 expandtab : */ From 87e004e4a92e825358e7b4e9c1c5e942146dc07f Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 5 Oct 2016 23:55:04 +0200 Subject: [PATCH 075/230] Warning fix. --- mach/proto/mcg/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 9c863b8ad..5789a1379 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -58,7 +58,7 @@ int main(int argc, char* const argv[]) symbol_init(); - if (!EM_open(inputfile)) + if (!EM_open((char*) inputfile)) fatal("couldn't open '%s': %s", inputfile ? inputfile : "", EM_error); From d20b63dc947b70ef0ccf9a500354bd6f57a38cc6 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 5 Oct 2016 23:55:38 +0200 Subject: [PATCH 076/230] The register allocator is really a pass, so arrange the code like one. --- mach/proto/mcg/mcg.h | 3 +-- .../mcg/{registerallocator.c => pass_registerallocator.c} | 2 +- mach/proto/mcg/procedure.c | 7 ++++--- 3 files changed, 6 insertions(+), 6 deletions(-) rename mach/proto/mcg/{registerallocator.c => pass_registerallocator.c} (92%) diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 1fdb7d96c..5d631e224 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -107,11 +107,10 @@ extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_group_irs(struct procedure* proc); extern void pass_instruction_selector(struct procedure* proc); extern void pass_promote_float_ops(struct procedure* proc); +extern void pass_register_allocator(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_split_critical_edges(struct procedure* proc); -extern void register_allocator(struct procedure* proc); - #endif /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/registerallocator.c b/mach/proto/mcg/pass_registerallocator.c similarity index 92% rename from mach/proto/mcg/registerallocator.c rename to mach/proto/mcg/pass_registerallocator.c index 664245826..27e421418 100644 --- a/mach/proto/mcg/registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -20,7 +20,7 @@ static void recursively_walk_dominance_graph(struct basicblock* bb) } } -void register_allocator(struct procedure* proc) +void pass_register_allocator(struct procedure* proc) { calculate_dominance_graph(proc); diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 8d0f83953..8685df54d 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -49,7 +49,9 @@ void procedure_compile(struct procedure* proc) pass_remove_dead_blocks(proc); procedure_update_bb_graph(proc); - /* Passes from here on can't alter the BB graph */ + + /* Passes from here on can't alter the BB graph without also updating prevs + * and nexts. */ print_blocks('2', proc); pass_convert_stack_ops(proc); @@ -62,8 +64,7 @@ void procedure_compile(struct procedure* proc) print_blocks('6', proc); pass_instruction_selector(proc); - - register_allocator(proc); + pass_register_allocator(proc); } static bool collect_outputs_cb(struct ir* ir, void* user) From 7f901aa4d0166409215930c97f50af4ced400e42 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 6 Oct 2016 21:33:43 +0200 Subject: [PATCH 077/230] We're not using 'allocates' any more; clean up. --- util/mcgg/gram.y | 2 -- util/mcgg/scan.l | 1 - 2 files changed, 3 deletions(-) diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index fbd191052..30c61cb4c 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -25,7 +25,6 @@ extern int yylex(void); struct constraint* constraint; } -%term ALLOCATES %term COPY %term COST %term DECLARATIONS @@ -43,7 +42,6 @@ extern int yylex(void); %token ID %token QFRAGMENT -%type allocates %type constraint %type constraints %type declaration diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 2d04f52c0..6bd50d294 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -38,7 +38,6 @@ static int braces = 0; "DECLARATIONS" return DECLARATIONS; "PATTERNS" return PATTERNS; "REGISTERS" return REGISTERS; -"allocates" return ALLOCATES; "cost" return COST; "emit" return EMIT; "fragment" return FRAGMENT; From ee93389c5fa01c2105d7d518472e7506748f6974 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 6 Oct 2016 21:34:21 +0200 Subject: [PATCH 078/230] Refactor the cfg and dominance stuff to make it a lot nicer. --- mach/proto/mcg/dominance.c | 123 -------------- mach/proto/mcg/dominance.h | 13 -- mach/proto/mcg/graph.c | 208 +++++++++++++++++++++++ mach/proto/mcg/graph.h | 26 +++ mach/proto/mcg/mcg.h | 2 +- mach/proto/mcg/pass_convertstackops.c | 1 - mach/proto/mcg/pass_registerallocator.c | 10 +- mach/proto/mcg/pass_splitcriticaledges.c | 8 +- mach/proto/mcg/pass_ssa.c | 19 +-- mach/proto/mcg/procedure.c | 52 +----- 10 files changed, 258 insertions(+), 204 deletions(-) delete mode 100644 mach/proto/mcg/dominance.c delete mode 100644 mach/proto/mcg/dominance.h create mode 100644 mach/proto/mcg/graph.c create mode 100644 mach/proto/mcg/graph.h diff --git a/mach/proto/mcg/dominance.c b/mach/proto/mcg/dominance.c deleted file mode 100644 index 9843f376c..000000000 --- a/mach/proto/mcg/dominance.c +++ /dev/null @@ -1,123 +0,0 @@ -#include "mcg.h" - -struct array postorder; -struct array preorder; -struct pmap dominators; - -static void recursively_walk_blocks(struct basicblock* bb); - -static void recursively_walk_graph(struct basicblock* bb) -{ - static ARRAYOF(struct basicblock) pending; - int i; - - if (array_contains(&postorder, bb) || array_contains(&pending, bb)) - return; - - array_appendu(&preorder, bb); - array_appendu(&pending, bb); - - i = 0; - for (i=0; inexts.count; i++) - recursively_walk_graph(bb->nexts.item[i]); - - array_remove(&pending, bb); - bb->order = postorder.count; - array_appendu(&postorder, bb); -} - -static void walk_graph_postorder(struct basicblock* entry) -{ - int i; - - preorder.count = 0; - postorder.count = 0; - recursively_walk_graph(entry); - - for (i=0; iname); - } -} - -static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2) -{ - while (p1 != p2) - { - while (p1->order < p2->order) - p1 = pmap_get(&dominators, p1); - - while (p2->order < p1->order) - p2 = pmap_get(&dominators, p2); - } - - return p1; -} - -void calculate_dominance_graph(struct procedure* proc) -{ - /* This is the algorithm described here: - * - * Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy. - * "A simple, fast dominance algorithm." - * Software Practice & Experience 4.1-10 (2001): 1-8. - * - * https://www.cs.rice.edu/~keith/EMBED/dom.pdf - */ - - int i, j; - bool changed; - struct basicblock* entry = proc->blocks.item[0]; - - entry = proc->blocks.item[0]; - walk_graph_postorder(entry); - assert(postorder.count == proc->blocks.count); - - dominators.count = 0; - - /* The entry block dominates itself. */ - - pmap_put(&dominators, entry, entry); - - do - { - changed = false; - - for (i = postorder.count-2; i >= 0; i--) - { - struct basicblock* b = postorder.item[i]; - struct basicblock* new_idom = NULL; - for (j=0; jprevs.count; j++) - { - struct basicblock* p = b->prevs.item[j]; - - /* Skip unprocessed blocks. */ - if (!pmap_get(&dominators, p)) - continue; - - if (!new_idom) - new_idom = p; - else if (pmap_get(&dominators, p)) - new_idom = intersect(p, new_idom); - } - - if (pmap_get(&dominators, b) != new_idom) - { - pmap_put(&dominators, b, new_idom); - changed = true; - } - } - } - while (changed); - - for (i=0; i %s\n", - ((struct basicblock*)dominators.item[i].left)->name, - ((struct basicblock*)dominators.item[i].right)->name); - } -} - -/* vim: set sw=4 ts=4 expandtab : */ - diff --git a/mach/proto/mcg/dominance.h b/mach/proto/mcg/dominance.h deleted file mode 100644 index ee5d39b68..000000000 --- a/mach/proto/mcg/dominance.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef DOMINANCE_H -#define DOMINANCE_H - -extern struct array postorder; -extern struct array preorder; -extern struct pmap dominators; - -extern void calculate_dominance_graph(struct procedure* proc); - -#endif - -/* vim: set sw=4 ts=4 expandtab : */ - diff --git a/mach/proto/mcg/graph.c b/mach/proto/mcg/graph.c new file mode 100644 index 000000000..2897bc78a --- /dev/null +++ b/mach/proto/mcg/graph.c @@ -0,0 +1,208 @@ +#include "mcg.h" + +struct graph_data cfg; +struct dominance_data dominance; + +static ARRAYOF(struct basicblock) pending; + +static bool collect_outputs_cb(struct ir* ir, void* user) +{ + struct basicblock* caller = user; + + if (ir->opcode == IR_BLOCK) + { + array_appendu(&caller->nexts, ir->u.bvalue); + array_appendu(&ir->u.bvalue->prevs, caller); + } + return false; +} + +static void update_block_pointers_from_ir(struct procedure* proc) +{ + int i, j; + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + bb->prevs.count = bb->nexts.count = 0; + } + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + for (j=0; jirs.count; j++) + ir_walk(bb->irs.item[j], collect_outputs_cb, bb); + } + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + + for (j=0; jnexts.count; j++) + { + tracef('D', "D: cfg graph %s -> %s\n", + bb->name, + bb->nexts.item[j]->name); + } + } +} + +static void recursively_walk_cfg_graph(struct basicblock* bb) +{ + int i; + + if (array_contains(&cfg.postorder, bb) || array_contains(&pending, bb)) + return; + + array_appendu(&cfg.preorder, bb); + array_appendu(&pending, bb); + + for (i=0; inexts.count; i++) + recursively_walk_cfg_graph(bb->nexts.item[i]); + + array_remove(&pending, bb); + bb->order = cfg.postorder.count; + array_appendu(&cfg.postorder, bb); +} + +static void walk_cfg_graph(void) +{ + int i; + + cfg.preorder.count = 0; + cfg.postorder.count = 0; + pending.count = 0; + recursively_walk_cfg_graph(cfg.entry); + + for (i=0; iname); + } +} + +static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2) +{ + while (p1 != p2) + { + while (p1->order < p2->order) + p1 = pmap_get(&dominance.graph, p1); + + while (p2->order < p1->order) + p2 = pmap_get(&dominance.graph, p2); + } + + return p1; +} + +static void calculate_dominance_graph(void) +{ + /* This is the algorithm described here: + * + * Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy. + * "A simple, fast dominance algorithm." + * Software Practice & Experience 4.1-10 (2001): 1-8. + * + * https://www.cs.rice.edu/~keith/EMBED/dom.pdf + */ + + int i, j; + bool changed; + + dominance.graph.count = 0; + + /* The entry block dominates itself. */ + + pmap_put(&dominance.graph, cfg.entry, cfg.entry); + + do + { + changed = false; + + for (i = cfg.postorder.count-2; i >= 0; i--) + { + struct basicblock* b = cfg.postorder.item[i]; + struct basicblock* new_idom = NULL; + for (j=0; jprevs.count; j++) + { + struct basicblock* p = b->prevs.item[j]; + + /* Skip unprocessed blocks. */ + if (!pmap_get(&dominance.graph, p)) + continue; + + if (!new_idom) + new_idom = p; + else if (pmap_get(&dominance.graph, p)) + new_idom = intersect(p, new_idom); + } + + if (pmap_get(&dominance.graph, b) != new_idom) + { + pmap_put(&dominance.graph, b, new_idom); + changed = true; + } + } + } + while (changed); + + for (i=0; i %s\n", + dominance.graph.item[i].right->name, + dominance.graph.item[i].left->name); + } +} + +static void recursively_walk_dominance_graph(struct basicblock* bb) +{ + int i; + + if (array_contains(&dominance.postorder, bb) || array_contains(&pending, bb)) + return; + + array_appendu(&dominance.preorder, bb); + array_appendu(&pending, bb); + + for (i=0; iname); + } +} + +void update_graph_data(struct procedure* proc) +{ + cfg.entry = proc->blocks.item[0]; + update_block_pointers_from_ir(proc); + + walk_cfg_graph(); + assert(cfg.postorder.count == proc->blocks.count); + assert(cfg.preorder.count == proc->blocks.count); + + calculate_dominance_graph(); + + walk_dominance_graph(); + assert(dominance.postorder.count == dominance.graph.count); + assert(dominance.preorder.count == dominance.graph.count); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/graph.h b/mach/proto/mcg/graph.h new file mode 100644 index 000000000..59c93137e --- /dev/null +++ b/mach/proto/mcg/graph.h @@ -0,0 +1,26 @@ +#ifndef GRAPH_H +#define GRAPH_H + +struct graph_data +{ + struct basicblock* entry; + ARRAYOF(struct basicblock) preorder; + ARRAYOF(struct basicblock) postorder; +}; + +struct dominance_data +{ + PMAPOF(struct basicblock, struct basicblock) graph; + ARRAYOF(struct basicblock) preorder; + ARRAYOF(struct basicblock) postorder; +}; + +extern struct graph_data cfg; +extern struct dominance_data dominance; + +extern void update_graph_data(struct procedure* proc); + +#endif + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 5d631e224..bad088ee3 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -27,7 +27,7 @@ #include "reg.h" #include "basicblock.h" #include "procedure.h" -#include "dominance.h" +#include "graph.h" extern char em_pseu[][4]; extern char em_mnem[][4]; diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index d555b58ba..dbc1f8276 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -1,6 +1,5 @@ #include "mcg.h" -static PMAPOF(struct basicblock, struct basicblock) graph; static ARRAYOF(struct ir) pops; static ARRAYOF(struct ir) pushes; diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 27e421418..23121bc42 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -11,10 +11,10 @@ static void recursively_walk_dominance_graph(struct basicblock* bb) /* Skip the entry block (which is its own dominator). */ - for (i=1; iblocks.item[0]); + recursively_walk_dominance_graph(cfg.entry); assert(blocks.count == proc->blocks.count); } diff --git a/mach/proto/mcg/pass_splitcriticaledges.c b/mach/proto/mcg/pass_splitcriticaledges.c index 9237be750..7962974cc 100644 --- a/mach/proto/mcg/pass_splitcriticaledges.c +++ b/mach/proto/mcg/pass_splitcriticaledges.c @@ -36,12 +36,14 @@ static void split_edge(struct basicblock* source, struct basicblock* sink) struct rewrite_params rwp; struct basicblock* bb = bb_get(NULL); - array_append(&bb->irs, + struct ir* jump = new_ir1( IR_JUMP, 0, new_bbir(sink) - ) - ); + ); + + jump->root = jump->left->root = jump; + array_append(&bb->irs, jump); rwp.find = sink; rwp.replace = bb; diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 2a030b132..0f7fc2d37 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -1,6 +1,5 @@ #include "mcg.h" -static struct basicblock* entry; static PMAPOF(struct basicblock, struct basicblock) dominancefrontiers; static struct local* current_local; @@ -24,10 +23,10 @@ static void calculate_dominance_frontier_graph(void) dominancefrontiers.count = 0; - for (i=0; iprevs.count >= 2) { for (j=0; jprevs.count; j++) @@ -38,7 +37,7 @@ static void calculate_dominance_frontier_graph(void) tracef('S', "S: %s is in %s's dominance frontier\n", b->name, runner->name); pmap_add(&dominancefrontiers, runner, b); - runner = pmap_get(&dominators, runner); + runner = pmap_get(&dominance.graph, runner); } } } @@ -158,7 +157,7 @@ static void ssa_convert(void) ir->left->root = ir; ir->right->root = ir; ir->right->left->root = ir; - array_insert(&entry->irs, ir, 0); + array_insert(&cfg.entry->irs, ir, 0); } defining.count = 0; @@ -166,9 +165,9 @@ static void ssa_convert(void) /* Find everwhere where the variable is *defined*. */ - for (i=0; iirs.count; j++) { struct ir* ir = bb->irs.item[j]; @@ -210,15 +209,13 @@ static void ssa_convert(void) definitions.count = 0; rewritten.count = 0; - recursively_rewrite_tree(entry); + recursively_rewrite_tree(cfg.entry); } void pass_convert_locals_to_ssa(struct procedure* proc) { int i; - entry = proc->blocks.item[0]; - calculate_dominance_graph(proc); calculate_dominance_frontier_graph(); for (i=0; ilocals.count; i++) diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 8685df54d..69aba0af8 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -48,66 +48,26 @@ void procedure_compile(struct procedure* proc) pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); - procedure_update_bb_graph(proc); + update_graph_data(proc); /* Passes from here on can't alter the BB graph without also updating prevs - * and nexts. */ + * and nexts (and then calling update_graph_data()). */ print_blocks('2', proc); pass_convert_stack_ops(proc); print_blocks('3', proc); pass_convert_locals_to_ssa(proc); print_blocks('4', proc); - pass_split_critical_edges(proc); - print_blocks('5', proc); pass_promote_float_ops(proc); + print_blocks('5', proc); + pass_split_critical_edges(proc); print_blocks('6', proc); + update_graph_data(proc); + pass_instruction_selector(proc); pass_register_allocator(proc); } -static bool collect_outputs_cb(struct ir* ir, void* user) -{ - struct basicblock* caller = user; - - if (ir->opcode == IR_BLOCK) - { - array_appendu(&caller->nexts, ir->u.bvalue); - array_appendu(&ir->u.bvalue->prevs, caller); - } - return false; -} - -void procedure_update_bb_graph(struct procedure* proc) -{ - int i, j; - - for (i=0; iblocks.count; i++) - { - struct basicblock* bb = proc->blocks.item[i]; - bb->prevs.count = bb->nexts.count = 0; - } - - for (i=0; iblocks.count; i++) - { - struct basicblock* bb = proc->blocks.item[i]; - for (j=0; jirs.count; j++) - ir_walk(bb->irs.item[j], collect_outputs_cb, bb); - } - - for (i=0; iblocks.count; i++) - { - struct basicblock* bb = proc->blocks.item[i]; - - for (j=0; jnexts.count; j++) - { - tracef('G', "G: graph %s -> %s\n", - bb->name, - bb->nexts.item[j]->name); - } - } -} - /* vim: set sw=4 ts=4 expandtab : */ From b7af003dbb246039cf6d2bd0ccc9998d74321268 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 8 Oct 2016 00:20:26 +0200 Subject: [PATCH 079/230] Add array_{appendall,removeall,appendallu}. --- modules/src/data/array.c | 33 +++++++++++++++++++++++++++++++++ modules/src/data/array.h | 6 ++++++ 2 files changed, 39 insertions(+) diff --git a/modules/src/data/array.c b/modules/src/data/array.c index 13c0b6cf6..2847bbdd4 100644 --- a/modules/src/data/array.c +++ b/modules/src/data/array.c @@ -90,5 +90,38 @@ void* array_pop(void* arrayp) return array->item[array->count--]; } +void array_appendall(void* arrayp, void* srcp) +{ + struct array* array = arrayp; + struct array* src = srcp; + int i; + + for (i=0; icount; i++) + array_append(array, src->item[i]); +} + +void array_removeall(void* arrayp, void* srcp) +{ + struct array* array = arrayp; + struct array* src = srcp; + int i; + + for (i=0; icount; i++) + array_remove(array, src->item[i]); +} + +bool array_appendallu(void* arrayp, void* srcp) +{ + struct array* array = arrayp; + struct array* src = srcp; + bool unchanged = true; + int i; + + for (i=0; icount; i++) + unchanged &= array_appendu(array, src->item[i]); + + return unchanged; +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/modules/src/data/array.h b/modules/src/data/array.h index 8762d7e6d..6ec497566 100644 --- a/modules/src/data/array.h +++ b/modules/src/data/array.h @@ -27,5 +27,11 @@ extern int array_indexof(void* array, void* value); #define array_push(a, v) array_append(a, v) extern void* array_pop(void* array); +extern void array_appendall(void* dest, void* src); +extern void array_removeall(void* dest, void* src); + +/* Returns false if *any* items were added. */ +extern bool array_appendallu(void* dest, void* src); + #endif From 4e49830e09772ba930f40194c75397a706adfc04 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 8 Oct 2016 00:21:23 +0200 Subject: [PATCH 080/230] Overhaul of everything phi related; critical edge splitting now happens before anything SSA happens; liveness calculations now look like they might be working. --- mach/proto/mcg/basicblock.h | 12 +- mach/proto/mcg/graph.c | 2 + mach/proto/mcg/graph.h | 1 + mach/proto/mcg/hop.c | 10 +- mach/proto/mcg/hop.h | 5 +- mach/proto/mcg/ir.c | 4 +- mach/proto/mcg/ir.h | 2 +- mach/proto/mcg/main.c | 32 +++++- mach/proto/mcg/mcg.h | 8 +- mach/proto/mcg/pass_convertstackops.c | 10 +- mach/proto/mcg/pass_instructionselection.c | 29 +++-- mach/proto/mcg/pass_livevreganalysis.c | 73 ++++++++++++ mach/proto/mcg/pass_registerallocator.c | 25 +---- mach/proto/mcg/pass_ssa.c | 3 +- mach/proto/mcg/procedure.c | 124 +++++++++++++++++++-- mach/proto/mcg/reg.h | 2 + 16 files changed, 286 insertions(+), 56 deletions(-) create mode 100644 mach/proto/mcg/pass_livevreganalysis.c diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h index 75aa38e84..4c65721e4 100644 --- a/mach/proto/mcg/basicblock.h +++ b/mach/proto/mcg/basicblock.h @@ -1,6 +1,12 @@ #ifndef BASICBLOCK_H #define BASICBLOCK_H +struct phi +{ + struct basicblock* prev; /* Predecessor that this phi is referring to */ + struct ir* ir; /* IR of variable definition */ +}; + struct basicblock { const char* name; @@ -12,7 +18,11 @@ struct basicblock ARRAYOF(struct basicblock) nexts; int order; /* used by dominance graph code */ - ARRAYOF(struct vreg) liveins; + PMAPOF(struct vreg, struct phi) phis; + + /* Used by liveness calculation. */ + ARRAYOF(struct vreg) liveins; + ARRAYOF(struct vreg) liveouts; bool is_fake : 1; bool is_root : 1; diff --git a/mach/proto/mcg/graph.c b/mach/proto/mcg/graph.c index 2897bc78a..9c976735b 100644 --- a/mach/proto/mcg/graph.c +++ b/mach/proto/mcg/graph.c @@ -13,6 +13,7 @@ static bool collect_outputs_cb(struct ir* ir, void* user) { array_appendu(&caller->nexts, ir->u.bvalue); array_appendu(&ir->u.bvalue->prevs, caller); + pmap_add(&cfg.graph, caller, ir->u.bvalue); } return false; } @@ -191,6 +192,7 @@ static void walk_dominance_graph(void) void update_graph_data(struct procedure* proc) { cfg.entry = proc->blocks.item[0]; + cfg.graph.count = 0; update_block_pointers_from_ir(proc); walk_cfg_graph(); diff --git a/mach/proto/mcg/graph.h b/mach/proto/mcg/graph.h index 59c93137e..93991b82f 100644 --- a/mach/proto/mcg/graph.h +++ b/mach/proto/mcg/graph.h @@ -4,6 +4,7 @@ struct graph_data { struct basicblock* entry; + PMAPOF(struct basicblock, struct basicblock) graph; ARRAYOF(struct basicblock) preorder; ARRAYOF(struct basicblock) postorder; }; diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 352ad9b2b..d175147b6 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -5,11 +5,11 @@ static struct hop* current_hop; static const struct burm_emitter_data emitter_data; -struct hop* new_hop(int insn_no, struct ir* ir) +struct hop* new_hop(struct basicblock* bb, struct ir* ir) { struct hop* hop = calloc(1, sizeof *hop); hop->id = hop_count++; - hop->insn_no = insn_no; + hop->bb = bb; hop->ir = ir; return hop; } @@ -63,9 +63,11 @@ void hop_print(char k, struct hop* hop) tracef(k, "%c: %d from $%d:", k, hop->id, hop->ir->id); for (j=0; jins.count; j++) - tracef(k, " <%%%d", hop->ins.item[j]->id); + tracef(k, " r%%%d", hop->ins.item[j]->id); + for (j=0; jthroughs.count; j++) + tracef(k, " =%%%d", hop->throughs.item[j]->id); for (j=0; jouts.count; j++) - tracef(k, " >%%%d", hop->outs.item[j]->id); + tracef(k, " w%%%d", hop->outs.item[j]->id); tracef(k, " "); soi = false; diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 66903cbfe..18e70d3b4 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -24,17 +24,18 @@ struct insel struct hop { int id; - int insn_no; + struct basicblock* bb; struct ir* ir; ARRAYOF(struct insel) insels; struct vreg* output; ARRAYOF(struct vreg) ins; ARRAYOF(struct vreg) outs; + ARRAYOF(struct vreg) throughs; PMAPOF(struct vreg, struct hreg) registers; }; -extern struct hop* new_hop(int insn_no, struct ir* ir); +extern struct hop* new_hop(struct basicblock* bb, struct ir* ir); extern void hop_add_string_insel(struct hop* hop, const char* string); extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index de3ec396f..74fbac060 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -132,7 +132,9 @@ static void print_expr(char k, const struct ir* ir) { if (i > 0) tracef(k, ", "); - tracef(k, "$%d", ir->u.phivalue.item[i]->id); + tracef(k, "%s=>$%d", + ir->u.phivalue.item[i].left->name, + ir->u.phivalue.item[i].right->id); } break; } diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index a12b9642c..c273709f2 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -17,7 +17,7 @@ struct ir int rvalue; const char* lvalue; struct basicblock* bvalue; - ARRAYOF(struct ir) phivalue; + PMAPOF(struct basicblock, struct ir) phivalue; } u; struct vreg* result; /* vreg containing IR result */ diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 5789a1379..235e9f357 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -1,8 +1,12 @@ #include "mcg.h" +#include #include static const char* tracechars = NULL; +FILE* dominance_dot_file = NULL; +FILE* cfg_dot_file = NULL; + bool tracing(char k) { if (!tracechars) @@ -39,12 +43,28 @@ int main(int argc, char* const argv[]) opterr = 1; for (;;) { - int c = getopt(argc, argv, "-d:"); + int c = getopt(argc, argv, "-d:D:C:"); if (c == -1) break; switch (c) { + case 'C': + cfg_dot_file = fopen(optarg, "w"); + if (!cfg_dot_file) + fatal("couldn't open output file '%s': %s", + optarg, strerror(errno)); + fprintf(cfg_dot_file, "digraph {\n"); + break; + + case 'D': + dominance_dot_file = fopen(optarg, "w"); + if (!dominance_dot_file) + fatal("couldn't open output file '%s': %s", + optarg, strerror(errno)); + fprintf(dominance_dot_file, "digraph {\n"); + break; + case 'd': tracechars = optarg; break; @@ -74,6 +94,16 @@ int main(int argc, char* const argv[]) symbol_walk(find_procedures_cb, NULL); EM_close(); + if (cfg_dot_file) + { + fprintf(cfg_dot_file, "}\n"); + fclose(cfg_dot_file); + } + if (dominance_dot_file) + { + fprintf(dominance_dot_file, "}\n"); + fclose(dominance_dot_file); + } return 0; } diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index bad088ee3..f4e33f2af 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -105,12 +105,16 @@ extern void pass_convert_locals_to_ssa(struct procedure* proc); extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_group_irs(struct procedure* proc); -extern void pass_instruction_selector(struct procedure* proc); +extern void pass_instruction_selector(void); +extern void pass_live_vreg_analysis(void); extern void pass_promote_float_ops(struct procedure* proc); -extern void pass_register_allocator(struct procedure* proc); +extern void pass_register_allocator(void); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_split_critical_edges(struct procedure* proc); +extern FILE* dominance_dot_file; +extern FILE* cfg_dot_file; + #endif /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index dbc1f8276..d73924d67 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -1,7 +1,7 @@ #include "mcg.h" static ARRAYOF(struct ir) pops; -static ARRAYOF(struct ir) pushes; +static PMAPOF(struct basicblock, struct ir) pushes; static struct ir* get_last_push(struct basicblock* bb) { @@ -74,7 +74,7 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) ir = get_last_push(inbb); if (!ir || (ir->size != lastpush->size)) return; - array_appendu(&pushes, ir); + pmap_add(&pushes, inbb, ir); } } @@ -87,7 +87,7 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) for (i=0; ileft; } @@ -97,7 +97,9 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) struct ir* phi = new_ir0(IR_PHI, ir->size); for (j=0; ju.phivalue, pushes.item[j]); + pmap_add(&phi->u.phivalue, + pushes.item[j].left, + pushes.item[j].right); phi->root = phi; *ir = *phi; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index ca7589e86..029cacd4b 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -52,7 +52,10 @@ static void emit_reg(int child) struct vreg* vreg = find_vreg_of_child(child); if (vreg) + { hop_add_vreg_insel(current_hop, vreg); + array_appendu(&vreg->used, current_hop); + } } static void emit_string(const char* data) @@ -165,13 +168,17 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) vreg = new_vreg(); } - insn->hop = current_hop = new_hop(0, insn->ir); + insn->hop = current_hop = new_hop(current_bb, insn->ir); insn->hop->output = vreg; if (vreg) + { array_appendu(¤t_hop->outs, vreg); + vreg->defined = current_hop; + } emit(insn); hop_print('I', current_hop); + array_append(¤t_bb->hops, current_hop); if (goal != 1) insn->ir->result = insn->hop->output; @@ -220,10 +227,18 @@ static void select_instructions(void) int j; current_ir->result = new_vreg(); - array_append(¤t_bb->liveins, current_ir->result); - tracef('I', "I: %d is phi:", current_ir->result->id); + tracef('I', "I: $%d is phi:", current_ir->result->id); for (j=0; ju.phivalue.count; j++) - tracef('I', " $%d", current_ir->u.phivalue.item[j]->id); + { + struct basicblock* parentbb = current_ir->u.phivalue.item[j].left; + struct ir* parentir = current_ir->u.phivalue.item[j].right; + struct phi* phi = calloc(1, sizeof(*phi)); + tracef('I', " %s=>$%d", parentbb->name, parentir->id); + + phi->prev = parentbb; + phi->ir = parentir; + pmap_add(¤t_bb->phis, current_ir->result, phi); + } tracef('I', "\n"); } else @@ -241,13 +256,13 @@ static void select_instructions(void) } } -void pass_instruction_selector(struct procedure* proc) +void pass_instruction_selector(void) { int i; - for (i=0; iblocks.count; i++) + for (i=0; iblocks.item[i]; + current_bb = cfg.preorder.item[i]; select_instructions(); } } diff --git a/mach/proto/mcg/pass_livevreganalysis.c b/mach/proto/mcg/pass_livevreganalysis.c new file mode 100644 index 000000000..889fe35b5 --- /dev/null +++ b/mach/proto/mcg/pass_livevreganalysis.c @@ -0,0 +1,73 @@ +#include "mcg.h" + +static bool finished; + +static void preload_blocks(void) +{ + /* Any variable referenced in a phi *must* be a liveout of one of our + * predecessors. */ + + int i, j; + for (i=0; iphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + + assert(array_contains(&bb->prevs, phi->prev)); + array_appendu(&phi->prev->liveouts, phi->ir->result); + } + } +} + +static void propagate_liveness(struct basicblock* bb) +{ + static ARRAYOF(struct vreg) current; + int i; + + current.count = 0; + array_appendall(¤t, &bb->liveouts); + + for (i=bb->hops.count-1; i>=0; i--) + { + struct hop* hop = bb->hops.item[i]; + + array_removeall(¤t, &hop->outs); + finished &= array_appendallu(&hop->throughs, ¤t); + array_appendallu(¤t, &hop->ins); + } + + for (i=0; iphis.count; i++) + array_remove(¤t, bb->phis.item[i].left); + + finished &= array_appendallu(&bb->liveins, ¤t); + + for (i=0; iprevs.count; i++) + { + struct basicblock* prev = bb->prevs.item[i]; + finished &= array_appendallu(&prev->liveouts, ¤t); + } +} + +void pass_live_vreg_analysis(void) +{ + int i; + + preload_blocks(); + + do + { + finished = true; + + tracef('L', "L: beginning liveness pass\n"); + for (i=0; iname); - - /* Skip the entry block (which is its own dominator). */ - - for (i=1; iblocks.count); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 0f7fc2d37..64f67698a 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -125,7 +125,8 @@ static void recursively_rewrite_tree(struct basicblock* bb) (ir->opcode == IR_PHI) && array_contains(&needsphis, nextbb)) { - array_appendu(&ir->u.phivalue, definitions.item[definitions.count-1]); + pmap_add(&ir->u.phivalue, + bb, definitions.item[definitions.count-1]); } recursively_rewrite_tree(nextbb); diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 69aba0af8..b6216542a 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -36,6 +36,108 @@ static void print_blocks(char k, struct procedure* proc) } } +static void print_hops(char k, struct procedure* proc) +{ + int i; + + tracef(k, "%c: procedure %s\n", k, proc->name); + for (int i=0; iis_fake ? "FAKE " : "", + bb->name); + + if (bb->prevs.count > 0) + { + tracef(k, "%c: FROM:", k); + for (j=0; jprevs.count; j++) + tracef(k, " %s", bb->prevs.item[j]->name); + tracef(k, "\n"); + } + + if (bb->nexts.count > 0) + { + tracef(k, "%c: TO:", k); + for (j=0; jnexts.count; j++) + tracef(k, " %s", bb->nexts.item[j]->name); + tracef(k, "\n"); + } + + if (bb->liveins.count > 0) + { + tracef(k, "%c: INS:", k); + for (j=0; jliveins.count; j++) + tracef(k, " %%%d", bb->liveins.item[j]->id); + tracef(k, "\n"); + } + + if (bb->liveouts.count > 0) + { + tracef(k, "%c: OUTS:", k); + for (j=0; jliveouts.count; j++) + tracef(k, " %%%d", bb->liveouts.item[j]->id); + tracef(k, "\n"); + } + + if (bb->phis.count > 0) + { + tracef(k, "%c: PHIS:", k); + for (j=0; jphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + + tracef(k, " %%%d(via %s)=>%%%d", + phi->ir->result->id, + phi->prev->name, + vreg->id); + } + tracef(k, "\n"); + } + + for (j=0; jhops.count; j++) + hop_print(k, bb->hops.item[j]); + } +} + +static void write_cfg_graph(const char* name) +{ + int i; + + fprintf(cfg_dot_file, "subgraph %s {\n", name); + fprintf(cfg_dot_file, "\t%s [color=red];\n", cfg.entry->name); + + for (i=0; i %s;\n", + cfg.graph.item[i].left->name, + cfg.graph.item[i].right->name); + } + + fprintf(cfg_dot_file, "}\n"); +} + +static void write_dominance_graph(const char* name) +{ + int i; + + fprintf(dominance_dot_file, "subgraph %s {\n", name); + fprintf(dominance_dot_file, "\t%s [color=green];\n", cfg.entry->name); + + for (i=0; i %s;\n", + dominance.graph.item[i].right->name, + dominance.graph.item[i].left->name); + } + + fprintf(dominance_dot_file, "}\n"); +} + void procedure_compile(struct procedure* proc) { int i; @@ -48,25 +150,31 @@ void procedure_compile(struct procedure* proc) pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); + print_blocks('2', proc); + update_graph_data(proc); + pass_split_critical_edges(proc); update_graph_data(proc); /* Passes from here on can't alter the BB graph without also updating prevs * and nexts (and then calling update_graph_data()). */ - print_blocks('2', proc); - pass_convert_stack_ops(proc); print_blocks('3', proc); - pass_convert_locals_to_ssa(proc); + pass_convert_stack_ops(proc); print_blocks('4', proc); - pass_promote_float_ops(proc); + pass_convert_locals_to_ssa(proc); print_blocks('5', proc); - pass_split_critical_edges(proc); + pass_promote_float_ops(proc); print_blocks('6', proc); - update_graph_data(proc); + pass_instruction_selector(); + pass_live_vreg_analysis(); + print_hops('7', proc); + //pass_register_allocator(); - pass_instruction_selector(proc); - pass_register_allocator(proc); + if (cfg_dot_file) + write_cfg_graph(proc->name); + if (dominance_dot_file) + write_dominance_graph(proc->name); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index 62bbb6900..b901eb667 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -14,6 +14,8 @@ struct hreg struct vreg { int id; + struct hop* defined; + ARRAYOF(struct hop) used; }; extern struct vreg* new_vreg(void); From 9db902314bdaa621457b126b0d54dc577b3a2db1 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 8 Oct 2016 10:21:24 +0200 Subject: [PATCH 081/230] Fix bug where pushes were being placed in the wrong blocks. --- mach/proto/mcg/pass_convertstackops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index d73924d67..64bca0762 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -1,6 +1,6 @@ #include "mcg.h" -static ARRAYOF(struct ir) pops; +static PMAPOF(struct basicblock, struct ir) pops; static PMAPOF(struct basicblock, struct ir) pushes; static struct ir* get_last_push(struct basicblock* bb) @@ -62,7 +62,7 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) ir = get_first_pop(outbb); if (!ir || (ir->size != lastpush->size)) return; - array_appendu(&pops, ir); + pmap_add(&pops, outbb, ir); /* Also abort unless *every* predecessor block of the one we've * just found *also* ends in a push of the same size. */ @@ -93,7 +93,8 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) for (i=0; isize); for (j=0; jroot = phi; *ir = *phi; - array_insert(&bb->irs, ir, 0); } } } From 9ebf731335819eef27c63b5bf342f215f02cc621 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 8 Oct 2016 11:07:28 +0200 Subject: [PATCH 082/230] Minor cleanup. --- mach/proto/mcg/hop.c | 2 +- mach/proto/mcg/pass_instructionselection.c | 2 +- mach/proto/mcg/pass_promotefloatops.c | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index d175147b6..652b9f658 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -103,7 +103,7 @@ void hop_print(char k, struct hop* hop) case IR_LOCAL: case IR_CONST: - tracef(k, "0x%d", ir->u.ivalue); + tracef(k, "%d", ir->u.ivalue); break; } break; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 029cacd4b..4e3edd4da 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -243,6 +243,7 @@ static void select_instructions(void) } else { + ir_print('I', current_ir); shadow = build_shadow_tree(current_ir, current_ir); burm_label(shadow); @@ -250,7 +251,6 @@ static void select_instructions(void) if (!insnno) burm_panic_cannot_match(shadow); - ir_print('I', current_ir); walk_instructions(shadow, 1); } } diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c index 478143b38..7b1d769f1 100644 --- a/mach/proto/mcg/pass_promotefloatops.c +++ b/mach/proto/mcg/pass_promotefloatops.c @@ -97,4 +97,3 @@ void pass_promote_float_ops(struct procedure* proc) } /* vim: set sw=4 ts=4 expandtab : */ - From 2198db69b17cda0864f2aa590cc83415dfa388da Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 8 Oct 2016 11:35:33 +0200 Subject: [PATCH 083/230] Instruction predicates work now. --- mach/proto/mcg/mcgg_generated_header.h | 3 + mach/proto/mcg/powerpc_predicates.c | 19 ++ mach/proto/mcg/table | 280 +++++++++++++++++-------- util/mcgg/iburg.c | 53 +++-- 4 files changed, 251 insertions(+), 104 deletions(-) create mode 100644 mach/proto/mcg/powerpc_predicates.c diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index 8ca4c4b34..47c2bd9e6 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -8,5 +8,8 @@ extern void burm_panic_cannot_match(NODEPTR_TYPE node); +extern bool burm_predicate_constant_signed_16_bit(struct burm_node* node); +extern bool burm_predicate_constant_is_zero(struct burm_node* node); + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/powerpc_predicates.c b/mach/proto/mcg/powerpc_predicates.c new file mode 100644 index 000000000..2748b43d0 --- /dev/null +++ b/mach/proto/mcg/powerpc_predicates.c @@ -0,0 +1,19 @@ +#include "mcg.h" + +bool burm_predicate_constant_signed_16_bit(struct burm_node* node) +{ + struct ir* ir = node->ir; + assert(ir->opcode == IR_CONST); + return (ir->u.ivalue >= -0x8000) && (ir->u.ivalue <= 0x7fff); +} + +bool burm_predicate_constant_is_zero(struct burm_node* node) +{ + struct ir* ir = node->ir; + assert(ir->opcode == IR_CONST); + return (ir->u.ivalue == 0); +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index f3f359f4b..c589101d6 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,38 +1,78 @@ REGISTERS - r0 bytes4 int ret; - r1 bytes4 int; - r2 bytes4 int; - r3 bytes4 int; - r4 bytes4 int; - r5 bytes4 int; - r6 bytes4 int; - r7 bytes4 int; - r8 bytes4 int; - r9 bytes4 int; - r10 bytes4 int; - r11 bytes4 int; + /* Reverse order because registers are assigned from top down. */ - s0 bytes4 float; - s1 bytes4 float; - s2 bytes4 float; - s3 bytes4 float; - s4 bytes4 float; - s5 bytes4 float; - s6 bytes4 float; - s7 bytes4 float; - s8 bytes4 float; - s9 bytes4 float; + r31 bytes4 int; + r30 bytes4 int; + r29 bytes4 int; + r28 bytes4 int; + r27 bytes4 int; + r26 bytes4 int; + r25 bytes4 int; + r24 bytes4 int; + r23 bytes4 int; + r22 bytes4 int; + r21 bytes4 int; + r20 bytes4 int; + r19 bytes4 int; + r18 bytes4 int; + r17 bytes4 int; + r16 bytes4 int; + r15 bytes4 int; + r14 bytes4 int; + r13 bytes4 int; + r12 bytes4 int; + r11 bytes4 int; + r10 bytes4 int; + r9 bytes4 int; + r8 bytes4 int; + r7 bytes4 int; + r6 bytes4 int; + r5 bytes4 int; + r4 bytes4 int; + r3 bytes4 int ret; - cc cc; + f31 bytes4 bytes8 float; + f30 bytes4 bytes8 float; + f29 bytes4 bytes8 float; + f28 bytes4 bytes8 float; + f27 bytes4 bytes8 float; + f26 bytes4 bytes8 float; + f25 bytes4 bytes8 float; + f24 bytes4 bytes8 float; + f23 bytes4 bytes8 float; + f22 bytes4 bytes8 float; + f21 bytes4 bytes8 float; + f20 bytes4 bytes8 float; + f19 bytes4 bytes8 float; + f18 bytes4 bytes8 float; + f17 bytes4 bytes8 float; + f16 bytes4 bytes8 float; + f15 bytes4 bytes8 float; + f14 bytes4 bytes8 float; + f13 bytes4 bytes8 float; + f12 bytes4 bytes8 float; + f11 bytes4 bytes8 float; + f10 bytes4 bytes8 float; + f9 bytes4 bytes8 float; + f8 bytes4 bytes8 float; + f7 bytes4 bytes8 float; + f6 bytes4 bytes8 float; + f5 bytes4 bytes8 float; + f4 bytes4 bytes8 float; + f3 bytes4 bytes8 float; + f2 bytes4 bytes8 float; + f1 bytes4 bytes8 float; + f0 bytes4 bytes8 float; + + cr0 cr; DECLARATIONS - cc; + cr; address fragment; - aluparam fragment; PATTERNS @@ -42,16 +82,23 @@ PATTERNS PAIR(BLOCK4, BLOCK4); + /* Miscellaneous special things */ PUSH4(in:(int)reg) - emit "push %in" + emit "stwu %in, -4(sp)" cost 4; out:(int)reg = POP4 - emit "pop %out" - cost 4; + emit "lwz %out, 0(sp)" + emit "addi sp, sp, 4" + cost 8; + out:(float)reg = POPF4 + emit "lfs %out, 0(sp)" + emit "addi sp, sp, 4" + cost 8; + RET emit "ret" cost 4; @@ -60,58 +107,71 @@ PATTERNS emit "mov r0, %in" cost 4; - STACKADJUST4(delta:aluparam) - emit "add sp, sp, %delta" + (ret)reg = GETRET4 + cost 1; + + STACKADJUST4(delta:CONST4) + when constant_signed_16_bit(delta) + emit "addi sp, sp, $delta" cost 4; + /* Memory operations */ STORE4(addr:address, value:(int)reg) - emit "str %value, %addr" + emit "stw %value, %addr" + cost 4; + + STORE2(addr:address, value:(int)reg) + emit "sth %value, %addr" cost 4; STORE1(addr:address, value:(int)reg) - emit "strb %value, %addr" + emit "stb %value, %addr" cost 4; out:(int)reg = LOAD4(addr:address) - emit "ldr %out, %addr" + emit "lwz %out, %addr" + cost 4; + + out:(int)reg = LOAD2(addr:address) + emit "lhz %out, %addr" cost 4; out:(int)reg = LOAD1(addr:address) - emit "ldrb %out, %addr" + emit "lbz %out, %addr" cost 4; out:(int)reg = CIU14(LOAD1(addr:address)) - emit "ldrb %out, %addr" + emit "lbz %out, %addr" + cost 4; + + out:(int)reg = CIU24(LOAD2(addr:address)) + emit "lhz %out, %addr" cost 4; - out:(int)reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) - emit "ldrsb %out, %addr" - cost 4; /* Locals */ out:(int)reg = in:LOCAL4 - emit "add %out, fp, #$in" + emit "addi %out, fp, #$in" cost 4; address = in:LOCAL4 - emit "[fp, #$in]"; + emit "$in(fp)"; + /* Memory addressing modes */ address = ADD4(addr:(int)reg, offset:CONST4) - emit "[%addr, #$offset]"; - - address = ADD4(addr1:(int)reg, addr2:(int)reg) - emit "[%addr1, %addr2]"; + when constant_signed_16_bit(offset) + emit "$offset(%addr)"; address = addr:(int)reg - emit "[%addr]"; + emit "0(%addr)"; @@ -121,99 +181,153 @@ PATTERNS emit "b $addr" cost 4; - CJUMPEQ(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4)) - emit "beq $true" + CJUMPEQ(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) + emit "bc IFTRUE, EQ, $true" emit "b $false" cost 8; - CJUMPLE(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4)) - emit "ble $true" - emit "b $false" + CJUMPLE(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) + emit "bc IFTRUE, LE, $true" + emit "b $false" cost 8; - CJUMPLT(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4)) - emit "blt $true" - emit "b $false" + CJUMPLT(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) + emit "bc IFTRUE, LT, $true" + emit "b $false" cost 8; CALL(dest:LABEL4) emit "bl $dest" cost 4; + CALL(dest:(int)reg) + emit "mtspr ctr, %dest" + emit "bcctrl ALWAYS, 0, 0" + cost 8; + + JUMP(dest:LABEL4) + emit "b $dest" + cost 4; + + /* Comparisons */ - (cc)cc = COMPARES4(left:(int)reg, right:aluparam) - emit "cmp %left, %right" + cr:(cr)cr = COMPARES4(left:(int)reg, right:(int)reg) + emit "cmp %cr, 0, %left, %right" cost 4; - (cc)cc = COMPARES4(COMPARES4(left:(int)reg, right:aluparam), CONST4) - emit "cmp %left, %right" + cr:(cr)cr = COMPARES4(left:(int)reg, right:CONST4) + when constant_signed_16_bit(right) + emit "cmpi %cr, 0, %left, $right" cost 4; - out:(int)reg = (cc)cc - emit "mov %out, #0" - emit "movlt %out, #-1" - emit "movgt %out, #1" - cost 12; + cr:(cr)cr = COMPAREU4(left:(int)reg, right:(int)reg) + emit "cmpl %cr, 0, %left, %right" + cost 4; + + cr:(cr)cr = COMPAREU4(left:(int)reg, right:CONST4) + when constant_signed_16_bit(right) + emit "cmpli %cr, 0, %left, $right" + cost 4; + + cr:(cr)cr = COMPARES4(COMPARES4(left:(int)reg, right:(int)reg), result:CONST4) + when constant_is_zero(result) + emit "cmp %cr, 0, %left, %right" + cost 4; + + cr:(cr)cr = COMPARES4(COMPARES4(left:(int)reg, right:CONST4), result:CONST4) + when constant_is_zero(result) + when constant_signed_16_bit(right) + emit "cmpi %cr, 0, %left, $right" + cost 4; + + cr:(cr)cr = COMPARES4(COMPAREU4(left:(int)reg, right:(int)reg), result:CONST4) + when constant_is_zero(result) + emit "cmpl %cr, 0, %left, %right" + cost 4; + /* Conversions */ out:(int)reg = CII14(CIU41(value:(int)reg)) - emit "sxtb %out, %value" + emit "extsb %out, %value" + cost 4; + + out:(int)reg = CII24(CIU42(value:(int)reg)) + emit "extsh %out, %value" cost 4; out:(int)reg = CIU41(in:(int)reg) - emit "and %out, %in, #0xff" + emit "andi %out, %in, 0xff" cost 4; + out:(int)reg = CIU42(in:(int)reg) + emit "andi %out, %in, 0xffff" + cost 4; + + out:(int)reg = CIU44(in:(int)reg) + emit "mr %out, %in" + cost 4; + + /* ALU operations */ - out:(int)reg = ADD4(left:(int)reg, right:aluparam) + out:(int)reg = ADD4(left:(int)reg, right:(int)reg) emit "add %out, %left, %right" cost 4; - out:(int)reg = ADD4(left:aluparam, right:(int)reg) - emit "add %out, %right, %left" + out:(int)reg = ADD4(left:(int)reg, right:CONST4) + when constant_signed_16_bit(right) + emit "addi %out, %left, $right" + cost 4; + + out:(int)reg = SUB4(left:(int)reg, right:(int)reg) + emit "sub %out, %right, %left" + cost 4; + + out:(int)reg = MUL4(left:(int)reg, right:(int)reg) + emit "mullw %out, %right, %left" cost 4; out:(int)reg = MOD4(left:(int)reg, right:(int)reg) - emit "udiv %out, %left, %right" - emit "mls %out, %out, %right, %left" - cost 8; + emit "divw %out, %left, %right" + emit "mullw %out, %out, %right" + emit "subf %out, %out, %left" + cost 12; - out:(int)reg = DIV4(left:(int)reg, right:aluparam) - emit "div %out, %left, %right" + out:(int)reg = DIV4(left:(int)reg, right:(int)reg) + emit "divw %out, %left, %right" cost 4; - aluparam = value:CONST4 - emit "#$value"; + out:(int)reg = NEG4(left:(int)reg) + emit "neg %out, %left" + cost 4; - aluparam = value:(int)reg - emit "%value"; - - out:(int)reg = value:aluparam - emit "mov %out, %value" + out:(int)reg = EOR4(left:(int)reg, right:(int)reg) + emit "xor %out, %right, %left" cost 4; out:(int)reg = value:LABEL4 - emit "adr %out, $value" + emit "la %out, $value" cost 4; out:(int)reg = value:BLOCK4 - emit "adr %out, $value" + emit "la %out, $value" cost 4; out:(int)reg = value:CONST4 - emit "ldr %out, address-containing-$value" + emit "la %out, $value" cost 8; out:(int)reg = value:CONSTF4 - emit "vldr %out, address-containing-$value" + emit "lfs %out, address-containing-$value" cost 8; + + /* FPU operations */ out:(float)reg = ADDF4(left:(float)reg, right:(float)reg) diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 5683b6cc4..550011140 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -1000,6 +1000,31 @@ static bool find_child_index(Tree node, const char* name, int* index, Tree* foun return false; } +static void emit_predicate_expr(Rule r, struct expr* p) +{ + bool first = true; + + print("%1if (%Ppredicate_%s(", p->name); + + p = p->next; + while (p) + { + uint32_t path = find_label(r->pattern, p->name, 0, NULL); + if (path == PATH_MISSING) + label_not_found(r, p->name); + + if (!first) + print(", "); + else + first = false; + + print_path(path); + p = p->next; + } + + print("))"); +} + /* emitpredicates - emit predicates for rules */ static void emitpredicatedefinitions(Rule r) { @@ -1012,28 +1037,14 @@ static void emitpredicatedefinitions(Rule r) for (i=0; iprefers.count; i++) { - struct expr* p = r->prefers.item[i]; - bool first = true; + emit_predicate_expr(r, r->prefers.item[i]); + print(" cost -= 1;\n"); + } - print("%1if (%Ppredicate_%s(", p->name); - - p = p->next; - while (p) - { - uint32_t path = find_label(r->pattern, p->name, 0, NULL); - if (path == PATH_MISSING) - label_not_found(r, p->name); - - if (!first) - print(", "); - else - first = false; - - print_path(path); - p = p->next; - } - - print(")) cost -= 1;\n"); + for (i=0; irequires.count; i++) + { + emit_predicate_expr(r, r->requires.item[i]); + print(" {} else return %d;\n", maxcost); } print("%1if (cost > %d) return %d;\n", maxcost, maxcost); From 637aeed70a37a1293ca102f1f684d1f98a9934fc Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 8 Oct 2016 12:15:21 +0200 Subject: [PATCH 084/230] Only allocate an output vreg if the instruction actually wants one. --- mach/proto/mcg/pass_instructionselection.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 4e3edd4da..db5280280 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -88,6 +88,13 @@ static void constrain_input_reg(int child, int attr) static void constrain_output_reg(int attr) { + struct vreg* vreg = current_hop->output; + + if (!vreg) + current_hop->output = vreg = new_vreg(); + + array_appendu(¤t_hop->outs, vreg); + vreg->defined = current_hop; } static const struct burm_emitter_data emitter_data = @@ -161,22 +168,12 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) case ir_to_esn(IR_NOP, 0): vreg = node->left->ir->result; break; - - default: - /* FIXME: some instructions don't emit anything, so - * allocating a register for them is a waste of time. */ - vreg = new_vreg(); } insn->hop = current_hop = new_hop(current_bb, insn->ir); - insn->hop->output = vreg; - if (vreg) - { - array_appendu(¤t_hop->outs, vreg); - vreg->defined = current_hop; - } - + current_hop->output = vreg; emit(insn); + hop_print('I', current_hop); array_append(¤t_bb->hops, current_hop); From 4261744537e9d6bd356bf5d2b0e1f2882ed863de Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 8 Oct 2016 23:32:13 +0200 Subject: [PATCH 085/230] Replace pmap_get() with pmap_findleft() and pmap_findright(), to allow lookups in both directions. --- modules/src/data/pmap.c | 17 ++++++++++++++++- modules/src/data/pmap.h | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/src/data/pmap.c b/modules/src/data/pmap.c index 9ed2d9fed..ae62af3c6 100644 --- a/modules/src/data/pmap.c +++ b/modules/src/data/pmap.c @@ -56,7 +56,7 @@ void pmap_add(void* mapp, void* left, void* right) append(map, left, right); } -void* pmap_get(void* mapp, void* left) +void* pmap_findleft(void* mapp, void* left) { struct pmap* map = mapp; int i; @@ -71,4 +71,19 @@ void* pmap_get(void* mapp, void* left) return NULL; } +void* pmap_findright(void* mapp, void* right) +{ + struct pmap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct pmap_node* node = &map->item[i]; + if (node->right == right) + return node->left; + } + + return NULL; +} + diff --git a/modules/src/data/pmap.h b/modules/src/data/pmap.h index 19986fc12..8c06ec605 100644 --- a/modules/src/data/pmap.h +++ b/modules/src/data/pmap.h @@ -25,7 +25,8 @@ struct pmap extern void pmap_put(void* map, void* left, void* right); extern void pmap_add(void* map, void* left, void* right); -extern void* pmap_get(void* map, void* left); +extern void* pmap_findleft(void* map, void* left); +extern void* pmap_findright(void* map, void* right); #endif From d75cc0a66317060772b79c7e71100a964f6f0430 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 8 Oct 2016 23:32:54 +0200 Subject: [PATCH 086/230] Basic register allocation works! --- mach/proto/mcg/basicblock.h | 6 + mach/proto/mcg/graph.c | 10 +- mach/proto/mcg/hop.c | 11 +- mach/proto/mcg/hop.h | 3 +- mach/proto/mcg/mcg.h | 2 +- mach/proto/mcg/pass_registerallocator.c | 169 ++++++++++++++++++++++++ mach/proto/mcg/pass_ssa.c | 6 +- mach/proto/mcg/procedure.c | 6 +- mach/proto/mcg/reg.c | 2 +- mach/proto/mcg/reg.h | 4 +- mach/proto/mcg/table | 2 +- 11 files changed, 205 insertions(+), 16 deletions(-) diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h index 4c65721e4..323fa4dd5 100644 --- a/mach/proto/mcg/basicblock.h +++ b/mach/proto/mcg/basicblock.h @@ -24,6 +24,12 @@ struct basicblock ARRAYOF(struct vreg) liveins; ARRAYOF(struct vreg) liveouts; + /* Register assignments on entry and exit. These are *pointers* (because + * they just point to the regsin/regsout of the first and last hop + * respectively). */ + register_assignment_t* regsin; + register_assignment_t* regsout; + bool is_fake : 1; bool is_root : 1; bool is_terminated : 1; diff --git a/mach/proto/mcg/graph.c b/mach/proto/mcg/graph.c index 9c976735b..395b7bfca 100644 --- a/mach/proto/mcg/graph.c +++ b/mach/proto/mcg/graph.c @@ -87,10 +87,10 @@ static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2 while (p1 != p2) { while (p1->order < p2->order) - p1 = pmap_get(&dominance.graph, p1); + p1 = pmap_findleft(&dominance.graph, p1); while (p2->order < p1->order) - p2 = pmap_get(&dominance.graph, p2); + p2 = pmap_findleft(&dominance.graph, p2); } return p1; @@ -129,16 +129,16 @@ static void calculate_dominance_graph(void) struct basicblock* p = b->prevs.item[j]; /* Skip unprocessed blocks. */ - if (!pmap_get(&dominance.graph, p)) + if (!pmap_findleft(&dominance.graph, p)) continue; if (!new_idom) new_idom = p; - else if (pmap_get(&dominance.graph, p)) + else if (pmap_findleft(&dominance.graph, p)) new_idom = intersect(p, new_idom); } - if (pmap_get(&dominance.graph, b) != new_idom) + if (pmap_findleft(&dominance.graph, b) != new_idom) { pmap_put(&dominance.graph, b, new_idom); changed = true; diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 652b9f658..d0a2dfcf3 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -81,8 +81,17 @@ void hop_print(char k, struct hop* hop) break; case INSEL_VREG: - tracef(k, "%%%d", insel->u.vreg->id); + { + struct vreg* vreg = insel->u.vreg; + struct hreg* hreg = pmap_findright(&hop->regsin, vreg); + if (!hreg) + hreg = pmap_findright(&hop->regsout, vreg); + if (hreg) + tracef(k, "%s", hreg->name); + else + tracef(k, "%%%d", vreg->id); break; + } case INSEL_STRING: tracef(k, "%s", insel->u.string); diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 18e70d3b4..16a39f734 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -32,7 +32,8 @@ struct hop ARRAYOF(struct vreg) ins; ARRAYOF(struct vreg) outs; ARRAYOF(struct vreg) throughs; - PMAPOF(struct vreg, struct hreg) registers; + register_assignment_t regsin; + register_assignment_t regsout; }; extern struct hop* new_hop(struct basicblock* bb, struct ir* ir); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index f4e33f2af..a90bbb5ef 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -23,8 +23,8 @@ #include "astring.h" #include "ir.h" #include "mcgg.h" -#include "hop.h" #include "reg.h" +#include "hop.h" #include "basicblock.h" #include "procedure.h" #include "graph.h" diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index e7cf1d7dd..bb22a4d43 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -1,7 +1,176 @@ #include "mcg.h" +static ARRAYOF(struct hreg) hregs; +static int stacksize; + +static void populate_hregs(void) +{ + const struct burm_register_data* brd = burm_register_data; + + stacksize = 0; + while (brd->name) + { + array_append(&hregs, new_hreg(brd)); + brd++; + } +} + +static void wire_up_blocks_ins_outs(void) +{ + int i, j; + + for (i=0; ihops.count >= 1); + bb->regsin = &bb->hops.item[0]->regsin; + bb->regsout = &bb->hops.item[bb->hops.count-1]->regsout; + } +} + +static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg) +{ + int i; + + for (i=0; ithroughs.count; i++) + { + struct vreg* vreg = hop->throughs.item[i]; + struct hreg* hreg = pmap_findright(old, vreg); + assert(hreg != NULL); + + pmap_put(in, hreg, vreg); + pmap_put(out, hreg, vreg); + } + + /* Any registers being *read* by the instruction should also stay where + * they are. (This is likely to duplicate some throughs.) */ + + for (i=0; iins.count; i++) + { + struct vreg* vreg = hop->ins.item[i]; + struct hreg* hreg = pmap_findright(old, vreg); + assert(hreg != NULL); + + pmap_put(in, hreg, vreg); + } + + /* Any output registers will be *new* vregs (because SSA). So, allocate + * new hregs for them. */ + + for (i=0; iouts.count; i++) + { + struct vreg* vreg = hop->outs.item[i]; + allocate_hreg(out, vreg); + } +} + void pass_register_allocator(void) { + int i, j, k; + + populate_hregs(); + wire_up_blocks_ins_outs(); + + for (i=0; iregsin; + + tracef('R', "R: allocating block %s\n", bb->name); + + /* Attempt to import any block input registers from a predecessor. At + * least one predecessor should export it; our graph traversal order + * guarantees it. */ + + for (j=0; jliveins.count; j++) + { + struct vreg* vreg = bb->liveins.item[j]; + for (k=0; kprevs.count; k++) + { + struct basicblock* prevbb = bb->prevs.item[k]; + struct hreg* hreg = pmap_findright(prevbb->regsout, vreg); + if (hreg) + { + tracef('R', "R: import hreg %s for input %%%d from %s\n", + hreg->name, vreg->id, prevbb->name); + assert(!pmap_findleft(old, hreg)); + pmap_put(old, hreg, vreg); + goto nextvreg; + } + } + + fatal("couldn't find a register assignment for $%d", vreg->id); + nextvreg:; + } + + /* And now do the same for the phis. Unlike input vregs, a phi can + * import a vreg from multiple locations. However, we don't care which + * one we find, as this is just a hint. Picking the same register as a + * predecessor helps reduce the number of copies the SSA deconstruction + * pass will need to insert. */ + + for (j=0; jphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + if (!pmap_findright(old, vreg)) + { + /* This variable isn't allocated yet. */ + + struct hreg* hreg = pmap_findright( + phi->prev->regsout, phi->ir->result); + if (hreg && !pmap_findleft(old, hreg)) + { + tracef('R', "R: import hreg %s for phi input %%%d from %s\n", + hreg->name, vreg->id, phi->prev->name); + pmap_put(old, hreg, vreg); + } + } + } + + /* It's possible for the previous stage to fail because in in has + * clobbered the physical register we were wanting. So we need to + * allocate a new register for that phi value. */ + + for (j=0; jphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + if (!pmap_findright(old, vreg)) + allocate_hreg(old, vreg); + } + + for (j=0; jhops.count; j++) + { + struct hop* hop = bb->hops.item[j]; + register_assignment_t* in = &hop->regsin; + register_assignment_t* out = &hop->regsout;; + + select_registers(hop, old, in, out); + + old = out; + } + } } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 64f67698a..9bf2d777b 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -26,7 +26,7 @@ static void calculate_dominance_frontier_graph(void) for (i=0; iprevs.count >= 2) { for (j=0; jprevs.count; j++) @@ -37,7 +37,7 @@ static void calculate_dominance_frontier_graph(void) tracef('S', "S: %s is in %s's dominance frontier\n", b->name, runner->name); pmap_add(&dominancefrontiers, runner, b); - runner = pmap_get(&dominance.graph, runner); + runner = pmap_findleft(&dominance.graph, runner); } } } @@ -187,7 +187,7 @@ static void ssa_convert(void) for (i=0; iname); diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c index c4cf71058..848c1cd98 100644 --- a/mach/proto/mcg/reg.c +++ b/mach/proto/mcg/reg.c @@ -9,7 +9,7 @@ struct vreg* new_vreg(void) return vreg; } -struct hreg* new_hreg(struct burm_register_data* brd) +struct hreg* new_hreg(const struct burm_register_data* brd) { struct hreg* hreg = calloc(1, sizeof *hreg); hreg->name = brd->name; diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index b901eb667..743b9c3e5 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -18,9 +18,11 @@ struct vreg ARRAYOF(struct hop) used; }; +typedef PMAPOF(struct hreg, struct vreg) register_assignment_t; + extern struct vreg* new_vreg(void); -extern struct hreg* new_hreg(struct burm_register_data* brd); +extern struct hreg* new_hreg(const struct burm_register_data* brd); extern struct hreg* new_stacked_hreg(int offset, uint32_t attrs); #endif diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index c589101d6..932172480 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -104,7 +104,7 @@ PATTERNS cost 4; SETRET4(in:(ret)reg) - emit "mov r0, %in" + emit "mr r3, %in" cost 4; (ret)reg = GETRET4 From cfe5312fccc8d3b71013c1e932fc4d4d4b7a43ea Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 9 Oct 2016 12:32:36 +0200 Subject: [PATCH 087/230] Predicates can now take numeric arguments. The PowerPC predicates have been turned into generic ones (as they'll be useful everywhere). Node arguments for predicates require the '%' prefix for consistency. Hex numbers are permitted. --- mach/proto/mcg/mcgg_generated_header.h | 5 ++-- mach/proto/mcg/powerpc_predicates.c | 19 --------------- mach/proto/mcg/predicates.c | 32 ++++++++++++++++++++++++++ mach/proto/mcg/table | 18 +++++++-------- util/mcgg/build.lua | 1 + util/mcgg/gram.y | 27 +++++++++++++++------- util/mcgg/iburg.c | 27 +++++++++++++++++----- util/mcgg/iburg.h | 15 +++++++++++- util/mcgg/scan.l | 3 ++- 9 files changed, 101 insertions(+), 46 deletions(-) delete mode 100644 mach/proto/mcg/powerpc_predicates.c create mode 100644 mach/proto/mcg/predicates.c diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index 47c2bd9e6..5d9b3ae2e 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -8,8 +8,9 @@ extern void burm_panic_cannot_match(NODEPTR_TYPE node); -extern bool burm_predicate_constant_signed_16_bit(struct burm_node* node); -extern bool burm_predicate_constant_is_zero(struct burm_node* node); +extern bool burm_predicate_signed_constant(struct burm_node* node, arith size); +extern bool burm_predicate_unsigned_constant(struct burm_node* node, arith size); +extern bool burm_predicate_specific_constant(struct burm_node* node, arith value); /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/powerpc_predicates.c b/mach/proto/mcg/powerpc_predicates.c deleted file mode 100644 index 2748b43d0..000000000 --- a/mach/proto/mcg/powerpc_predicates.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "mcg.h" - -bool burm_predicate_constant_signed_16_bit(struct burm_node* node) -{ - struct ir* ir = node->ir; - assert(ir->opcode == IR_CONST); - return (ir->u.ivalue >= -0x8000) && (ir->u.ivalue <= 0x7fff); -} - -bool burm_predicate_constant_is_zero(struct burm_node* node) -{ - struct ir* ir = node->ir; - assert(ir->opcode == IR_CONST); - return (ir->u.ivalue == 0); -} - -/* vim: set sw=4 ts=4 expandtab : */ - - diff --git a/mach/proto/mcg/predicates.c b/mach/proto/mcg/predicates.c new file mode 100644 index 000000000..427a59836 --- /dev/null +++ b/mach/proto/mcg/predicates.c @@ -0,0 +1,32 @@ +#include "mcg.h" + +bool burm_predicate_signed_constant(struct burm_node* node, arith size) +{ + struct ir* ir = node->ir; + arith pivot = 1<<(size-1); + arith mask = ~((1<opcode == IR_CONST); + + return ((ir->u.ivalue + pivot) & mask) == 0; +} + +bool burm_predicate_unsigned_constant(struct burm_node* node, arith size) +{ + struct ir* ir = node->ir; + arith mask = ~((1<opcode == IR_CONST); + + return (ir->u.ivalue & mask) == 0; +} + +bool burm_predicate_specific_constant(struct burm_node* node, arith val) +{ + struct ir* ir = node->ir; + assert(ir->opcode == IR_CONST); + + return ir->u.ivalue == val; +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 932172480..e19f56d07 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -111,7 +111,7 @@ PATTERNS cost 1; STACKADJUST4(delta:CONST4) - when constant_signed_16_bit(delta) + when signed_constant(%delta, 16) emit "addi sp, sp, $delta" cost 4; @@ -167,7 +167,7 @@ PATTERNS /* Memory addressing modes */ address = ADD4(addr:(int)reg, offset:CONST4) - when constant_signed_16_bit(offset) + when signed_constant(%offset, 16) emit "$offset(%addr)"; address = addr:(int)reg @@ -218,7 +218,7 @@ PATTERNS cost 4; cr:(cr)cr = COMPARES4(left:(int)reg, right:CONST4) - when constant_signed_16_bit(right) + when signed_constant(%right, 16) emit "cmpi %cr, 0, %left, $right" cost 4; @@ -227,23 +227,23 @@ PATTERNS cost 4; cr:(cr)cr = COMPAREU4(left:(int)reg, right:CONST4) - when constant_signed_16_bit(right) + when signed_constant(%right, 16) emit "cmpli %cr, 0, %left, $right" cost 4; cr:(cr)cr = COMPARES4(COMPARES4(left:(int)reg, right:(int)reg), result:CONST4) - when constant_is_zero(result) + when specific_constant(%result, 0) emit "cmp %cr, 0, %left, %right" cost 4; cr:(cr)cr = COMPARES4(COMPARES4(left:(int)reg, right:CONST4), result:CONST4) - when constant_is_zero(result) - when constant_signed_16_bit(right) + when specific_constant(%result, 0) + when signed_constant(%right, 16) emit "cmpi %cr, 0, %left, $right" cost 4; cr:(cr)cr = COMPARES4(COMPAREU4(left:(int)reg, right:(int)reg), result:CONST4) - when constant_is_zero(result) + when specific_constant(%result, 0) emit "cmpl %cr, 0, %left, %right" cost 4; @@ -280,7 +280,7 @@ PATTERNS cost 4; out:(int)reg = ADD4(left:(int)reg, right:CONST4) - when constant_signed_16_bit(right) + when signed_constant(%right, 16) emit "addi %out, %left, $right" cost 4; diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index 83d800eaf..aa575667a 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -50,6 +50,7 @@ cprogram { "+lib", "+yacc", "modules/src/data+lib", + "modules+headers", } } diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 30c61cb4c..74c0c0502 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -13,8 +13,8 @@ extern int yylex(void); %} %union { - int n; - char* string; + arith n; + const char* string; Nonterm nonterm; Tree tree; Rule rule; @@ -44,16 +44,17 @@ extern int yylex(void); %type constraint %type constraints +%type predicate +%type predicate_arg +%type predicate_args %type declaration %type register +%type pattern %type pattern_constraints %type pattern_emit -%type pattern %type qfragments %type terminfo %type rhs -%type predicate -%type predicate_args %% spec @@ -155,13 +156,23 @@ qfragments ; predicate - : ID '(' predicate_args ')' { $$ = calloc(1, sizeof *$$); $$->name = $1; $$->next = $3; } + : ID '(' predicate_args ')' { + $$ = calloc(1, sizeof *$$); + $$->type = PREDICATE_FUNCTION; + $$->u.name = $1; + $$->next = $3; + } ; predicate_args : /* nothing */ { $$ = NULL; } - | ID { $$ = calloc(1, sizeof *$$); $$->name = $1; } - | ID ',' predicate_args { $$ = calloc(1, sizeof *$$); $$->name = $1; $$->next = $3; } + | predicate_arg { $$ = $1; } + | predicate_arg ',' predicate_args { $$ = $1; $$->next = $3; } + ; + +predicate_arg + : '%' ID { $$ = calloc(1, sizeof *$$); $$->type = PREDICATE_NODE; $$->u.name = $2; } + | INT { $$ = calloc(1, sizeof *$$); $$->type = PREDICATE_NUMBER; $$->u.number = $1; } ; %% diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 550011140..c93a1b373 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -1004,21 +1004,36 @@ static void emit_predicate_expr(Rule r, struct expr* p) { bool first = true; - print("%1if (%Ppredicate_%s(", p->name); + assert(p->type == PREDICATE_FUNCTION); + print("%1if (%Ppredicate_%s(", p->u.name); p = p->next; while (p) { - uint32_t path = find_label(r->pattern, p->name, 0, NULL); - if (path == PATH_MISSING) - label_not_found(r, p->name); - if (!first) print(", "); else first = false; - print_path(path); + switch (p->type) + { + case PREDICATE_NODE: + { + uint32_t path = find_label(r->pattern, p->u.name, 0, NULL); + if (path == PATH_MISSING) + label_not_found(r, p->u.name); + + print_path(path); + break; + } + + case PREDICATE_NUMBER: + { + print("%d", p->u.number); + break; + } + } + p = p->next; } diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 48981722b..d9d69b8c6 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -1,6 +1,7 @@ #ifndef BURG_INCLUDED #define BURG_INCLUDED +#include "em_arith.h" #include "stringlist.h" #include "array.h" @@ -31,10 +32,22 @@ struct constraint struct constraint* next; }; +enum +{ + PREDICATE_FUNCTION, + PREDICATE_NODE, + PREDICATE_NUMBER +}; + struct expr { - const char* name; + int type; struct expr* next; + union + { + const char* name; + arith number; + } u; }; struct terminfo diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 6bd50d294..68de96ed4 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -50,7 +50,8 @@ static int braces = 0; "//"[^\n]*\n ; [A-Za-z_][A-Za-z0-9_]* { yylval.string = strdup(yytext); return ID; } -[0-9]+ { yylval.n = atoi(yytext); return INT; } +-?[0-9]+ { yylval.n = atoi(yytext); return INT; } +-?0x[0-9a-fA-F]+ { yylval.n = strtol(yytext, NULL, 0); return INT; } [ \t\r\n]* ; . return yytext[0]; From 36cddd6afba6afc0d7be79bf2f46ae6637a087e5 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 9 Oct 2016 14:45:13 +0200 Subject: [PATCH 088/230] Add some more opcodes; rearrange the registers to be more PowerPC-friendly. --- mach/proto/mcg/table | 102 ++++++++++++++++++----------------- mach/proto/mcg/treebuilder.c | 29 ++++++++++ 2 files changed, 83 insertions(+), 48 deletions(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index e19f56d07..953b4e704 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,6 +1,18 @@ REGISTERS - /* Reverse order because registers are assigned from top down. */ + /* Registers are allocated top down; the order here is odd in order to make + * sure that non-volatile registers get allocated from r31 (or f31) down. */ + + r12 bytes4 int volatile; + r11 bytes4 int volatile; + r10 bytes4 int volatile; + r9 bytes4 int volatile; + r8 bytes4 int volatile; + r7 bytes4 int volatile; + r6 bytes4 int volatile; + r5 bytes4 int volatile; + r4 bytes4 int volatile; + r3 bytes4 int ret volatile; r31 bytes4 int; r30 bytes4 int; @@ -17,55 +29,45 @@ REGISTERS r19 bytes4 int; r18 bytes4 int; r17 bytes4 int; - r16 bytes4 int; - r15 bytes4 int; - r14 bytes4 int; - r13 bytes4 int; - r12 bytes4 int; - r11 bytes4 int; - r10 bytes4 int; - r9 bytes4 int; - r8 bytes4 int; - r7 bytes4 int; - r6 bytes4 int; - r5 bytes4 int; - r4 bytes4 int; - r3 bytes4 int ret; + r16 bytes4 int; + r15 bytes4 int; + r14 bytes4 int; - f31 bytes4 bytes8 float; - f30 bytes4 bytes8 float; - f29 bytes4 bytes8 float; - f28 bytes4 bytes8 float; - f27 bytes4 bytes8 float; - f26 bytes4 bytes8 float; - f25 bytes4 bytes8 float; - f24 bytes4 bytes8 float; - f23 bytes4 bytes8 float; - f22 bytes4 bytes8 float; - f21 bytes4 bytes8 float; - f20 bytes4 bytes8 float; - f19 bytes4 bytes8 float; - f18 bytes4 bytes8 float; - f17 bytes4 bytes8 float; - f16 bytes4 bytes8 float; - f15 bytes4 bytes8 float; - f14 bytes4 bytes8 float; - f13 bytes4 bytes8 float; - f12 bytes4 bytes8 float; - f11 bytes4 bytes8 float; - f10 bytes4 bytes8 float; - f9 bytes4 bytes8 float; - f8 bytes4 bytes8 float; - f7 bytes4 bytes8 float; - f6 bytes4 bytes8 float; - f5 bytes4 bytes8 float; - f4 bytes4 bytes8 float; - f3 bytes4 bytes8 float; - f2 bytes4 bytes8 float; - f1 bytes4 bytes8 float; - f0 bytes4 bytes8 float; + f14 bytes4 float volatile; + f13 bytes4 float volatile; + f12 bytes4 float volatile; + f11 bytes4 float volatile; + f10 bytes4 float volatile; + f9 bytes4 float volatile; + f8 bytes4 float volatile; + f7 bytes4 float volatile; + f6 bytes4 float volatile; + f5 bytes4 float volatile; + f4 bytes4 float volatile; + f3 bytes4 float volatile; + f2 bytes4 float volatile; + f1 bytes4 float volatile; + f0 bytes4 float volatile; - cr0 cr; + f31 bytes4 float; + f30 bytes4 float; + f29 bytes4 float; + f28 bytes4 float; + f27 bytes4 float; + f26 bytes4 float; + f25 bytes4 float; + f24 bytes4 float; + f23 bytes4 float; + f22 bytes4 float; + f21 bytes4 float; + f20 bytes4 float; + f19 bytes4 float; + f18 bytes4 float; + f17 bytes4 float; + f16 bytes4 float; + f15 bytes4 float; + + cr0 cr; DECLARATIONS @@ -302,6 +304,10 @@ PATTERNS emit "divw %out, %left, %right" cost 4; + out:(int)reg = ASL4(left:(int)reg, right:(int)reg) + emit "slw %out, %left, %right" + cost 4; + out:(int)reg = NEG4(left:(int)reg) emit "neg %out, %left" cost 4; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 5e9ee1233..8039b3449 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -376,6 +376,10 @@ static void insn_ivalue(int opcode, arith value) case op_mli: simple_alu2(opcode, value, IR_MUL); break; case op_dvi: simple_alu2(opcode, value, IR_DIV); break; case op_rmi: simple_alu2(opcode, value, IR_MOD); break; + case op_sli: simple_alu2(opcode, value, IR_ASL); break; + case op_sri: simple_alu2(opcode, value, IR_ASR); break; + case op_slu: simple_alu2(opcode, value, IR_LSL); break; + case op_sru: simple_alu2(opcode, value, IR_LSR); break; case op_ngi: simple_alu1(opcode, value, IR_NEG); break; case op_and: simple_alu2(opcode, value, IR_AND); break; @@ -414,6 +418,31 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_lil: + push( + new_ir1( + IR_LOAD, EM_wordsize, + new_ir1( + IR_LOAD, EM_wordsize, + new_localir(value) + ) + ) + ); + break; + + case op_sil: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + new_ir1( + IR_LOAD, EM_wordsize, + new_localir(value) + ), + pop(EM_wordsize) + ) + ); + break; + case op_inl: change_by(new_localir(value), 1); break; From 38de688c5ad0c9ea7c1de2224c3f33d93bdbb588 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 9 Oct 2016 15:08:03 +0200 Subject: [PATCH 089/230] Floating point promotion was broken since the IR float change. Fix. --- mach/proto/mcg/pass_promotefloatops.c | 12 +++++------- mach/proto/mcg/table | 14 +++++++++----- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c index 7b1d769f1..1fdff6f4a 100644 --- a/mach/proto/mcg/pass_promotefloatops.c +++ b/mach/proto/mcg/pass_promotefloatops.c @@ -41,14 +41,12 @@ static void promote(struct ir* ir) break; case IR_PHI: - if (!array_appendu(&promotable, ir)) - { - if (ir->left) - promote(ir->left); - if (ir->right) - promote(ir->right); - } + { + int i; + for (i=0; iu.phivalue.count; i++) + array_appendu(&promotable, ir->u.phivalue.item[i].right); break; + } } } diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 953b4e704..4a853a642 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -328,17 +328,21 @@ PATTERNS emit "la %out, $value" cost 8; - out:(int)reg = value:CONSTF4 - emit "lfs %out, address-containing-$value" - cost 8; - - /* FPU operations */ + out:(float)reg = value:CONSTF4 + emit "lfs %out, address-containing-$value" + cost 8; + out:(float)reg = ADDF4(left:(float)reg, right:(float)reg) emit "fadds %out, %left, %right" cost 4; + out:(float)reg = SUBF4(left:(float)reg, right:(float)reg) + emit "fsubs %out, %left, %right" + cost 4; + + /* vim: set sw=4 ts=4 expandtab : */ From 23c3575f0fbe998bd2ac31db13d653ce43d6997a Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 9 Oct 2016 15:09:34 +0200 Subject: [PATCH 090/230] The register allocator now makes a spirited attempt to honour register attributes when allocating. Unfortunately, backward edges don't work (because the limited def-use chain stuff doesn't work across basic blocks). Needs more thought. --- mach/proto/mcg/hop.h | 7 ++++ mach/proto/mcg/pass_instructionselection.c | 20 +++++++++-- mach/proto/mcg/pass_registerallocator.c | 41 +++++++++++++++++----- util/mcgg/iburg.c | 17 +++++---- util/mcgg/iburg.h | 2 +- util/mcgg/ir.dat | 4 +++ util/mcgg/mcgg.h | 4 +-- 7 files changed, 75 insertions(+), 20 deletions(-) diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 16a39f734..4e7868c9a 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -21,6 +21,11 @@ struct insel u; }; +struct constraint +{ + uint32_t attrs; +}; + struct hop { int id; @@ -29,6 +34,8 @@ struct hop ARRAYOF(struct insel) insels; struct vreg* output; + PMAPOF(struct vreg, struct constraint) constraints; + ARRAYOF(struct vreg) ins; ARRAYOF(struct vreg) outs; ARRAYOF(struct vreg) throughs; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index db5280280..6ab678ac9 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -78,15 +78,29 @@ static void emit_eoi(void) hop_add_eoi_insel(current_hop); } -static void constrain_input_reg(int child, int attr) +static struct constraint* get_constraint(struct vreg* vreg) +{ + struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + if (!c) + { + c = calloc(1, sizeof(*c)); + pmap_put(¤t_hop->constraints, vreg, c); + } + return c; +} + +static void constrain_input_reg(int child, uint32_t attr) { struct vreg* vreg = find_vreg_of_child(child); + struct constraint* c; if (vreg) array_appendu(¤t_hop->ins, vreg); + + get_constraint(vreg)->attrs = attr; } -static void constrain_output_reg(int attr) +static void constrain_output_reg(uint32_t attr) { struct vreg* vreg = current_hop->output; @@ -95,6 +109,8 @@ static void constrain_output_reg(int attr) array_appendu(¤t_hop->outs, vreg); vreg->defined = current_hop; + + get_constraint(vreg)->attrs = attr; } static const struct burm_emitter_data emitter_data = diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index bb22a4d43..0bacdd225 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -28,7 +28,7 @@ static void wire_up_blocks_ins_outs(void) } } -static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg) +static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg, uint32_t attr) { int i; @@ -37,8 +37,11 @@ static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg struct hreg* hreg = hregs.item[i]; if (!pmap_findleft(regs, hreg)) { - pmap_put(regs, hreg, vreg); - return hreg; + if (hreg->attrs & attr) + { + pmap_put(regs, hreg, vreg); + return hreg; + } } } @@ -81,7 +84,8 @@ static void select_registers(struct hop* hop, for (i=0; iouts.count; i++) { struct vreg* vreg = hop->outs.item[i]; - allocate_hreg(out, vreg); + struct constraint* c = pmap_findleft(&hop->constraints, vreg); + allocate_hreg(out, vreg, c->attrs); } } @@ -97,7 +101,7 @@ void pass_register_allocator(void) struct basicblock* bb = dominance.preorder.item[i]; register_assignment_t* old = bb->regsin; - tracef('R', "R: allocating block %s\n", bb->name); + tracef('R', "R: considering block %s\n", bb->name); /* Attempt to import any block input registers from a predecessor. At * least one predecessor should export it; our graph traversal order @@ -151,21 +155,42 @@ void pass_register_allocator(void) /* It's possible for the previous stage to fail because in in has * clobbered the physical register we were wanting. So we need to - * allocate a new register for that phi value. */ + * allocate a new register for that phi value. + * + * We don't bother allocating anything if the vreg is never used. + * */ for (j=0; jphis.count; j++) { struct vreg* vreg = bb->phis.item[j].left; - if (!pmap_findright(old, vreg)) - allocate_hreg(old, vreg); + struct phi* phi = bb->phis.item[j].right; + if (!pmap_findright(old, vreg) && (vreg->used.count > 0)) + { + struct hop* used = vreg->used.item[0]; + struct constraint* c = pmap_findleft(&used->constraints, vreg); + struct hreg* hreg = allocate_hreg(old, vreg, c->attrs); + + tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n", + hreg->name, vreg->id, phi->prev->name); + } } for (j=0; jhops.count; j++) { + int k; struct hop* hop = bb->hops.item[j]; register_assignment_t* in = &hop->regsin; register_assignment_t* out = &hop->regsout;; + tracef('R', "R: %d from $%d:", hop->id, hop->ir->id); + for (k=0; kins.count; k++) + tracef('R', " r%%%d", hop->ins.item[k]->id); + for (k=0; kthroughs.count; k++) + tracef('R', " =%%%d", hop->throughs.item[k]->id); + for (k=0; kouts.count; k++) + tracef('R', " w%%%d", hop->outs.item[k]->id); + tracef('R', "\n"); + select_registers(hop, old, in, out); old = out; diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index c93a1b373..9f2c6b729 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -400,8 +400,8 @@ Tree tree(const struct terminfo* ti, Tree left, Tree right) if (ti->attr && ti->attr[0]) { - nt->attr = smap_get(®isterattrs, ti->attr); - if (!nt->attr) + t->attr = smap_get(®isterattrs, ti->attr); + if (!t->attr) yyerror("'%s' doesn't seem to be a known register attribute", ti->attr); } } @@ -1077,10 +1077,12 @@ static void emit_input_regs(Tree node, int* index) Nonterm nt = node->op; if ((nt->kind == NONTERM) && !nt->is_fragment && !node->left && !node->right) { - uint32_t attr = 0; - if (nt->attr->number) - attr = 1<attr->number; - print("%1data->constrain_input_reg(%d, 0x%x);\n", *index, attr); + if (node->attr) + { + uint32_t attr = 1<attr->number; + print("%1data->constrain_input_reg(%d, 0x%x /* %s */);\n", + *index, attr, node->attr->name); + } } if (!node->left && !node->right) @@ -1118,7 +1120,8 @@ static void emitinsndata(Rule rules) print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern); if (r->attr) - print("%1data->constrain_output_reg(0x%x);\n", 1<attr->number); + print("%1data->constrain_output_reg(0x%x /* %s */);\n", + 1<attr->number, r->attr->name); { int index = 0; diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index d9d69b8c6..8a5a71b32 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -96,7 +96,6 @@ struct nonterm Rule chain; /* chain rules w/non-terminal on rhs */ Nonterm link; /* next terminal in number order */ bool is_fragment; /* these instructions are all fragments */ - struct regattr* attr; /* input register attribute */ }; extern void* lookup(const char* name); extern Nonterm nonterm(const char* id, bool allocate); @@ -109,6 +108,7 @@ struct tree const char* label; /* user label for this node */ Tree left, right; /* operands */ int nterms; /* number of terminal nodes in this tree */ + struct regattr* attr; /* input register attribute */ }; extern Tree tree(const struct terminfo* ti, Tree left, Tree right); diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 50c2e44ed..31574adbb 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -42,6 +42,10 @@ S AND S OR S EOR S NOT +S ASL +S ASR +S LSL +S LSR # Conversions S CII1 diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 14353c0e3..4e86e79e0 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -44,8 +44,8 @@ struct burm_emitter_data void (*emit_reg)(int child); void (*emit_value)(int child); void (*emit_eoi)(void); - void (*constrain_input_reg)(int child, int attr); - void (*constrain_output_reg)(int attr); + void (*constrain_input_reg)(int child, uint32_t attr); + void (*constrain_output_reg)(uint32_t attr); }; typedef void burm_emitter_t(const struct burm_emitter_data* data); From ff58a6100fb351883096902844091648632af600 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 9 Oct 2016 22:03:44 +0200 Subject: [PATCH 091/230] Add pmap_remove(). --- modules/src/data/pmap.c | 18 ++++++++++++++++++ modules/src/data/pmap.h | 1 + 2 files changed, 19 insertions(+) diff --git a/modules/src/data/pmap.c b/modules/src/data/pmap.c index ae62af3c6..fffba7e90 100644 --- a/modules/src/data/pmap.c +++ b/modules/src/data/pmap.c @@ -1,5 +1,6 @@ #include #include +#include #include "pmap.h" static void append(void* mapp, void* left, void* right) @@ -56,6 +57,23 @@ void pmap_add(void* mapp, void* left, void* right) append(map, left, right); } +void pmap_remove(void* mapp, void* left, void* right) +{ + struct pmap* map = mapp; + int i; + + for (i=0; icount; i++) + { + struct pmap_node* node = &map->item[i]; + if ((node->left == left) && (node->right == right)) + { + memmove(node, node+1, sizeof(*node) * (map->count - i - 1)); + map->count--; + return; + } + } +} + void* pmap_findleft(void* mapp, void* left) { struct pmap* map = mapp; diff --git a/modules/src/data/pmap.h b/modules/src/data/pmap.h index 8c06ec605..a7980a3a3 100644 --- a/modules/src/data/pmap.h +++ b/modules/src/data/pmap.h @@ -25,6 +25,7 @@ struct pmap extern void pmap_put(void* map, void* left, void* right); extern void pmap_add(void* map, void* left, void* right); +extern void pmap_remove(void* map, void* left, void* right); extern void* pmap_findleft(void* map, void* left); extern void* pmap_findright(void* map, void* right); From fac12aae326cd355ed54c003e1762ce8b9b6fb5f Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 9 Oct 2016 22:04:20 +0200 Subject: [PATCH 092/230] Calculate phi congruency groups; use them to solve the importing-hreg-from-the-future problem (probably poorly). --- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_phigroups.c | 85 +++++++++++++++++++++++++ mach/proto/mcg/pass_registerallocator.c | 5 +- mach/proto/mcg/procedure.c | 1 + mach/proto/mcg/reg.h | 9 +++ 5 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 mach/proto/mcg/pass_phigroups.c diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index a90bbb5ef..db4d570b3 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -104,6 +104,7 @@ extern void tb_regvar(struct procedure* proc, arith offset, int size, int type, extern void pass_convert_locals_to_ssa(struct procedure* proc); extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); +extern void pass_find_phi_congruence_groups(void); extern void pass_group_irs(struct procedure* proc); extern void pass_instruction_selector(void); extern void pass_live_vreg_analysis(void); diff --git a/mach/proto/mcg/pass_phigroups.c b/mach/proto/mcg/pass_phigroups.c new file mode 100644 index 000000000..c773aa5ad --- /dev/null +++ b/mach/proto/mcg/pass_phigroups.c @@ -0,0 +1,85 @@ +#include "mcg.h" + +static PMAPOF(struct vreg, struct vreg) phimap; + +static void make_phimap(void) +{ + int i, j; + + phimap.count = 0; + for (i=0; iphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + struct vreg* prevvreg = phi->ir->result; + + pmap_add(&phimap, vreg, prevvreg); + } + } +} + +static void recursively_associate_group(struct phicongruence* c, struct vreg* vreg) +{ + int i; + + vreg->congruence = c; + array_appendu(&c->vregs, vreg); + tracef('V', "V: %%%d is a member of congruence group %d\n", + vreg->id, c->id); + + if (vreg->defined) + { + struct constraint* constraint = pmap_findleft(&vreg->defined->constraints, vreg); + if ((c->attrs == 0) || (constraint->attrs < c->attrs)) + c->attrs = constraint->attrs; + + array_appendu(&c->definitions, vreg->defined); + } + + for (;;) + { + struct vreg* child = pmap_findleft(&phimap, vreg); + if (!child) + break; + + pmap_remove(&phimap, vreg, child); + recursively_associate_group(c, child); + } + + for (;;) + { + struct vreg* child = pmap_findright(&phimap, vreg); + if (!child) + break; + + pmap_remove(&phimap, child, vreg); + recursively_associate_group(c, child); + } +} + +static void associate_groups(void) +{ + static int number = 0; + + while (phimap.count > 0) + { + struct phicongruence* c = calloc(1, sizeof(*c)); + c->id = number++; + recursively_associate_group(c, phimap.item[0].left); + } +} + +void pass_find_phi_congruence_groups(void) +{ + make_phimap(); + associate_groups(); +} + +/* vim: set sw=4 ts=4 expandtab : */ + + + diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 0bacdd225..2e2ad0764 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -164,10 +164,9 @@ void pass_register_allocator(void) { struct vreg* vreg = bb->phis.item[j].left; struct phi* phi = bb->phis.item[j].right; - if (!pmap_findright(old, vreg) && (vreg->used.count > 0)) + if (!pmap_findright(old, vreg)) { - struct hop* used = vreg->used.item[0]; - struct constraint* c = pmap_findleft(&used->constraints, vreg); + struct phicongruence* c = vreg->congruence; struct hreg* hreg = allocate_hreg(old, vreg, c->attrs); tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n", diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index b2970b67b..329c384d3 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -168,6 +168,7 @@ void procedure_compile(struct procedure* proc) pass_instruction_selector(); print_hops('7', proc); + pass_find_phi_congruence_groups(); pass_live_vreg_analysis(); print_hops('8', proc); pass_register_allocator(); diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index 743b9c3e5..fc72f2ae0 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -3,6 +3,14 @@ #define WITH_ATTR(a) (1<<(a)) +struct phicongruence +{ + int id; + ARRAYOF(struct vreg) vregs; + ARRAYOF(struct hop) definitions; + uint32_t attrs; +}; + struct hreg { const char* name; @@ -14,6 +22,7 @@ struct hreg struct vreg { int id; + struct phicongruence* congruence; struct hop* defined; ARRAYOF(struct hop) used; }; From a4d06d1795ddec398ade72a423c6e0a9dc2dcb6f Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 10 Oct 2016 23:18:37 +0200 Subject: [PATCH 093/230] D'oh, need multiple passes over the edge splitter in order to properly find all cases. --- mach/proto/mcg/pass_splitcriticaledges.c | 31 ++++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/mach/proto/mcg/pass_splitcriticaledges.c b/mach/proto/mcg/pass_splitcriticaledges.c index 7962974cc..38628d995 100644 --- a/mach/proto/mcg/pass_splitcriticaledges.c +++ b/mach/proto/mcg/pass_splitcriticaledges.c @@ -63,29 +63,44 @@ static void split_edge(struct basicblock* source, struct basicblock* sink) array_append(¤t_proc->blocks, bb); } -static void consider_edges_leading_to(struct basicblock* bb) +static bool consider_edges_leading_from(struct basicblock* bb) { - if (bb->prevs.count > 1) + bool changed = false; + + if (bb->nexts.count > 1) { int i; - for (i=0; iprevs.count; i++) + for (i=0; inexts.count; i++) { - struct basicblock* prev = bb->prevs.item[i]; - if (prev->nexts.count > 1) - split_edge(prev, bb); + struct basicblock* next = bb->nexts.item[i]; + if (next->prevs.count > 1) + { + split_edge(bb, next); + changed = true; + } } } + + return changed; } void pass_split_critical_edges(struct procedure* proc) { int i; + bool changed; current_proc = proc; - for (i=0; iblocks.count; i++) - consider_edges_leading_to(proc->blocks.item[i]); + do + { + changed = false; + + for (i=0; iblocks.count; i++) + changed |= consider_edges_leading_from(proc->blocks.item[i]); + + } + while (changed); } /* vim: set sw=4 ts=4 expandtab : */ From 92bd1ac5f4e62ad9793401c5c075e7d856b66aa4 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 10 Oct 2016 23:19:46 +0200 Subject: [PATCH 094/230] Register allocator now gets all the way through all of my test file without crashing (albeit with register moves and swaps stubbed out). Correct code? Who knows. --- mach/proto/mcg/hop.c | 49 ++++-- mach/proto/mcg/hop.h | 3 + mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_registerallocator.c | 192 +++++++++++++++++++++++- 4 files changed, 227 insertions(+), 18 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index d0a2dfcf3..68b776280 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -28,6 +28,13 @@ void hop_add_string_insel(struct hop* hop, const char* string) array_append(&hop->insels, insel); } +void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg) +{ + struct insel* insel = new_insel(INSEL_HREG); + insel->u.hreg = hreg; + array_append(&hop->insels, insel); +} + void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg) { struct insel* insel = new_insel(INSEL_VREG); @@ -48,10 +55,30 @@ void hop_add_eoi_insel(struct hop* hop) array_append(&hop->insels, insel); } +static void print_header(char k, struct hop* hop) +{ + int i; + + tracef(k, "%c: %d", k, hop->id); + if (hop->ir) + tracef(k, " from $%d", hop->ir->id); + tracef(k, ":"); + + for (i=0; iins.count; i++) + tracef(k, " r%%%d", hop->ins.item[i]->id); + for (i=0; ithroughs.count; i++) + tracef(k, " =%%%d", hop->throughs.item[i]->id); + for (i=0; iouts.count; i++) + tracef(k, " w%%%d", hop->outs.item[i]->id); + tracef(k, " "); +} + void hop_print(char k, struct hop* hop) { - int i, j; - bool soi = true; + int i; + bool soi = false; + + print_header(k, hop); i = 0; for (i=0; iinsels.count; i++) @@ -60,16 +87,7 @@ void hop_print(char k, struct hop* hop) if (soi) { - tracef(k, "%c: %d from $%d:", k, hop->id, hop->ir->id); - - for (j=0; jins.count; j++) - tracef(k, " r%%%d", hop->ins.item[j]->id); - for (j=0; jthroughs.count; j++) - tracef(k, " =%%%d", hop->throughs.item[j]->id); - for (j=0; jouts.count; j++) - tracef(k, " w%%%d", hop->outs.item[j]->id); - tracef(k, " "); - + print_header(k, hop); soi = false; } @@ -80,6 +98,13 @@ void hop_print(char k, struct hop* hop) soi = true; break; + case INSEL_HREG: + { + struct hreg* hreg = insel->u.hreg; + tracef(k, "%s", hreg->name); + break; + } + case INSEL_VREG: { struct vreg* vreg = insel->u.vreg; diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 4e7868c9a..34d5c116f 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -4,6 +4,7 @@ enum insel_type { INSEL_STRING, + INSEL_HREG, INSEL_VREG, INSEL_VALUE, INSEL_EOI @@ -15,6 +16,7 @@ struct insel union { const char* string; + struct hreg* hreg; struct vreg* vreg; struct ir* value; } @@ -46,6 +48,7 @@ struct hop extern struct hop* new_hop(struct basicblock* bb, struct ir* ir); extern void hop_add_string_insel(struct hop* hop, const char* string); +extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg); extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_eoi_insel(struct hop* hop); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index db4d570b3..e1b8083e1 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -106,6 +106,7 @@ extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_find_phi_congruence_groups(void); extern void pass_group_irs(struct procedure* proc); +extern void pass_insert_moves(void); extern void pass_instruction_selector(void); extern void pass_live_vreg_analysis(void); extern void pass_promote_float_ops(struct procedure* proc); diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 2e2ad0764..f2d9fb6ab 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -3,6 +3,9 @@ static ARRAYOF(struct hreg) hregs; static int stacksize; +static int insert_moves(struct basicblock* bb, int index, + register_assignment_t* srcregs, register_assignment_t* destregs); + static void populate_hregs(void) { const struct burm_register_data* brd = burm_register_data; @@ -89,13 +92,10 @@ static void select_registers(struct hop* hop, } } -void pass_register_allocator(void) +static void assign_hregs_to_vregs(void) { int i, j, k; - populate_hregs(); - wire_up_blocks_ins_outs(); - for (i=0; iregsin; register_assignment_t* out = &hop->regsout;; + select_registers(hop, old, in, out); + tracef('R', "R: %d from $%d:", hop->id, hop->ir->id); for (k=0; kins.count; k++) tracef('R', " r%%%d", hop->ins.item[k]->id); @@ -188,14 +190,192 @@ void pass_register_allocator(void) tracef('R', " =%%%d", hop->throughs.item[k]->id); for (k=0; kouts.count; k++) tracef('R', " w%%%d", hop->outs.item[k]->id); - tracef('R', "\n"); + tracef('R', " ["); + for (k=0; kregsin.count; k++) + { + struct hreg* hreg = hop->regsin.item[k].left; + struct vreg* vreg = hop->regsin.item[k].right; + if (k != 0) + tracef('R', " "); + tracef('R', "%%%d=>%s", vreg->id, hreg->name); + } + tracef('R', "] ["); + for (k=0; kregsout.count; k++) + { + struct hreg* hreg = hop->regsout.item[k].left; + struct vreg* vreg = hop->regsout.item[k].right; + if (k != 0) + tracef('R', " "); + tracef('R', "%%%d=>%s", vreg->id, hreg->name); + } + tracef('R', "]\n"); - select_registers(hop, old, in, out); + if (j > 0) + j += insert_moves(bb, j, old, in); old = out; } } } +static struct hop* create_move(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + hop_add_string_insel(hop, "! move "); + hop_add_hreg_insel(hop, src); + hop_add_string_insel(hop, " -> "); + hop_add_hreg_insel(hop, dest); + hop_add_eoi_insel(hop); + + return hop; +} + +static struct hop* create_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + hop_add_string_insel(hop, "! swap "); + hop_add_hreg_insel(hop, src); + hop_add_string_insel(hop, " <-> "); + hop_add_hreg_insel(hop, dest); + hop_add_eoi_insel(hop); + + return hop; +} + +/* returns the number of instructions inserted */ +static int insert_moves(struct basicblock* bb, int index, + register_assignment_t* srcregs, register_assignment_t* destregs) +{ + int i; + int inserted = 0; + static PMAPOF(struct hreg, struct hreg) copies; + + copies.count = 0; + for (i=0; icount; i++) + { + struct hreg* dest = destregs->item[i].left; + struct vreg* vreg = destregs->item[i].right; + struct hreg* src = pmap_findright(srcregs, vreg); + assert(src != NULL); + + if (src != dest) + pmap_add(&copies, src, dest); + } + + while (copies.count > 0) + { + struct hreg* src; + struct hreg* dest; + struct hreg* temp; + struct hop* hop; + + /* Try and find a destination which isn't a source. */ + + src = NULL; + for (i=0; ihops, hop, index + inserted); + inserted++; + } + + return inserted; +} + +static void insert_phi_copies(void) +{ + int i, j, k; + + /* If we're importing an hreg from a parent block via a phi, insert a move + * at the end of the parent block to put the result into the right + * register. */ + + for (i=0; iprevs.count; j++) + { + struct basicblock* prevbb = bb->prevs.item[j]; + static register_assignment_t destregs; + + tracef('R', "R: inserting phis for %s -> %s\n", + prevbb->name, bb->name); + destregs.count = 0; + for (k=0; kphis.count; k++) + { + struct vreg* vreg = bb->phis.item[k].left; + struct phi* phi = bb->phis.item[k].right; + struct hreg* dest = pmap_findright(bb->regsin, vreg); + + if ((phi->prev == prevbb) && dest) + { + /* We inserted critical edges to guarantee this. */ + assert(prevbb->nexts.count == 1); + + tracef('R', "R: map %%%d -> %%%d (%s)\n", + phi->ir->result->id, + vreg->id, dest->name); + + pmap_put(&destregs, dest, phi->ir->result); + } + } + + /* Add any non-phi inputs. */ + + for (k=0; kregsin->count; k++) + { + struct hreg* hreg = bb->regsin->item[k].left; + struct vreg* vreg = bb->regsin->item[k].right; + if (!pmap_findleft(&bb->phis, vreg)) + pmap_add(&destregs, hreg, vreg); + } + + /* The last instruction of a block should be the jump that sends us + * to the next block. Insert the moves before then. */ + + insert_moves(prevbb, prevbb->hops.count-1, prevbb->regsout, &destregs); + } + } +} + +void pass_register_allocator(void) +{ + populate_hregs(); + wire_up_blocks_ins_outs(); + assign_hregs_to_vregs(); + insert_phi_copies(); +} + /* vim: set sw=4 ts=4 expandtab : */ From e93c58dc8dbca6cf45026f4fcba11aefea624270 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Oct 2016 00:12:11 +0200 Subject: [PATCH 095/230] Refactored the way hops are rendered; add support for emitting code (although with no prologue or epilogue yet). --- mach/proto/mcg/data.c | 24 +++++------ mach/proto/mcg/hop.c | 82 ++++++++++++++++++++++++++++---------- mach/proto/mcg/hop.h | 1 + mach/proto/mcg/main.c | 35 +++++++++++++--- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/procedure.c | 19 +++++++++ 6 files changed, 122 insertions(+), 40 deletions(-) diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index acc14c0fd..0f79cb767 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -36,8 +36,8 @@ static void emit_header(int desired_section) else if (pending->section != desired_section) fatal("label '%s' can't change sections", pending->name); - printf("\n.sect %s\n", section_to_str(pending->section)); - printf("%s:\n", pending->name); + fprintf(outputfile, "\n.sect %s\n", section_to_str(pending->section)); + fprintf(outputfile, "%s:\n", pending->name); pending = NULL; } } @@ -46,7 +46,7 @@ void data_int(arith data, size_t size, bool is_ro) { emit_header(is_ro ? SECTION_ROM : SECTION_DATA); assert((size == 1) || (size == 2) || (size == 4) || (size == 8)); - printf("\t.data%d 0x%0*lld\n", size, size*2, data); + fprintf(outputfile, "\t.data%d 0x%0*lld\n", size, size*2, data); } void data_block(const uint8_t* data, size_t size, bool is_ro) @@ -65,13 +65,13 @@ void data_block(const uint8_t* data, size_t size, bool is_ro) if (start < p) { - printf("\t.ascii \""); + fprintf(outputfile, "\t.ascii \""); while (start < p) { - printf("%c", *start); + fprintf(outputfile, "%c", *start); start++; } - printf("\"\n"); + fprintf(outputfile, "\"\n"); } while ((p < end) && !isprint(*p)) @@ -81,16 +81,16 @@ void data_block(const uint8_t* data, size_t size, bool is_ro) { bool first = true; - printf("\t.data1 "); + fprintf(outputfile, "\t.data1 "); while (start < p) { if (!first) - printf(", "); - printf("0x%02x", *start); + fprintf(outputfile, ", "); + fprintf(outputfile, "0x%02x", *start); start++; first = false; } - printf("\n"); + fprintf(outputfile, "\n"); } } } @@ -98,7 +98,7 @@ void data_block(const uint8_t* data, size_t size, bool is_ro) void data_offset(const char* label, arith offset, bool is_ro) { emit_header(is_ro ? SECTION_ROM : SECTION_DATA); - printf("\t.data%d %s+%lld\n", EM_pointersize, label, offset); + fprintf(outputfile, "\t.data%d %s+%lld\n", EM_pointersize, label, offset); } void data_bss(arith size, int init) @@ -107,7 +107,7 @@ void data_bss(arith size, int init) fatal("non-zero-initialised bss not supported"); emit_header(SECTION_BSS); - printf("\t.space %lld\n", size); + fprintf(outputfile, "\t.space %lld\n", size); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 68b776280..f9873136b 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -2,6 +2,9 @@ static int hop_count = 1; static struct hop* current_hop; +static char* buffer = NULL; +static int bufferlen = 0; +static int buffersize = 0; static const struct burm_emitter_data emitter_data; @@ -73,35 +76,54 @@ static void print_header(char k, struct hop* hop) tracef(k, " "); } -void hop_print(char k, struct hop* hop) +static char* appendf(const char* fmt, ...) { - int i; - bool soi = false; + int n; + char* p; + va_list ap; - print_header(k, hop); + va_start(ap, fmt); + n = bufferlen + vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + if (n > buffersize) + { + buffersize *= 2; + if (buffersize < n) + buffersize = n*2; + buffer = realloc(buffer, buffersize); + } + + va_start(ap, fmt); + vsprintf(buffer+bufferlen, fmt, ap); + va_end(ap); + + bufferlen = n - 1; /* remember the \0 at the end */ + return p; +} + +char* hop_render(struct hop* hop) +{ + int i; + + appendf(""); /* ensure the buffer has been allocated */ + bufferlen = 0; + buffer[0] = '\0'; - i = 0; for (i=0; iinsels.count; i++) { struct insel* insel = hop->insels.item[i]; - if (soi) - { - print_header(k, hop); - soi = false; - } - switch (insel->type) { case INSEL_EOI: - tracef(k, "\n"); - soi = true; + appendf("\n"); break; case INSEL_HREG: { struct hreg* hreg = insel->u.hreg; - tracef(k, "%s", hreg->name); + appendf("%s", hreg->name); break; } @@ -112,14 +134,14 @@ void hop_print(char k, struct hop* hop) if (!hreg) hreg = pmap_findright(&hop->regsout, vreg); if (hreg) - tracef(k, "%s", hreg->name); + appendf("%s", hreg->name); else - tracef(k, "%%%d", vreg->id); + appendf("%%%d", vreg->id); break; } case INSEL_STRING: - tracef(k, "%s", insel->u.string); + appendf("%s", insel->u.string); break; case INSEL_VALUE: @@ -128,16 +150,16 @@ void hop_print(char k, struct hop* hop) switch (ir->opcode) { case IR_BLOCK: - tracef(k, "%s", ir->u.bvalue->name); + appendf("%s", ir->u.bvalue->name); break; case IR_LABEL: - tracef(k, "%s", ir->u.lvalue); + appendf("%s", ir->u.lvalue); break; case IR_LOCAL: case IR_CONST: - tracef(k, "%d", ir->u.ivalue); + appendf("%d", ir->u.ivalue); break; } break; @@ -145,8 +167,24 @@ void hop_print(char k, struct hop* hop) } } - if (!soi) - tracef(k, "\n", k); + return buffer; +} + +void hop_print(char k, struct hop* hop) +{ + int i; + bool soi = false; + char* p; + + hop_render(hop); + + p = strtok(buffer, "\n"); + while (p) + { + print_header(k, hop); + tracef(k, "%s\n", p); + p = strtok(NULL, "\n"); + } } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 34d5c116f..7dcbfd87a 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -53,6 +53,7 @@ extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_eoi_insel(struct hop* hop); +extern char* hop_render(struct hop* hop); extern void hop_print(char k, struct hop* hop); #endif diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 235e9f357..1c0d7065c 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -4,6 +4,7 @@ static const char* tracechars = NULL; +FILE* outputfile = NULL; FILE* dominance_dot_file = NULL; FILE* cfg_dot_file = NULL; @@ -36,7 +37,9 @@ static bool find_procedures_cb(struct symbol* symbol, void* user) int main(int argc, char* const argv[]) { - const char* inputfile = NULL; + const char* inputfilename = NULL; + const char* outputfilename = NULL; + FILE* output; program_name = argv[0]; @@ -69,19 +72,35 @@ int main(int argc, char* const argv[]) tracechars = optarg; break; + case 'o': + if (outputfilename) + fatal("already specified an output file"); + outputfilename = optarg; + break; + case 1: - if (inputfile) + if (inputfilename) fatal("unexpected argument '%s'", optarg); - inputfile = optarg; + inputfilename = optarg; } } symbol_init(); - if (!EM_open((char*) inputfile)) - fatal("couldn't open '%s': %s", - inputfile ? inputfile : "", EM_error); + if (!EM_open((char*) inputfilename)) + fatal("couldn't open input '%s': %s", + inputfilename ? inputfilename : "", EM_error); + if (outputfilename) + { + outputfile = fopen(outputfilename, "w"); + if (!outputfile) + fatal("couldn't open output '%s': %s", + outputfilename, strerror(errno)); + } + else + outputfile = stdout; + /* Reads in the EM, outputs the data sections, parses any code and * generates IR trees. */ @@ -93,7 +112,10 @@ int main(int argc, char* const argv[]) symbol_walk(find_procedures_cb, NULL); + if (outputfilename) + fclose(outputfile); EM_close(); + if (cfg_dot_file) { fprintf(cfg_dot_file, "}\n"); @@ -104,6 +126,7 @@ int main(int argc, char* const argv[]) fprintf(dominance_dot_file, "}\n"); fclose(dominance_dot_file); } + return 0; } diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index e1b8083e1..567885886 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -114,6 +114,7 @@ extern void pass_register_allocator(void); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_split_critical_edges(struct procedure* proc); +extern FILE* outputfile; extern FILE* dominance_dot_file; extern FILE* cfg_dot_file; diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 329c384d3..35b986f55 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -104,6 +104,23 @@ static void print_hops(char k, struct procedure* proc) } } +static void emit_procedure(struct procedure* proc) +{ + int i, j; + + for (i=0; iname); + for (j=0; jhops.count; j++) + { + struct hop* hop = bb->hops.item[j]; + fprintf(outputfile, "%s", hop_render(hop)); + } + } +} + static void write_cfg_graph(const char* name) { int i; @@ -174,6 +191,8 @@ void procedure_compile(struct procedure* proc) pass_register_allocator(); print_hops('9', proc); + emit_procedure(proc); + if (cfg_dot_file) write_cfg_graph(proc->name); if (dominance_dot_file) From 2be1c51885afb8940548aa96e999cb8c24917f1d Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Oct 2016 00:23:35 +0200 Subject: [PATCH 096/230] A little fiddling with store instructions. The PowerPC is not friendly to iburg. --- mach/proto/mcg/table | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 4a853a642..20ef46b2b 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -73,6 +73,7 @@ REGISTERS DECLARATIONS cr; + ubyte_to_be; address fragment; @@ -129,10 +130,23 @@ PATTERNS emit "sth %value, %addr" cost 4; - STORE1(addr:address, value:(int)reg) + STORE1(addr:address, value:(int)ubyte_to_be) emit "stb %value, %addr" cost 4; + STORE1(ADD4(left:(int)reg, right:(int)reg), value:(int)ubyte_to_be) + emit "stbx %value, %left, %right" + cost 4; + + out:(int)ubyte_to_be = in:(int)reg + cost 1; + + out:(int)ubyte_to_be = CIU41(value:(int)reg) + cost 1; + + out:(int)ubyte_to_be = CIU41(CII14(CIU41(value:(int)reg))) + cost 1; + out:(int)reg = LOAD4(addr:address) emit "lwz %out, %addr" cost 4; @@ -325,7 +339,7 @@ PATTERNS cost 4; out:(int)reg = value:CONST4 - emit "la %out, $value" + emit "li %out, $value" cost 8; From 668cccdff1d5292893f13e9c88a4312aa43a9d6e Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Oct 2016 00:29:18 +0200 Subject: [PATCH 097/230] A few more opcodes. --- mach/proto/mcg/table | 6 +++++- mach/proto/mcg/treebuilder.c | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 20ef46b2b..f50f02c11 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -301,7 +301,11 @@ PATTERNS cost 4; out:(int)reg = SUB4(left:(int)reg, right:(int)reg) - emit "sub %out, %right, %left" + emit "subf %out, %left, %right" + cost 4; + + out:(int)reg = SUB4(left:(int)reg, right:CONST4) + emit "addi %out, %left, -($right)" cost 4; out:(int)reg = MUL4(left:(int)reg, right:(int)reg) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 8039b3449..828a99747 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -217,6 +217,30 @@ static void insn_simple(int opcode) break; } + case op_inc: + { + push( + new_ir2( + IR_ADD, EM_wordsize, + pop(EM_wordsize), + new_wordir(1) + ) + ); + break; + } + + case op_dec: + { + push( + new_ir2( + IR_SUB, EM_wordsize, + pop(EM_wordsize), + new_wordir(1) + ) + ); + break; + } + default: fatal("treebuilder: unknown simple instruction '%s'", em_mnem[opcode - sp_fmnem]); From 96dffd2007920604c9ab8dc8ea001d28efc6b721 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Oct 2016 23:17:30 +0200 Subject: [PATCH 098/230] Clean up the allocator a bit, in preparation for making it lots more complicated; no semantic changes. --- mach/proto/mcg/pass_registerallocator.c | 117 +++++++++++++++++++----- 1 file changed, 95 insertions(+), 22 deletions(-) diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index f2d9fb6ab..1c8df2d16 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -1,7 +1,17 @@ #include "mcg.h" +struct assignment +{ + struct vreg* in; + struct vreg* out; +}; + static ARRAYOF(struct hreg) hregs; -static int stacksize; + +static ARRAYOF(struct vreg) evicted; +static struct hop* current_hop; +static register_assignment_t* current_ins; +static register_assignment_t* current_outs; static int insert_moves(struct basicblock* bb, int index, register_assignment_t* srcregs, register_assignment_t* destregs); @@ -10,7 +20,7 @@ static void populate_hregs(void) { const struct burm_register_data* brd = burm_register_data; - stacksize = 0; + hregs.count = 0; while (brd->name) { array_append(&hregs, new_hreg(brd)); @@ -31,24 +41,87 @@ static void wire_up_blocks_ins_outs(void) } } -static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg, uint32_t attr) +static struct hreg* allocate_phi_hreg(register_assignment_t* regs, + struct vreg* vreg, uint32_t attrs) { int i; + /* We need a new register at the beginning of the block to put a phi value + * into. */ + for (i=0; iattrs & attrs)) { - if (hreg->attrs & attr) - { - pmap_put(regs, hreg, vreg); - return hreg; - } + /* This one is unused. Use it. */ + return hreg; } } - fatal("ran out of registers"); + /* We'll need to allocate a new stack slot for it. */ + assert(false); +} + +static bool allocatable(struct hreg* hreg, struct vreg* vreg) +{ + struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + return (hreg->attrs & c->attrs); +} + +static void add_input_register(struct vreg* vreg, struct hreg* hreg) +{ + int i; + + /* Register hint for an input? */ + + if (hreg) + { + /* If it's already assigned, it's most likely a through. */ + if (!pmap_findleft(current_ins, hreg)) + pmap_add(current_ins, hreg, vreg); + return; + } + + /* Find an unused input register of the right class. */ + + for (i=0; iins.item[i]; struct hreg* hreg = pmap_findright(old, vreg); - assert(hreg != NULL); - - pmap_put(in, hreg, vreg); + add_input_register(vreg, hreg); } /* Any output registers will be *new* vregs (because SSA). So, allocate @@ -87,8 +162,7 @@ static void select_registers(struct hop* hop, for (i=0; iouts.count; i++) { struct vreg* vreg = hop->outs.item[i]; - struct constraint* c = pmap_findleft(&hop->constraints, vreg); - allocate_hreg(out, vreg, c->attrs); + add_output_register(vreg); } } @@ -156,9 +230,7 @@ static void assign_hregs_to_vregs(void) /* It's possible for the previous stage to fail because in in has * clobbered the physical register we were wanting. So we need to * allocate a new register for that phi value. - * - * We don't bother allocating anything if the vreg is never used. - * */ + */ for (j=0; jphis.count; j++) { @@ -167,16 +239,16 @@ static void assign_hregs_to_vregs(void) if (!pmap_findright(old, vreg)) { struct phicongruence* c = vreg->congruence; - struct hreg* hreg = allocate_hreg(old, vreg, c->attrs); + struct hreg* hreg = allocate_phi_hreg(old, vreg, c->attrs); tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n", hreg->name, vreg->id, phi->prev->name); + pmap_add(old, hreg, vreg); } } for (j=0; jhops.count; j++) { - int k; struct hop* hop = bb->hops.item[j]; register_assignment_t* in = &hop->regsin; register_assignment_t* out = &hop->regsout;; @@ -373,6 +445,7 @@ void pass_register_allocator(void) { populate_hregs(); wire_up_blocks_ins_outs(); + assign_hregs_to_vregs(); insert_phi_copies(); } From df239b3f90ed5e752c9ec83053f5bfe5130b9da7 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 12 Oct 2016 00:45:36 +0200 Subject: [PATCH 099/230] Don't allow the same IR to be added to the sequence list more than once (sometimes happens because op_dup, but makes no sense). --- mach/proto/mcg/treebuilder.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 828a99747..4060b206f 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -75,7 +75,7 @@ static struct ir* appendir(struct ir* ir) int i; assert(current_bb != NULL); - array_append(¤t_bb->irs, ir); + array_appendu(¤t_bb->irs, ir); ir_print('0', ir); return ir; @@ -196,6 +196,7 @@ static void insn_simple(int opcode) case op_cii: simple_convert(IR_CII1); break; case op_ciu: simple_convert(IR_CIU1); break; + case op_cui: simple_convert(IR_CUI1); break; case op_cmp: push( @@ -406,6 +407,9 @@ static void insn_ivalue(int opcode, arith value) case op_sru: simple_alu2(opcode, value, IR_LSR); break; case op_ngi: simple_alu1(opcode, value, IR_NEG); break; + case op_adu: simple_alu2(opcode, value, IR_ADD); break; + case op_sbu: simple_alu2(opcode, value, IR_SUB); break; + case op_and: simple_alu2(opcode, value, IR_AND); break; case op_ior: simple_alu2(opcode, value, IR_OR); break; case op_xor: simple_alu2(opcode, value, IR_EOR); break; @@ -712,6 +716,16 @@ static void insn_lvalue(int opcode, const char* label, arith offset) ); break; + case op_zre: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_external(label, offset), + new_wordir(0) + ) + ); + break; + case op_cal: assert(offset == 0); materialise_stack(); From 4723a1442f173fb239b468be8c5a7913f1f5177e Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 12 Oct 2016 21:50:12 +0200 Subject: [PATCH 100/230] Add code to remove unused phis, converting to pruned SSA form, to avoid confusing the register allocator later. --- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_removedeadphis.c | 88 ++++++++++++++++++++++++++++ mach/proto/mcg/procedure.c | 3 +- 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 mach/proto/mcg/pass_removedeadphis.c diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 567885886..0df947df7 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -112,6 +112,7 @@ extern void pass_live_vreg_analysis(void); extern void pass_promote_float_ops(struct procedure* proc); extern void pass_register_allocator(void); extern void pass_remove_dead_blocks(struct procedure* proc); +extern void pass_remove_dead_phis(void); extern void pass_split_critical_edges(struct procedure* proc); extern FILE* outputfile; diff --git a/mach/proto/mcg/pass_removedeadphis.c b/mach/proto/mcg/pass_removedeadphis.c new file mode 100644 index 000000000..b8b61fbbd --- /dev/null +++ b/mach/proto/mcg/pass_removedeadphis.c @@ -0,0 +1,88 @@ +#include "mcg.h" + +static ARRAYOF(struct ir) phis; +static bool changed; + +static void collect_phis(struct basicblock* bb) +{ + int i; + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + if (ir->opcode == IR_PHI) + array_append(&phis, ir); + } +} + +static bool ir_walker_cb(struct ir* ir, void* user) +{ + if (ir->left) + array_remove(&phis, ir->left); + if (ir->right) + array_remove(&phis, ir->right); + + return false; +} + +static void remove_referenced_phis(struct basicblock* bb) +{ + int i, j; + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + switch (ir->opcode) + { + case IR_PHI: + for (j=0; ju.phivalue.count; j++) + array_remove(&phis, ir->u.phivalue.item[j].right); + break; + + default: + ir_walk(ir, ir_walker_cb, NULL); + break; + } + } +} + +static void purge_unused_phis(struct basicblock* bb) +{ + int i; + + for (i=0; iirs.count; i++) + { + struct ir* ir = bb->irs.item[i]; + if ((ir->opcode == IR_PHI) && (array_contains(&phis, ir))) + { + array_remove(&bb->irs, ir); + i--; + changed = true; + } + } +} + +void pass_remove_dead_phis(void) +{ + int i; + + do + { + changed = false; + + phis.count = 0; + for (i=0; i Date: Wed, 12 Oct 2016 22:58:46 +0200 Subject: [PATCH 101/230] Keep track of register types as well as attributes --- the type being how we find new registers when evicting values. Input constraints work (they were being ignored before). Various bug fixing so they actually work. --- mach/proto/mcg/ir.h | 2 + mach/proto/mcg/pass_groupirs.c | 2 +- mach/proto/mcg/pass_instructionselection.c | 5 +- mach/proto/mcg/pass_registerallocator.c | 109 +++++++++++++--- mach/proto/mcg/reg.h | 1 + mach/proto/mcg/table | 141 +++++++++++---------- util/mcgg/gram.y | 3 +- util/mcgg/iburg.c | 6 +- util/mcgg/iburg.h | 3 +- util/mcgg/ir.dat | 5 + util/mcgg/mcgg.h | 1 + 11 files changed, 191 insertions(+), 87 deletions(-) diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index c273709f2..83dd34246 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -20,6 +20,8 @@ struct ir PMAPOF(struct basicblock, struct ir) phivalue; } u; + ARRAYOF(struct ir) uses; /* all places this IR is used */ + struct vreg* result; /* vreg containing IR result */ }; diff --git a/mach/proto/mcg/pass_groupirs.c b/mach/proto/mcg/pass_groupirs.c index 833809b1d..ac86ff230 100644 --- a/mach/proto/mcg/pass_groupirs.c +++ b/mach/proto/mcg/pass_groupirs.c @@ -28,7 +28,7 @@ static void collect_irs(struct procedure* proc) { struct ir* ir = bb->irs.item[j]; addall(ir); - array_appendu(&rootirs, ir); + array_append(&rootirs, ir); } } } diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 6ab678ac9..b87ede3aa 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -177,7 +177,10 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) switch (node->label) { - case ir_to_esn(IR_REG, 0): + case ir_to_esn(IR_REG, 1): + case ir_to_esn(IR_REG, 2): + case ir_to_esn(IR_REG, 4): + case ir_to_esn(IR_REG, 8): vreg = node->ir->result; break; diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 1c8df2d16..42f43ef33 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -8,7 +8,7 @@ struct assignment static ARRAYOF(struct hreg) hregs; -static ARRAYOF(struct vreg) evicted; +static PMAPOF(struct vreg, struct hreg) evicted; static struct hop* current_hop; static register_assignment_t* current_ins; static register_assignment_t* current_outs; @@ -63,6 +63,42 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs, assert(false); } +static bool evictable(struct hreg* hreg, struct vreg* vreg) +{ + struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + return (hreg->attrs & c->attrs) && !array_contains(¤t_hop->ins, vreg); + /* Find an unused output register of the right class which is not also being used as an input register. */ +} + +static struct hreg* evict(struct vreg* vreg) +{ + int i; + + /* Look for a through register which matches our requirements. We should be + * doing some calculation here to figure out the cheapest register to + * evict, but for now we're picking the first one. FIXME. */ + + for (i=0; iid, hreg->name); + pmap_put(&evicted, candidate, hreg); + pmap_remove(current_ins, hreg, candidate); + pmap_remove(current_outs, hreg, candidate); + return hreg; + } + } + + /* Couldn't find anything to evict */ + assert(false); +} + static bool allocatable(struct hreg* hreg, struct vreg* vreg) { struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); @@ -75,7 +111,7 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg) /* Register hint for an input? */ - if (hreg) + if (hreg && allocatable(hreg, vreg)) { /* If it's already assigned, it's most likely a through. */ if (!pmap_findleft(current_ins, hreg)) @@ -85,6 +121,7 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg) /* Find an unused input register of the right class. */ + hreg = NULL; for (i=0; itype; + struct hreg* hreg; + int i; + + /* Find an unused output register of the right class which is not also + * being used as an input register. */ + + hreg = NULL; + for (i=0; itype == src->type) && + !pmap_findleft(current_ins, hreg) && + !pmap_findleft(current_outs, hreg)) + { + goto found; + } + } + + /* No more registers --- allocate a stack slot. */ + assert(false); + +found: + tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->name); + pmap_add(current_ins, hreg, vreg); + pmap_add(current_outs, hreg, vreg); } static void select_registers(struct hop* hop, @@ -132,6 +203,7 @@ static void select_registers(struct hop* hop, current_hop = hop; current_ins = in; current_outs = out; + evicted.count = 0; /* First, any vregs passing through the instruction stay in the same * registers they are currently in. */ @@ -164,6 +236,16 @@ static void select_registers(struct hop* hop, struct vreg* vreg = hop->outs.item[i]; add_output_register(vreg); } + + /* Any evicted registers now need to go somewhere (potentially, the stack). + * */ + + for (i=0; iregsin; register_assignment_t* out = &hop->regsout;; + hop_print('R', hop); + select_registers(hop, old, in, out); - tracef('R', "R: %d from $%d:", hop->id, hop->ir->id); - for (k=0; kins.count; k++) - tracef('R', " r%%%d", hop->ins.item[k]->id); - for (k=0; kthroughs.count; k++) - tracef('R', " =%%%d", hop->throughs.item[k]->id); - for (k=0; kouts.count; k++) - tracef('R', " w%%%d", hop->outs.item[k]->id); - tracef('R', " ["); + tracef('R', "R: %d from $%d: [", hop->id, hop->ir->id); for (k=0; kregsin.count; k++) { struct hreg* hreg = hop->regsin.item[k].left; diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index fc72f2ae0..753109063 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -14,6 +14,7 @@ struct phicongruence struct hreg { const char* name; + uint32_t type; uint32_t attrs; bool is_stacked; int offset; diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index f50f02c11..12ad4a35d 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -1,73 +1,77 @@ REGISTERS /* Registers are allocated top down; the order here is odd in order to make - * sure that non-volatile registers get allocated from r31 (or f31) down. */ + * sure that non-volatile registers get allocated from r31 (or f31) down. + * + * Attributes ending in an exclamation mark must match exactly when copying + * a register into another register (e.g. for eviction). + */ - r12 bytes4 int volatile; - r11 bytes4 int volatile; - r10 bytes4 int volatile; - r9 bytes4 int volatile; - r8 bytes4 int volatile; - r7 bytes4 int volatile; - r6 bytes4 int volatile; - r5 bytes4 int volatile; - r4 bytes4 int volatile; - r3 bytes4 int ret volatile; + r12 bytes4! int! volatile; + r11 bytes4! int! volatile; + r10 bytes4! int! volatile; + r9 bytes4! int! volatile; + r8 bytes4! int! volatile; + r7 bytes4! int! volatile; + r6 bytes4! int! volatile; + r5 bytes4! int! volatile; + r4 bytes4! int! volatile; + r3 bytes4! int! ret volatile; - r31 bytes4 int; - r30 bytes4 int; - r29 bytes4 int; - r28 bytes4 int; - r27 bytes4 int; - r26 bytes4 int; - r25 bytes4 int; - r24 bytes4 int; - r23 bytes4 int; - r22 bytes4 int; - r21 bytes4 int; - r20 bytes4 int; - r19 bytes4 int; - r18 bytes4 int; - r17 bytes4 int; - r16 bytes4 int; - r15 bytes4 int; - r14 bytes4 int; + r31 bytes4! int!; + r30 bytes4! int!; + r29 bytes4! int!; + r28 bytes4! int!; + r27 bytes4! int!; + r26 bytes4! int!; + r25 bytes4! int!; + r24 bytes4! int!; + r23 bytes4! int!; + r22 bytes4! int!; + r21 bytes4! int!; + r20 bytes4! int!; + r19 bytes4! int!; + r18 bytes4! int!; + r17 bytes4! int!; + r16 bytes4! int!; + r15 bytes4! int!; + r14 bytes4! int!; - f14 bytes4 float volatile; - f13 bytes4 float volatile; - f12 bytes4 float volatile; - f11 bytes4 float volatile; - f10 bytes4 float volatile; - f9 bytes4 float volatile; - f8 bytes4 float volatile; - f7 bytes4 float volatile; - f6 bytes4 float volatile; - f5 bytes4 float volatile; - f4 bytes4 float volatile; - f3 bytes4 float volatile; - f2 bytes4 float volatile; - f1 bytes4 float volatile; - f0 bytes4 float volatile; + f14 bytes4! float! volatile; + f13 bytes4! float! volatile; + f12 bytes4! float! volatile; + f11 bytes4! float! volatile; + f10 bytes4! float! volatile; + f9 bytes4! float! volatile; + f8 bytes4! float! volatile; + f7 bytes4! float! volatile; + f6 bytes4! float! volatile; + f5 bytes4! float! volatile; + f4 bytes4! float! volatile; + f3 bytes4! float! volatile; + f2 bytes4! float! volatile; + f1 bytes4! float! volatile; + f0 bytes4! float! volatile; - f31 bytes4 float; - f30 bytes4 float; - f29 bytes4 float; - f28 bytes4 float; - f27 bytes4 float; - f26 bytes4 float; - f25 bytes4 float; - f24 bytes4 float; - f23 bytes4 float; - f22 bytes4 float; - f21 bytes4 float; - f20 bytes4 float; - f19 bytes4 float; - f18 bytes4 float; - f17 bytes4 float; - f16 bytes4 float; - f15 bytes4 float; + f31 bytes4! float!; + f30 bytes4! float!; + f29 bytes4! float!; + f28 bytes4! float!; + f27 bytes4! float!; + f26 bytes4! float!; + f25 bytes4! float!; + f24 bytes4! float!; + f23 bytes4! float!; + f22 bytes4! float!; + f21 bytes4! float!; + f20 bytes4! float!; + f19 bytes4! float!; + f18 bytes4! float!; + f17 bytes4! float!; + f16 bytes4! float!; + f15 bytes4! float!; - cr0 cr; + cr0 cr!; DECLARATIONS @@ -75,7 +79,7 @@ DECLARATIONS cr; ubyte_to_be; - address fragment; + address fragment; PATTERNS @@ -107,10 +111,11 @@ PATTERNS cost 4; SETRET4(in:(ret)reg) - emit "mr r3, %in" + emit "! setret4" cost 4; (ret)reg = GETRET4 + emit "! getret4" cost 1; STACKADJUST4(delta:CONST4) @@ -139,12 +144,15 @@ PATTERNS cost 4; out:(int)ubyte_to_be = in:(int)reg + emit "! reg -> ubyte" cost 1; out:(int)ubyte_to_be = CIU41(value:(int)reg) + emit "! CIU41(reg) -> ubyte" cost 1; out:(int)ubyte_to_be = CIU41(CII14(CIU41(value:(int)reg))) + emit "! CIU41(CII14(CIU41(reg))) -> ubyte" cost 1; out:(int)reg = LOAD4(addr:address) @@ -284,9 +292,12 @@ PATTERNS cost 4; out:(int)reg = CIU44(in:(int)reg) - emit "mr %out, %in" + emit "mr %out, %in ! ciu44" cost 4; + out:(int)reg = CUI44(in:(int)reg) + emit "mr %out, %in ! cui44" + cost 4; /* ALU operations */ diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 74c0c0502..f6f39ae0f 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -71,7 +71,8 @@ registers register : ID { $$ = makereg($1); } - | register ID { $$ = $1; addregattr($1, $2); } + | register ID { $$ = $1; addregattr($1, $2, false); } + | register ID '!' { $$ = $1; addregattr($1, $2, true); } ; declarations diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 9f2c6b729..bf3a698d1 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -283,7 +283,7 @@ struct regattr* makeregattr(const char* id) return p; } -void addregattr(struct reg* reg, const char* id) +void addregattr(struct reg* reg, const char* id, bool exact) { struct regattr* p = smap_get(®isterattrs, id); @@ -291,6 +291,8 @@ void addregattr(struct reg* reg, const char* id) p = makeregattr(id); reg->attrs |= 1<<(p->number); + if (exact) + reg->type |= 1<<(p->number); } struct regattr* getregattr(const char* id) @@ -589,7 +591,7 @@ static void emitregisters(void) struct reg* r = registers.item[i].right; assert(r->number == i); - print("%1{ \"%s\", 0x%x },\n", r->name, r->attrs); + print("%1{ \"%s\", 0x%x, 0x%x },\n", r->name, r->type, r->attrs); } print("%1{ NULL }\n"); print("};\n\n"); diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 8a5a71b32..34c046e13 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -62,6 +62,7 @@ struct reg const char* name; /* register name */ int number; /* identifying number */ uint32_t attrs; /* bitfield of register attributes */ + uint32_t type; /* register type */ }; struct regattr @@ -71,7 +72,7 @@ struct regattr }; extern struct reg* makereg(const char* name); -extern void addregattr(struct reg* reg, const char* regattr); +extern void addregattr(struct reg* reg, const char* regattr, bool exact); extern struct regattr* getregattr(const char* name); struct term diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 31574adbb..0667ee04d 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -58,6 +58,11 @@ S CIU2 S CIU4 S CIU8 +S CUI1 +S CUI2 +S CUI4 +S CUI8 + # Tristate comparisons S COMPARES S COMPAREU diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 4e86e79e0..94e5b67bf 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -62,6 +62,7 @@ extern const struct burm_instruction_data burm_instruction_data[]; struct burm_register_data { const char* name; + uint32_t type; uint32_t attrs; }; From 216ff5cc43ecf9c362af27254a4167b460accfd8 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 12 Oct 2016 23:12:53 +0200 Subject: [PATCH 102/230] Make loads and stores in the table nicer; fix a place where it looked like it was working but only accidentally. --- mach/proto/mcg/table | 68 +++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 12ad4a35d..3cea3efb8 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -77,7 +77,8 @@ REGISTERS DECLARATIONS cr; - ubyte_to_be; + ubyte; + ushort; address fragment; @@ -127,53 +128,74 @@ PATTERNS /* Memory operations */ + /* Stores */ + STORE4(addr:address, value:(int)reg) emit "stw %value, %addr" cost 4; - STORE2(addr:address, value:(int)reg) + STORE2(addr:address, value:(int)ushort) emit "sth %value, %addr" cost 4; - STORE1(addr:address, value:(int)ubyte_to_be) + STORE2(ADD4(left:(int)reg, right:(int)reg), value:(int)ushort) + emit "sthx %value, %left, %right" + cost 4; + + STORE1(addr:address, value:(int)ubyte) emit "stb %value, %addr" cost 4; - STORE1(ADD4(left:(int)reg, right:(int)reg), value:(int)ubyte_to_be) + STORE1(ADD4(left:(int)reg, right:(int)reg), value:(int)ubyte) emit "stbx %value, %left, %right" cost 4; - out:(int)ubyte_to_be = in:(int)reg - emit "! reg -> ubyte" - cost 1; - - out:(int)ubyte_to_be = CIU41(value:(int)reg) - emit "! CIU41(reg) -> ubyte" - cost 1; - - out:(int)ubyte_to_be = CIU41(CII14(CIU41(value:(int)reg))) - emit "! CIU41(CII14(CIU41(reg))) -> ubyte" - cost 1; + /* Loads */ out:(int)reg = LOAD4(addr:address) emit "lwz %out, %addr" cost 4; - out:(int)reg = LOAD2(addr:address) + out:(int)ushort = LOAD2(addr:address) emit "lhz %out, %addr" cost 4; - out:(int)reg = LOAD1(addr:address) + out:(int)ubyte = LOAD1(addr:address) emit "lbz %out, %addr" cost 4; - out:(int)reg = CIU14(LOAD1(addr:address)) - emit "lbz %out, %addr" - cost 4; + /* Conversions to ubyte and ushort */ + + out:(int)ubyte = in:(int)reg + emit "mr %out, %in ! reg -> ubyte" + cost 1; + + out:(int)ubyte = CIU41(value:(int)reg) + emit "mr %out, %value ! CIU41(reg) -> ubyte" + cost 1; + + out:(int)ubyte = CIU41(CII14(CIU41(value:(int)reg))) + emit "mr %out, %value ! CIU41(CII14(CIU41(reg))) -> ubyte" + cost 1; + + out:(int)ushort = in:(int)reg + emit "mr %out, %in ! reg -> ushort" + cost 1; + + out:(int)ushort = CIU42(value:(int)reg) + emit "mr %out, %value ! CIU42(reg) -> ushort" + cost 1; + + out:(int)ushort = CIU42(CII24(CIU42(value:(int)reg))) + emit "mr %out, %value ! CIU42(CII24(CIU42(reg))) -> ushort" + cost 1; + + /* Conversions from ubyte and ushort */ + + out:(int)reg = CIU14(in:(int)ubyte) + emit "mr %out, %in ! CIU14" + cost 4; - out:(int)reg = CIU24(LOAD2(addr:address)) - emit "lhz %out, %addr" - cost 4; From 98fe70a7de240b243ea8959ea5060255f1992e0a Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 14 Oct 2016 22:17:02 +0200 Subject: [PATCH 103/230] Output register equality constraints work. --- mach/proto/mcg/hop.h | 1 + mach/proto/mcg/pass_instructionselection.c | 10 +++- mach/proto/mcg/pass_registerallocator.c | 70 ++++++++++++++++++---- mach/proto/mcg/table | 21 ++++--- util/mcgg/gram.y | 8 +-- util/mcgg/iburg.c | 34 ++++++++++- util/mcgg/iburg.h | 2 - util/mcgg/mcgg.h | 1 + 8 files changed, 119 insertions(+), 28 deletions(-) diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 7dcbfd87a..ab2b39d59 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -26,6 +26,7 @@ struct insel struct constraint { uint32_t attrs; + struct vreg* equals_to; }; struct hop diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index b87ede3aa..7e38efe4b 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -113,6 +113,13 @@ static void constrain_output_reg(uint32_t attr) get_constraint(vreg)->attrs = attr; } +static void constrain_output_reg_equal_to(int child) +{ + struct vreg* vreg = find_vreg_of_child(child); + + get_constraint(current_hop->output)->equals_to = vreg; +} + static const struct burm_emitter_data emitter_data = { &emit_string, @@ -122,7 +129,8 @@ static const struct burm_emitter_data emitter_data = &emit_value, &emit_eoi, &constrain_input_reg, - &constrain_output_reg + &constrain_output_reg, + &constrain_output_reg_equal_to, }; static void emit(struct insn* insn) diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 42f43ef33..6f2cff26a 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -142,26 +142,74 @@ static void add_output_register(struct vreg* vreg) { struct hreg* hreg; int i; + struct constraint* c; - /* Find an unused output register of the right class. */ + /* Is this register supposed to be the same as one of the input registers? + * */ - hreg = NULL; - for (i=0; iconstraints, vreg); + if (c->equals_to) { - hreg = hregs.item[i]; - if (allocatable(hreg, vreg) && - !pmap_findleft(current_outs, hreg)) + /* This output register is constrained to be in the same hreg as an + * input register (most likely for a 2op instruction). */ + + hreg = pmap_findright(current_ins, c->equals_to); + + /* If this register is current unused as an output, use it. */ + + if (!pmap_findleft(current_outs, hreg)) { - goto found; + pmap_add(current_outs, hreg, vreg); + return; } + + /* Okay, something's in it. Most likely it's a through being used as an + * input register. Trying to evict it would be pointless as that would + * also evict the input. So, we're going to have to do this the hard + * way: we try to allocate a matched set of input and output registers. + * */ + + hreg = NULL; + for (i=0; iequals_to); } + else + { + /* This is an ordinary new register. */ - /* If we couldn't find one, evict a register. */ + hreg = NULL; + for (i=0; i ubyte" + with %out == %in + emit "! reg -> ubyte" cost 1; out:(int)ubyte = CIU41(value:(int)reg) - emit "mr %out, %value ! CIU41(reg) -> ubyte" + with %out == %value + emit "! CIU41(reg) -> ubyte" cost 1; out:(int)ubyte = CIU41(CII14(CIU41(value:(int)reg))) - emit "mr %out, %value ! CIU41(CII14(CIU41(reg))) -> ubyte" + with %out == %value + emit "! CIU41(CII14(CIU41(reg))) -> ubyte" cost 1; out:(int)ushort = in:(int)reg - emit "mr %out, %in ! reg -> ushort" + with %out == %in + emit "! reg -> ushort" cost 1; out:(int)ushort = CIU42(value:(int)reg) - emit "mr %out, %value ! CIU42(reg) -> ushort" + with %out == %value + emit "! CIU42(reg) -> ushort" cost 1; out:(int)ushort = CIU42(CII24(CIU42(value:(int)reg))) - emit "mr %out, %value ! CIU42(CII24(CIU42(reg))) -> ushort" + with %out == %value + emit "! CIU42(CII24(CIU42(reg))) -> ushort" cost 1; /* Conversions from ubyte and ushort */ out:(int)reg = CIU14(in:(int)ubyte) - emit "mr %out, %in ! CIU14" + with %out == %in + emit "! CIU14" cost 4; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index f6f39ae0f..3fe5f9c10 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -143,12 +143,8 @@ constraints constraint : '(' constraint ')' { $$ = $2; } - | ID ID { $$ = calloc(1, sizeof(*$$)); - $$->type = CONSTRAINT_ATTR; $$->left = $1; $$->right = $2; } - | ID EQUALS ID { $$ = calloc(1, sizeof(*$$)); - $$->type = CONSTRAINT_EQUALS; $$->left = $1; $$->right = $3; } - | ID NOTEQUALS ID { $$ = calloc(1, sizeof(*$$)); - $$->type = CONSTRAINT_NOTEQUALS; $$->left = $1; $$->right = $3; } + | '%' ID EQUALS '%' ID { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_EQUALS; $$->left = $2; $$->right = $5; } ; qfragments diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index bf3a698d1..a3d9568e8 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -1096,6 +1096,36 @@ static void emit_input_regs(Tree node, int* index) emit_input_regs(node->right, index); } +static void emit_output_constraints(Rule r) +{ + int i; + struct constraint* outputc = NULL; + + for (i=0; iconstraints.count; i++) + { + struct constraint* c = r->constraints.item[i]; + + if (c->type == CONSTRAINT_EQUALS) + { + if (strcmp(c->left, r->label) != 0) + yyerror("equality register constraints must have an output register on the left hand side"); + if (outputc != NULL) + yyerror("you can't specify more than one output register constraint"); + outputc = c; + } + } + + if (outputc) + { + int index = 0; + + if (!find_child_index(r->pattern, outputc->right, &index, NULL)) + label_not_found(r, outputc->right); + + print("%1data->constrain_output_reg_equal_to(%d);\n", index); + } +} + /* emitinsndata - emit the code generation data */ static void emitinsndata(Rule rules) { @@ -1129,7 +1159,9 @@ static void emitinsndata(Rule rules) int index = 0; emit_input_regs(r->pattern, &index); } - + + emit_output_constraints(r); + while (f) { switch (f->data[0]) diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 34c046e13..ebd22fbe3 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -19,9 +19,7 @@ typedef struct term* Term; enum { - CONSTRAINT_ATTR, CONSTRAINT_EQUALS, - CONSTRAINT_NOTEQUALS }; struct constraint diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 94e5b67bf..c0c9d87fb 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -46,6 +46,7 @@ struct burm_emitter_data void (*emit_eoi)(void); void (*constrain_input_reg)(int child, uint32_t attr); void (*constrain_output_reg)(uint32_t attr); + void (*constrain_output_reg_equal_to)(int child); }; typedef void burm_emitter_t(const struct burm_emitter_data* data); From bb53a7fb5123ec25a391396d00711fd29790550f Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 14 Oct 2016 23:12:29 +0200 Subject: [PATCH 104/230] Fix stupid issue where hop output registers were being overwritten, leading to invalid SSA form. --- mach/proto/mcg/pass_instructionselection.c | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 7e38efe4b..e8c9c453f 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -181,26 +181,26 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) if (!insn->insndata->is_fragment) { - struct vreg* vreg = NULL; - - switch (node->label) - { - case ir_to_esn(IR_REG, 1): - case ir_to_esn(IR_REG, 2): - case ir_to_esn(IR_REG, 4): - case ir_to_esn(IR_REG, 8): - vreg = node->ir->result; - break; - - case ir_to_esn(IR_NOP, 0): - vreg = node->left->ir->result; - break; - } - insn->hop = current_hop = new_hop(current_bb, insn->ir); - current_hop->output = vreg; emit(insn); + if (!current_hop->output) + { + switch (node->label) + { + case ir_to_esn(IR_REG, 1): + case ir_to_esn(IR_REG, 2): + case ir_to_esn(IR_REG, 4): + case ir_to_esn(IR_REG, 8): + current_hop->output = node->ir->result; + break; + + case ir_to_esn(IR_NOP, 0): + current_hop->output = node->left->ir->result; + break; + } + } + hop_print('I', current_hop); array_append(¤t_bb->hops, current_hop); From a63052427ead9a8c85fa7143f834d05239b25bde Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 14 Oct 2016 23:17:06 +0200 Subject: [PATCH 105/230] Factor out the register allocation routines to make them easier to deal with. --- mach/proto/mcg/pass_registerallocator.c | 111 ++++++++++++++---------- 1 file changed, 67 insertions(+), 44 deletions(-) diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 6f2cff26a..9068c5958 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -105,6 +105,61 @@ static bool allocatable(struct hreg* hreg, struct vreg* vreg) return (hreg->attrs & c->attrs); } +static struct hreg* find_input_reg(struct vreg* vreg) +{ + int i; + struct hreg* hreg = NULL; + + for (i=0; i %s\n", + c->equals_to->id, hreg->name); pmap_add(current_ins, hreg, c->equals_to); } else { /* This is an ordinary new register. */ - hreg = NULL; - for (i=0; i Date: Fri, 14 Oct 2016 23:19:02 +0200 Subject: [PATCH 106/230] Reworked loads and stores; it's now *different*, maybe not better. --- mach/proto/mcg/table | 155 +++++++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 58 deletions(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 88fc59159..4653e2d60 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -77,8 +77,10 @@ REGISTERS DECLARATIONS cr; - ubyte; - ushort; + ubyteX; /* bottom 8 bits valid, the rest undefined */ + ubyte0; /* bottom 8 bits valid, the rest 0 */ + ushortX; /* bottom 16 bits valid, the rest undefined */ + ushort0; /* bottom 16 bits valid, the rest 0 */ address fragment; @@ -134,19 +136,19 @@ PATTERNS emit "stw %value, %addr" cost 4; - STORE2(addr:address, value:(int)ushort) + STORE2(addr:address, value:(int)ushortX) emit "sth %value, %addr" cost 4; - STORE2(ADD4(left:(int)reg, right:(int)reg), value:(int)ushort) + STORE2(ADD4(left:(int)reg, right:(int)reg), value:(int)ushortX) emit "sthx %value, %left, %right" cost 4; - STORE1(addr:address, value:(int)ubyte) + STORE1(addr:address, value:(int)ubyteX) emit "stb %value, %addr" cost 4; - STORE1(ADD4(left:(int)reg, right:(int)reg), value:(int)ubyte) + STORE1(ADD4(left:(int)reg, right:(int)reg), value:(int)ubyteX) emit "stbx %value, %left, %right" cost 4; @@ -156,54 +158,107 @@ PATTERNS emit "lwz %out, %addr" cost 4; - out:(int)ushort = LOAD2(addr:address) + out:(int)ushort0 = LOAD2(addr:address) emit "lhz %out, %addr" cost 4; - out:(int)ubyte = LOAD1(addr:address) + out:(int)ubyte0 = LOAD1(addr:address) emit "lbz %out, %addr" cost 4; - /* Conversions to ubyte and ushort */ + /* ubyte intrinsics */ - out:(int)ubyte = in:(int)reg + out:(int)ubyteX = in:(int)ubyte0 with %out == %in - emit "! reg -> ubyte" + emit "! ubyte0 -> ubyteX" cost 1; - out:(int)ubyte = CIU41(value:(int)reg) - with %out == %value - emit "! CIU41(reg) -> ubyte" - cost 1; - - out:(int)ubyte = CIU41(CII14(CIU41(value:(int)reg))) - with %out == %value - emit "! CIU41(CII14(CIU41(reg))) -> ubyte" - cost 1; - - out:(int)ushort = in:(int)reg - with %out == %in - emit "! reg -> ushort" - cost 1; - - out:(int)ushort = CIU42(value:(int)reg) - with %out == %value - emit "! CIU42(reg) -> ushort" - cost 1; - - out:(int)ushort = CIU42(CII24(CIU42(value:(int)reg))) - with %out == %value - emit "! CIU42(CII24(CIU42(reg))) -> ushort" - cost 1; - - /* Conversions from ubyte and ushort */ - - out:(int)reg = CIU14(in:(int)ubyte) - with %out == %in - emit "! CIU14" + out:(int)ubyte0 = in:(int)ubyteX + emit "andi %out, %in, 0xff ! ubyteX -> ubyte0" cost 4; - + out:(int)reg = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> reg" + cost 4; + + out:(int)ubyteX = in:(int)reg + with %out == %in + emit "! reg -> ubyteX" + cost 1; + + /* ushort intrinsics */ + + out:(int)ushortX = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> ushortX" + cost 1; + + out:(int)ushort0 = in:(int)ushortX + emit "andi %out, %in, 0xff ! ushortX -> ushort0" + cost 4; + + out:(int)reg = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> reg" + cost 4; + + out:(int)ushortX = in:(int)reg + with %out == %in + emit "! reg -> ushortX" + cost 1; + + /* byte conversions */ + + out:(int)ubyte0 = CIU14(in:(int)ubyte0) + with %out == %in + emit "! CIU14(ubyte0) -> ubyte0" + cost 1; + + out:(int)ubyte0 = CIU41(in:(int)ubyte0) + with %out == %in + emit "! CIU41(ubyte0) -> ubyte0" + cost 1; + + out:(int)ubyteX = CIU41(in:(int)ubyteX) + with %out == %in + emit "! CIU41(ubyteX) -> ubyteX" + cost 1; + + out:(int)reg = CII14(in:(int)ubyte0) + with %out == %in + emit "! CII14(ubyte0) -> reg" + cost 4; + + out:(int)reg = CII14(in:(int)ubyteX) + emit "extsb %out, %in ! CII14(ubyteX) -> reg" + cost 4; + + /* short conversions */ + + out:(int)ushort0 = CIU24(in:(int)ushort0) + with %out == %in + emit "! CIU24(ushort0) -> ushort0" + cost 1; + + out:(int)ushort0 = CIU42(in:(int)ushort0) + with %out == %in + emit "! CIU42(ushort0) -> ushort0" + cost 1; + + out:(int)ushortX = CIU42(in:(int)ushortX) + with %out == %in + emit "! CIU42(ushortX) -> ushortX" + cost 1; + + out:(int)reg = CII24(in:(int)ushort0) + with %out == %in + emit "! CII24(ushort0) -> reg" + cost 4; + + out:(int)reg = CII24(in:(int)ushortX) + emit "extsh %out, %in" + cost 4; /* Locals */ @@ -304,22 +359,6 @@ PATTERNS /* Conversions */ - out:(int)reg = CII14(CIU41(value:(int)reg)) - emit "extsb %out, %value" - cost 4; - - out:(int)reg = CII24(CIU42(value:(int)reg)) - emit "extsh %out, %value" - cost 4; - - out:(int)reg = CIU41(in:(int)reg) - emit "andi %out, %in, 0xff" - cost 4; - - out:(int)reg = CIU42(in:(int)reg) - emit "andi %out, %in, 0xffff" - cost 4; - out:(int)reg = CIU44(in:(int)reg) emit "mr %out, %in ! ciu44" cost 4; From 886adb86d741d3d985eb89439911fc5732f2aec4 Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 14 Oct 2016 23:19:25 +0200 Subject: [PATCH 107/230] Log empty hops. --- mach/proto/mcg/hop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index f9873136b..b42cd9548 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -178,7 +178,14 @@ void hop_print(char k, struct hop* hop) hop_render(hop); + print_header(k, hop); + p = strtok(buffer, "\n"); + if (!p) + { + print_header(k, hop); + tracef(k, "\n"); + } while (p) { print_header(k, hop); From bb17aea73ac6fb48f3436f656c245e8ed91298fb Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 01:15:08 +0200 Subject: [PATCH 108/230] You can now mark a register as corrupting a certain register class; calls work, or at least look like they work. The bad news is that the register allocator has a rare talent for putting things in the wrong register. --- mach/proto/mcg/hop.c | 17 ++-- mach/proto/mcg/hop.h | 1 + mach/proto/mcg/pass_instructionselection.c | 1 + mach/proto/mcg/pass_registerallocator.c | 102 +++++++++++++++------ mach/proto/mcg/table | 2 + util/mcgg/gram.y | 3 + util/mcgg/iburg.c | 21 +++++ util/mcgg/iburg.h | 1 + util/mcgg/mcgg.h | 1 + util/mcgg/scan.l | 1 + 10 files changed, 115 insertions(+), 35 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index b42cd9548..6b84c62a7 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -178,20 +178,19 @@ void hop_print(char k, struct hop* hop) hop_render(hop); - print_header(k, hop); - p = strtok(buffer, "\n"); - if (!p) - { - print_header(k, hop); - tracef(k, "\n"); - } + print_header(k, hop); while (p) { - print_header(k, hop); - tracef(k, "%s\n", p); + tracef(k, "%s", p); p = strtok(NULL, "\n"); + if (p) + { + tracef(k, "\n"); + print_header(k, hop); + } } + tracef(k, "\n"); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index ab2b39d59..1dbf5772c 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -34,6 +34,7 @@ struct hop int id; struct basicblock* bb; struct ir* ir; + const struct burm_instruction_data* insndata; ARRAYOF(struct insel) insels; struct vreg* output; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index e8c9c453f..9b5a615c6 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -182,6 +182,7 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) if (!insn->insndata->is_fragment) { insn->hop = current_hop = new_hop(current_bb, insn->ir); + current_hop->insndata = insn->insndata; emit(insn); if (!current_hop->output) diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 9068c5958..fffc6a138 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -99,10 +99,19 @@ static struct hreg* evict(struct vreg* vreg) assert(false); } -static bool allocatable(struct hreg* hreg, struct vreg* vreg) +static bool allocatable_input(struct hreg* hreg, struct vreg* vreg) { struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); - return (hreg->attrs & c->attrs); + return !pmap_findleft(current_ins, hreg) && + (!c || (hreg->attrs & c->attrs)); +} + +static bool allocatable_output(struct hreg* hreg, struct vreg* vreg) +{ + struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + return !pmap_findleft(current_outs, hreg) && + (!c || (hreg->attrs & c->attrs)) && + !(hreg->attrs & current_hop->insndata->corrupts); } static struct hreg* find_input_reg(struct vreg* vreg) @@ -113,8 +122,7 @@ static struct hreg* find_input_reg(struct vreg* vreg) for (i=0; iconstraints, vreg); if (c->equals_to) { + tracef('R', "R: outputput equality constraint of %%%d to %%%d\n", + vreg->id, c->equals_to->id); + /* This output register is constrained to be in the same hreg as an * input register (most likely for a 2op instruction). */ hreg = pmap_findright(current_ins, c->equals_to); - /* If this register is current unused as an output, use it. */ + /* If this register is currently unused as an output, use it. */ - if (!pmap_findleft(current_outs, hreg)) + if (allocatable_output(hreg, c->equals_to)) { pmap_add(current_outs, hreg, vreg); return; @@ -235,6 +256,38 @@ static void add_output_register(struct vreg* vreg) } } +static void add_through_register(struct vreg* vreg, struct hreg* hreg) +{ + /* Register hint for an input? */ + + if (hreg) + { + bool infree = allocatable_input(hreg, vreg); + bool outfree = allocatable_output(hreg, vreg); + + if (infree && outfree) + { + /* Register unused --- use it. */ + } + if ((infree || pmap_findleft(current_ins, hreg) == vreg) && + (outfree || pmap_findleft(current_outs, hreg) == vreg)) + { + /* Input and output are either free or already assigned. */ + } + else + { + /* Nope, can't honour the hint. */ + hreg = NULL; + } + } + + if (!hreg) + hreg = find_through_reg(vreg); + + pmap_put(current_ins, hreg, vreg); + pmap_put(current_outs, hreg, vreg); +} + static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* src) { uint32_t srctype = src->type; @@ -249,8 +302,8 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s { hreg = hregs.item[i]; if ((hreg->type == src->type) && - !pmap_findleft(current_ins, hreg) && - !pmap_findleft(current_outs, hreg)) + allocatable_input(hreg, vreg) && + allocatable_output(hreg, vreg)) { goto found; } @@ -283,10 +336,7 @@ static void select_registers(struct hop* hop, { struct vreg* vreg = hop->throughs.item[i]; struct hreg* hreg = pmap_findright(old, vreg); - assert(hreg != NULL); - - pmap_put(current_ins, hreg, vreg); - pmap_put(current_outs, hreg, vreg); + add_through_register(vreg, hreg); } /* Any registers being *read* by the instruction should also stay where diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 4653e2d60..dce199cae 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -305,10 +305,12 @@ PATTERNS cost 8; CALL(dest:LABEL4) + with corrupted(volatile) emit "bl $dest" cost 4; CALL(dest:(int)reg) + with corrupted(volatile) emit "mtspr ctr, %dest" emit "bcctrl ALWAYS, 0, 0" cost 8; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 3fe5f9c10..748d3fa38 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -26,6 +26,7 @@ extern int yylex(void); } %term COPY +%term CORRUPTED %term COST %term DECLARATIONS %term EMIT @@ -145,6 +146,8 @@ constraint : '(' constraint ')' { $$ = $2; } | '%' ID EQUALS '%' ID { $$ = calloc(1, sizeof(*$$)); $$->type = CONSTRAINT_EQUALS; $$->left = $2; $$->right = $5; } + | CORRUPTED '(' ID ')' { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_CORRUPTED_ATTR; $$->left = $3; } ; qfragments diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index a3d9568e8..ff8b1e973 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -1239,6 +1239,27 @@ static void emitinsndata(Rule rules) print("%2%s,\n", r->lhs->is_fragment ? "true" : "false"); + { + int i; + uint32_t attrs = 0; + + for (i=0; iconstraints.count; i++) + { + struct constraint* c = r->constraints.item[i]; + + if (c->type == CONSTRAINT_CORRUPTED_ATTR) + { + struct regattr* p = smap_get(®isterattrs, c->left); + if (!p) + yyerror("no such register attribute '%s'", c->left); + + attrs |= 1<<(p->number); + } + } + + print("%2%d, /* corruption attrs */\n", attrs); + } + print("%1},\n"); r = r->link; } diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index ebd22fbe3..689a84177 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -20,6 +20,7 @@ typedef struct term* Term; enum { CONSTRAINT_EQUALS, + CONSTRAINT_CORRUPTED_ATTR, }; struct constraint diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index c0c9d87fb..242c1efcd 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -56,6 +56,7 @@ struct burm_instruction_data const char* name; burm_emitter_t* emitter; bool is_fragment; + uint32_t corrupts; }; extern const struct burm_instruction_data burm_instruction_data[]; diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 68de96ed4..d6a60d361 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -38,6 +38,7 @@ static int braces = 0; "DECLARATIONS" return DECLARATIONS; "PATTERNS" return PATTERNS; "REGISTERS" return REGISTERS; +"corrupted" return CORRUPTED; "cost" return COST; "emit" return EMIT; "fragment" return FRAGMENT; From b2ddf124732f9595d3a79d3bf408d4e724135d19 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 11:22:40 +0200 Subject: [PATCH 109/230] Some more opcodes. --- mach/proto/mcg/treebuilder.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 4060b206f..c2083b8ab 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -504,6 +504,23 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_lof: + { + struct ir* ptr = pop(EM_pointersize); + + push( + new_ir1( + IR_LOAD, EM_wordsize, + new_ir2( + IR_ADD, EM_pointersize, + ptr, + new_wordir(value) + ) + ) + ); + break; + } + case op_sti: { struct ir* ptr = pop(EM_pointersize); @@ -518,6 +535,25 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_stf: + { + struct ir* ptr = pop(EM_pointersize); + struct ir* val = pop(value); + + appendir( + new_ir2( + IR_STORE, EM_wordsize, + new_ir2( + IR_ADD, EM_pointersize, + ptr, + new_wordir(value) + ), + val + ) + ); + break; + } + case op_cmi: push( tristate_compare(value, IR_COMPARES) From 517120d0fbca0e3ebbacd1997e714029b50c13a9 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 11:42:47 +0200 Subject: [PATCH 110/230] Allow asm names for registers which are different from the friendly names shown in the tracing (because PowerPC register names are just numbers). --- mach/proto/mcg/hop.c | 4 +- mach/proto/mcg/reg.c | 2 + mach/proto/mcg/reg.h | 1 + mach/proto/mcg/table | 124 +++++++++++++++++++++---------------------- util/mcgg/gram.y | 2 +- util/mcgg/iburg.c | 6 ++- util/mcgg/iburg.h | 5 +- util/mcgg/mcgg.h | 1 + 8 files changed, 76 insertions(+), 69 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 6b84c62a7..a362f8b79 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -123,7 +123,7 @@ char* hop_render(struct hop* hop) case INSEL_HREG: { struct hreg* hreg = insel->u.hreg; - appendf("%s", hreg->name); + appendf("%s", hreg->realname); break; } @@ -134,7 +134,7 @@ char* hop_render(struct hop* hop) if (!hreg) hreg = pmap_findright(&hop->regsout, vreg); if (hreg) - appendf("%s", hreg->name); + appendf("%s", hreg->realname); else appendf("%%%d", vreg->id); break; diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c index 848c1cd98..bb7266504 100644 --- a/mach/proto/mcg/reg.c +++ b/mach/proto/mcg/reg.c @@ -13,6 +13,7 @@ struct hreg* new_hreg(const struct burm_register_data* brd) { struct hreg* hreg = calloc(1, sizeof *hreg); hreg->name = brd->name; + hreg->realname = brd->realname; hreg->attrs = brd->attrs; hreg->is_stacked = false; return hreg; @@ -22,6 +23,7 @@ struct hreg* new_stacked_hreg(int offset, uint32_t attrs) { struct hreg* hreg = calloc(1, sizeof *hreg); hreg->name = aprintf("stacked_%d", offset); + hreg->realname = hreg->name; hreg->attrs = attrs; hreg->is_stacked = true; hreg->offset = offset; diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index 753109063..f1b5e1b05 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -14,6 +14,7 @@ struct phicongruence struct hreg { const char* name; + const char* realname; uint32_t type; uint32_t attrs; bool is_stacked; diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index dce199cae..ad94b05b9 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -7,71 +7,71 @@ REGISTERS * a register into another register (e.g. for eviction). */ - r12 bytes4! int! volatile; - r11 bytes4! int! volatile; - r10 bytes4! int! volatile; - r9 bytes4! int! volatile; - r8 bytes4! int! volatile; - r7 bytes4! int! volatile; - r6 bytes4! int! volatile; - r5 bytes4! int! volatile; - r4 bytes4! int! volatile; - r3 bytes4! int! ret volatile; + r12 "12" bytes4! int! volatile; + r11 "11" bytes4! int! volatile; + r10 "10" bytes4! int! volatile; + r9 "9" bytes4! int! volatile; + r8 "8" bytes4! int! volatile; + r7 "7" bytes4! int! volatile; + r6 "6" bytes4! int! volatile; + r5 "5" bytes4! int! volatile; + r4 "4" bytes4! int! volatile; + r3 "3" bytes4! int! ret volatile; - r31 bytes4! int!; - r30 bytes4! int!; - r29 bytes4! int!; - r28 bytes4! int!; - r27 bytes4! int!; - r26 bytes4! int!; - r25 bytes4! int!; - r24 bytes4! int!; - r23 bytes4! int!; - r22 bytes4! int!; - r21 bytes4! int!; - r20 bytes4! int!; - r19 bytes4! int!; - r18 bytes4! int!; - r17 bytes4! int!; - r16 bytes4! int!; - r15 bytes4! int!; - r14 bytes4! int!; + r31 "31" bytes4! int!; + r30 "30" bytes4! int!; + r29 "29" bytes4! int!; + r28 "28" bytes4! int!; + r27 "27" bytes4! int!; + r26 "26" bytes4! int!; + r25 "25" bytes4! int!; + r24 "24" bytes4! int!; + r23 "23" bytes4! int!; + r22 "22" bytes4! int!; + r21 "21" bytes4! int!; + r20 "20" bytes4! int!; + r19 "19" bytes4! int!; + r18 "18" bytes4! int!; + r17 "17" bytes4! int!; + r16 "16" bytes4! int!; + r15 "15" bytes4! int!; + r14 "14" bytes4! int!; - f14 bytes4! float! volatile; - f13 bytes4! float! volatile; - f12 bytes4! float! volatile; - f11 bytes4! float! volatile; - f10 bytes4! float! volatile; - f9 bytes4! float! volatile; - f8 bytes4! float! volatile; - f7 bytes4! float! volatile; - f6 bytes4! float! volatile; - f5 bytes4! float! volatile; - f4 bytes4! float! volatile; - f3 bytes4! float! volatile; - f2 bytes4! float! volatile; - f1 bytes4! float! volatile; - f0 bytes4! float! volatile; + f14 "14" bytes4! float! volatile; + f13 "13" bytes4! float! volatile; + f12 "12" bytes4! float! volatile; + f11 "11" bytes4! float! volatile; + f10 "10" bytes4! float! volatile; + f9 "9" bytes4! float! volatile; + f8 "8" bytes4! float! volatile; + f7 "7" bytes4! float! volatile; + f6 "6" bytes4! float! volatile; + f5 "5" bytes4! float! volatile; + f4 "4" bytes4! float! volatile; + f3 "3" bytes4! float! volatile; + f2 "2" bytes4! float! volatile; + f1 "1" bytes4! float! volatile; + f0 "0" bytes4! float! volatile; - f31 bytes4! float!; - f30 bytes4! float!; - f29 bytes4! float!; - f28 bytes4! float!; - f27 bytes4! float!; - f26 bytes4! float!; - f25 bytes4! float!; - f24 bytes4! float!; - f23 bytes4! float!; - f22 bytes4! float!; - f21 bytes4! float!; - f20 bytes4! float!; - f19 bytes4! float!; - f18 bytes4! float!; - f17 bytes4! float!; - f16 bytes4! float!; - f15 bytes4! float!; - - cr0 cr!; + f31 "31" bytes4! float!; + f30 "30" bytes4! float!; + f29 "29" bytes4! float!; + f28 "28" bytes4! float!; + f27 "27" bytes4! float!; + f26 "26" bytes4! float!; + f25 "25" bytes4! float!; + f24 "24" bytes4! float!; + f23 "23" bytes4! float!; + f22 "22" bytes4! float!; + f21 "21" bytes4! float!; + f20 "20" bytes4! float!; + f19 "19" bytes4! float!; + f18 "18" bytes4! float!; + f17 "17" bytes4! float!; + f16 "16" bytes4! float!; + f15 "15" bytes4! float!; + + cr0 "cr0" cr!; DECLARATIONS diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 748d3fa38..9155271fc 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -71,7 +71,7 @@ registers ; register - : ID { $$ = makereg($1); } + : ID QFRAGMENT { $$ = makereg($1, $2); } | register ID { $$ = $1; addregattr($1, $2, false); } | register ID '!' { $$ = $1; addregattr($1, $2, true); } ; diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index ff8b1e973..390853201 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -253,7 +253,7 @@ static void* install(const char* name) return &p->sym; } -struct reg* makereg(const char* id) +struct reg* makereg(const char* id, const char* realname) { struct reg* p = smap_get(®isters, id); static int number = 0; @@ -262,6 +262,7 @@ struct reg* makereg(const char* id) yyerror("redefinition of '%s'", id); p = calloc(1, sizeof(*p)); p->name = id; + p->realname = realname; p->number = number++; smap_put(®isters, id, p); @@ -591,7 +592,8 @@ static void emitregisters(void) struct reg* r = registers.item[i].right; assert(r->number == i); - print("%1{ \"%s\", 0x%x, 0x%x },\n", r->name, r->type, r->attrs); + print("%1{ \"%s\", \"%s\", 0x%x, 0x%x },\n", + r->name, r->realname, r->type, r->attrs); } print("%1{ NULL }\n"); print("};\n\n"); diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 689a84177..48397c21e 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -58,7 +58,8 @@ struct terminfo struct reg { - const char* name; /* register name */ + const char* name; /* friendly register name */ + const char* realname; /* name used in assembly output */ int number; /* identifying number */ uint32_t attrs; /* bitfield of register attributes */ uint32_t type; /* register type */ @@ -70,7 +71,7 @@ struct regattr int number; /* identifying number */ }; -extern struct reg* makereg(const char* name); +extern struct reg* makereg(const char* name, const char* realname); extern void addregattr(struct reg* reg, const char* regattr, bool exact); extern struct regattr* getregattr(const char* name); diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 242c1efcd..2631e0097 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -64,6 +64,7 @@ extern const struct burm_instruction_data burm_instruction_data[]; struct burm_register_data { const char* name; + const char* realname; uint32_t type; uint32_t attrs; }; From 358c44de35c10e3e9aff84ee2e726206698d302b Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 12:11:40 +0200 Subject: [PATCH 111/230] Bytes were sometimes failing to be sign extended correctly. --- mach/proto/mcg/table | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index ad94b05b9..9a9493199 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -225,11 +225,6 @@ PATTERNS emit "! CIU41(ubyteX) -> ubyteX" cost 1; - out:(int)reg = CII14(in:(int)ubyte0) - with %out == %in - emit "! CII14(ubyte0) -> reg" - cost 4; - out:(int)reg = CII14(in:(int)ubyteX) emit "extsb %out, %in ! CII14(ubyteX) -> reg" cost 4; From 5ad3aa8595d4b42e9188388a0f3c1970d3ba9744 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 13:07:59 +0200 Subject: [PATCH 112/230] Add a pile of new instructions used by Pascal; I'm going to need to think about how locals and the local base are handled. --- mach/proto/mcg/parse_em.c | 16 +++++ mach/proto/mcg/table | 30 ++++++++ mach/proto/mcg/treebuilder.c | 131 +++++++++++++++++++++++++++++++++++ util/mcgg/ir.dat | 3 + 4 files changed, 180 insertions(+) diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 167910ad4..27e3a8dda 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -243,6 +243,10 @@ static void parse_pseu(void) data_offset(dlabel_to_str(em.em_dlb), em.em_off, ro); break; + case sof_ptyp: + data_offset(strdup(em.em_dnam), em.em_off, ro); + break; + case ilb_ptyp: { const char* label = ilabel_to_str(em.em_ilb); @@ -279,6 +283,18 @@ static void parse_pseu(void) data_bss(EM_bsssize, em.em_cst); break; + case ico_ptyp: + case uco_ptyp: + { + arith val = atol(em.em_string); + data_int(val, em.em_size, false); + break; + } + + case sof_ptyp: + data_offset(strdup(em.em_dnam), em.em_off, false); + break; + default: unknown_type("bss"); } diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 9a9493199..6a24d9e6b 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -126,6 +126,18 @@ PATTERNS emit "addi sp, sp, $delta" cost 4; + out:(int)reg = GETFP4 + emit "mr %out, fp" + cost 4; + + out:(int)reg = FPTOARGS4(GETFP4) + emit "addi %out, fp, 8" + cost 4; + + out:(int)reg = FPTOARGS4(in:(int)reg) + emit "addi %out, %in, 8" + cost 4; + /* Memory operations */ @@ -354,6 +366,20 @@ PATTERNS +/* Booleans */ + + out:(int)reg = IFEQ4(in:(cr)cr) + emit "mfcr %out" /* get cr0 */ + emit "rlwinmi %out, %out, 32-2, 2, 31" /* extract just EQ */ + cost 8; + + out:(int)reg = IFEQ4(in:(int)reg) + emit "cntlzw %out, %in" /* returns 0..32 */ + emit "rlwinmi %out, %out, 32-5, 5, 31" /* if 32, return 1, otherwise 0 */ + cost 8; + + + /* Conversions */ out:(int)reg = CIU44(in:(int)reg) @@ -406,6 +432,10 @@ PATTERNS emit "neg %out, %left" cost 4; + out:(int)reg = OR4(left:(int)reg, right:(int)reg) + emit "or %out, %right, %left" + cost 4; + out:(int)reg = EOR4(left:(int)reg, right:(int)reg) emit "xor %out, %right, %left" cost 4; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index c2083b8ab..7f0abd19d 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -204,6 +204,15 @@ static void insn_simple(int opcode) ); break; + case op_teq: + push( + new_ir1( + IR_IFEQ, EM_wordsize, + pop(EM_wordsize) + ) + ); + break; + case op_cai: { struct ir* dest = pop(EM_pointersize); @@ -242,6 +251,35 @@ static void insn_simple(int opcode) break; } + case op_lim: + { + push( + new_ir1( + IR_LOAD, 2, + new_labelir(".ignmask") + ) + ); + break; + } + + case op_sim: + { + appendir( + new_ir2( + IR_STORE, 2, + new_labelir(".ignmask"), + pop(EM_wordsize) + ) + ); + break; + } + + case op_lni: + { + /* Increment line number --- ignore. */ + break; + } + default: fatal("treebuilder: unknown simple instruction '%s'", em_mnem[opcode - sp_fmnem]); @@ -561,6 +599,7 @@ static void insn_ivalue(int opcode, arith value) break; case op_cmu: + case op_cms: push( tristate_compare(value, IR_COMPAREU) ); @@ -717,6 +756,92 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_sar: + case op_lar: + case op_aar: + { + const char* helper; + if (value != EM_wordsize) + fatal("sar/lar/aar are only supported when using " + "word-size descriptors"); + + switch (opcode) + { + case op_sar: helper = ".sar4"; break; + case op_lar: helper = ".lar4"; break; + case op_aar: helper = ".aar4"; break; + } + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(helper) + ) + ); + push( + new_ir0( + IR_GETRET, EM_wordsize + ) + ); + break; + } + + case op_lxl: + { + struct ir* ir; + + /* Walk the static chain. */ + + ir = new_ir0( + IR_GETFP, EM_pointersize + ); + + while (value--) + { + ir = new_ir1( + IR_CHAINFP, EM_pointersize, + ir + ); + } + + push(ir); + break; + } + + case op_lxa: + { + struct ir* ir; + + /* Walk the static chain. */ + + ir = new_ir0( + IR_GETFP, EM_pointersize + ); + + while (value--) + { + ir = new_ir1( + IR_CHAINFP, EM_pointersize, + ir + ); + } + + push( + new_ir1( + IR_FPTOARGS, EM_pointersize, + ir + ) + ); + break; + } + + case op_lin: + { + /* Set line number --- ignore. */ + break; + } + default: fatal("treebuilder: unknown ivalue instruction '%s'", em_mnem[opcode - sp_fmnem]); @@ -783,6 +908,12 @@ static void insn_lvalue(int opcode, const char* label, arith offset) ) ); break; + + case op_fil: + { + /* Set filename --- ignore. */ + break; + } default: fatal("treebuilder: unknown lvalue instruction '%s'", diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 0667ee04d..44e28e9f8 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -86,4 +86,7 @@ V RET S STACKADJUST S GETRET S SETRET +S GETFP +S CHAINFP +S FPTOARGS From 9504aec2bdae275343f5d95497abfd61f70da3c7 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 18:38:46 +0200 Subject: [PATCH 113/230] Function termination gets routed through an exit block; we now have prologues and epilogues. mcgg now exports some useful data as headers. Start factoring out some of the architecture-specific bits into an architecture-specific file. --- mach/proto/mcg/build.lua | 7 +- mach/proto/mcg/hop.c | 49 ++++++++ mach/proto/mcg/hop.h | 2 + mach/proto/mcg/mcg.h | 6 + mach/proto/mcg/mcgg_generated_header.h | 1 - mach/proto/mcg/parse_em.c | 4 +- mach/proto/mcg/pass_instructionselection.c | 4 +- mach/proto/mcg/pass_prologueepilogue.c | 19 +++ mach/proto/mcg/pass_registerallocator.c | 17 +-- mach/proto/mcg/powerpc.c | 41 +++++++ mach/proto/mcg/procedure.c | 1 + mach/proto/mcg/procedure.h | 3 +- mach/proto/mcg/reg.c | 6 +- mach/proto/mcg/reg.h | 2 +- mach/proto/mcg/table | 129 +++++++++++---------- mach/proto/mcg/treebuilder.c | 24 +++- util/mcgg/build.lua | 3 +- util/mcgg/gram.y | 2 - util/mcgg/iburg.c | 117 ++++++++++--------- util/mcgg/iburg.h | 1 + 20 files changed, 285 insertions(+), 153 deletions(-) create mode 100644 mach/proto/mcg/pass_prologueepilogue.c create mode 100644 mach/proto/mcg/powerpc.c diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index 0626c4a3c..8fc41be95 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -9,10 +9,11 @@ cprogram { name = "mcg", srcs = { "./*.c", - "+mcgg_c", + matching(filenamesof("+mcgg_c"), "%.c$"), }, deps = { - "util/mcgg+lib", + "+mcgg_c", + "./*.h", "h+emheaders", "modules+headers", "modules/src/alloc+lib", @@ -23,7 +24,7 @@ cprogram { "modules/src/read_em+lib_ev", "modules/src/string+lib", "modules/src/system+lib", - "./*.h", + "util/mcgg+lib", }, vars = { ["+cflags"] = { diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index a362f8b79..3797d7b24 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -58,6 +58,55 @@ void hop_add_eoi_insel(struct hop* hop) array_append(&hop->insels, insel); } +void hop_add_insel(struct hop* hop, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + while (*fmt) + { + if (*fmt == '%') + { + fmt += 2; + switch (fmt[-1]) + { + case 'd': + hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int))); + break; + + case 'H': + hop_add_hreg_insel(hop, va_arg(ap, struct hreg*)); + break; + + case 'V': + hop_add_vreg_insel(hop, va_arg(ap, struct vreg*)); + break; + } + } + else + { + const char* end = strchr(fmt, '%'); + const char* s; + if (end) + { + int len = end - fmt; + s = strndup(fmt, len); + fmt = end; + } + else + { + s = fmt; + fmt += strlen(fmt); + } + + hop_add_string_insel(hop, s); + } + } + + hop_add_eoi_insel(hop); + va_end(ap); +} + static void print_header(char k, struct hop* hop) { int i; diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 1dbf5772c..dcc6fe03b 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -55,6 +55,8 @@ extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_eoi_insel(struct hop* hop); +extern void hop_add_insel(struct hop* hop, const char* fmt, ...); + extern char* hop_render(struct hop* hop); extern void hop_print(char k, struct hop* hop); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 0df947df7..5cd875ef4 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -28,6 +28,7 @@ #include "basicblock.h" #include "procedure.h" #include "graph.h" +#include "tables.h" extern char em_pseu[][4]; extern char em_mnem[][4]; @@ -109,12 +110,17 @@ extern void pass_group_irs(struct procedure* proc); extern void pass_insert_moves(void); extern void pass_instruction_selector(void); extern void pass_live_vreg_analysis(void); +extern void pass_add_prologue_epilogue(struct procedure* proc); extern void pass_promote_float_ops(struct procedure* proc); extern void pass_register_allocator(void); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_remove_dead_phis(void); extern void pass_split_critical_edges(struct procedure* proc); +extern struct hop* platform_prologue(struct procedure* proc); +extern struct hop* platform_epilogue(struct procedure* proc); +extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest); + extern FILE* outputfile; extern FILE* dominance_dot_file; extern FILE* cfg_dot_file; diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index 5d9b3ae2e..f0bfa99a0 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -1,7 +1,6 @@ #include "mcg.h" #include "mcgg.h" - #define PANIC printf #define burm_assert(b, s) assert(b) diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 27e3a8dda..2b88eac81 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -307,9 +307,9 @@ static void parse_pseu(void) current_proc = calloc(sizeof(struct procedure), 1); current_proc->name = strdup(em.em_pnam); - current_proc->root_bb = bb_get(current_proc->name); + current_proc->entry = bb_get(current_proc->name); current_proc->nlocals = em.em_nlocals; - code_bb = current_proc->root_bb; + code_bb = current_proc->entry; code_bb->is_root = true; array_append(¤t_proc->blocks, code_bb); diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 9b5a615c6..752648de5 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -205,7 +205,7 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) hop_print('I', current_hop); array_append(¤t_bb->hops, current_hop); - if (goal != 1) + if (goal != burm_stmt_NT) insn->ir->result = insn->hop->output; } } @@ -276,7 +276,7 @@ static void select_instructions(void) if (!insnno) burm_panic_cannot_match(shadow); - walk_instructions(shadow, 1); + walk_instructions(shadow, burm_stmt_NT); } } } diff --git a/mach/proto/mcg/pass_prologueepilogue.c b/mach/proto/mcg/pass_prologueepilogue.c new file mode 100644 index 000000000..056630707 --- /dev/null +++ b/mach/proto/mcg/pass_prologueepilogue.c @@ -0,0 +1,19 @@ +#include "mcg.h" + +void pass_add_prologue_epilogue(struct procedure* proc) +{ + struct hop* prologue = platform_prologue(proc); + array_insert(&proc->entry->hops, prologue, 0); + + if (proc->exit) + { + struct hop* epilogue = platform_epilogue(proc); + + proc->exit->hops.count = 0; + array_append(&proc->exit->hops, epilogue); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + + diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index fffc6a138..f967e3136 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -488,19 +488,6 @@ static void assign_hregs_to_vregs(void) } } -static struct hop* create_move(struct basicblock* bb, struct hreg* src, struct hreg* dest) -{ - struct hop* hop = new_hop(bb, NULL); - - hop_add_string_insel(hop, "! move "); - hop_add_hreg_insel(hop, src); - hop_add_string_insel(hop, " -> "); - hop_add_hreg_insel(hop, dest); - hop_add_eoi_insel(hop); - - return hop; -} - static struct hop* create_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) { struct hop* hop = new_hop(bb, NULL); @@ -558,7 +545,7 @@ static int insert_moves(struct basicblock* bb, int index, { /* Copy. */ - hop = create_move(bb, src, dest); + hop = platform_move(bb, src, dest); pmap_remove(&copies, src, dest); } else @@ -567,7 +554,7 @@ static int insert_moves(struct basicblock* bb, int index, src = copies.item[0].left; dest = pmap_findleft(&copies, src); - hop = create_move(bb, src, dest); + hop = create_swap(bb, src, dest); pmap_remove(&copies, src, dest); pmap_remove(&copies, dest, src); } diff --git a/mach/proto/mcg/powerpc.c b/mach/proto/mcg/powerpc.c new file mode 100644 index 000000000..b5c606110 --- /dev/null +++ b/mach/proto/mcg/powerpc.c @@ -0,0 +1,41 @@ +#include "mcg.h" + +struct hop* platform_prologue(struct procedure* proc) +{ + int framesize = proc->nlocals + 8; + int retbase = proc->nlocals; + + struct hop* hop = new_hop(proc->entry, NULL); + + hop_add_insel(hop, "addi sp, fp, %d", -framesize); + hop_add_insel(hop, "mfspr 0, lr"); + hop_add_insel(hop, "stw fp, %d(sp)", retbase); + hop_add_insel(hop, "stw 0, %d(sp)", retbase+4); + hop_add_insel(hop, "addi fp, sp, retbase"); + + return hop; +} + +struct hop* platform_epilogue(struct procedure* proc) +{ + struct hop* hop = new_hop(proc->exit, NULL); + + hop_add_insel(hop, "b .ret"); + + return hop; +} + +struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR)) + hop_add_insel(hop, "mr %H, %H", dest, src); + else + fatal("cannot generate move from %s to %s", src->name, dest->name); + + return hop; +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index af05f80e3..d6382b06d 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -190,6 +190,7 @@ void procedure_compile(struct procedure* proc) pass_live_vreg_analysis(); print_hops('8', proc); pass_register_allocator(); + pass_add_prologue_epilogue(proc); print_hops('9', proc); emit_procedure(proc); diff --git a/mach/proto/mcg/procedure.h b/mach/proto/mcg/procedure.h index 2414db050..9d653b3f4 100644 --- a/mach/proto/mcg/procedure.h +++ b/mach/proto/mcg/procedure.h @@ -11,7 +11,8 @@ struct local struct procedure { const char* name; - struct basicblock* root_bb; + struct basicblock* entry; + struct basicblock* exit; size_t nlocals; ARRAYOF(struct basicblock) blocks; IMAPOF(struct local) locals; diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c index bb7266504..2cb523764 100644 --- a/mach/proto/mcg/reg.c +++ b/mach/proto/mcg/reg.c @@ -14,17 +14,19 @@ struct hreg* new_hreg(const struct burm_register_data* brd) struct hreg* hreg = calloc(1, sizeof *hreg); hreg->name = brd->name; hreg->realname = brd->realname; + hreg->type = brd->type; hreg->attrs = brd->attrs; hreg->is_stacked = false; return hreg; } -struct hreg* new_stacked_hreg(int offset, uint32_t attrs) +struct hreg* new_stacked_hreg(int offset, uint32_t type) { struct hreg* hreg = calloc(1, sizeof *hreg); hreg->name = aprintf("stacked_%d", offset); hreg->realname = hreg->name; - hreg->attrs = attrs; + hreg->type = type; + hreg->attrs = type; hreg->is_stacked = true; hreg->offset = offset; return hreg; diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index f1b5e1b05..0f47dfd03 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -34,7 +34,7 @@ typedef PMAPOF(struct hreg, struct vreg) register_assignment_t; extern struct vreg* new_vreg(void); extern struct hreg* new_hreg(const struct burm_register_data* brd); -extern struct hreg* new_stacked_hreg(int offset, uint32_t attrs); +extern struct hreg* new_stacked_hreg(int offset, uint32_t type); #endif diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 6a24d9e6b..24b9d6e32 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -7,69 +7,69 @@ REGISTERS * a register into another register (e.g. for eviction). */ - r12 "12" bytes4! int! volatile; - r11 "11" bytes4! int! volatile; - r10 "10" bytes4! int! volatile; - r9 "9" bytes4! int! volatile; - r8 "8" bytes4! int! volatile; - r7 "7" bytes4! int! volatile; - r6 "6" bytes4! int! volatile; - r5 "5" bytes4! int! volatile; - r4 "4" bytes4! int! volatile; - r3 "3" bytes4! int! ret volatile; + r12 "r12" bytes4! int! volatile; + r11 "r11" bytes4! int! volatile; + r10 "r10" bytes4! int! volatile; + r9 "r9" bytes4! int! volatile; + r8 "r8" bytes4! int! volatile; + r7 "r7" bytes4! int! volatile; + r6 "r6" bytes4! int! volatile; + r5 "r5" bytes4! int! volatile; + r4 "r4" bytes4! int! volatile; + r3 "r3" bytes4! int! ret volatile; - r31 "31" bytes4! int!; - r30 "30" bytes4! int!; - r29 "29" bytes4! int!; - r28 "28" bytes4! int!; - r27 "27" bytes4! int!; - r26 "26" bytes4! int!; - r25 "25" bytes4! int!; - r24 "24" bytes4! int!; - r23 "23" bytes4! int!; - r22 "22" bytes4! int!; - r21 "21" bytes4! int!; - r20 "20" bytes4! int!; - r19 "19" bytes4! int!; - r18 "18" bytes4! int!; - r17 "17" bytes4! int!; - r16 "16" bytes4! int!; - r15 "15" bytes4! int!; - r14 "14" bytes4! int!; + r31 "r31" bytes4! int!; + r30 "r30" bytes4! int!; + r29 "r29" bytes4! int!; + r28 "r28" bytes4! int!; + r27 "r27" bytes4! int!; + r26 "r26" bytes4! int!; + r25 "r25" bytes4! int!; + r24 "r24" bytes4! int!; + r23 "r23" bytes4! int!; + r22 "r22" bytes4! int!; + r21 "r21" bytes4! int!; + r20 "r20" bytes4! int!; + r19 "r19" bytes4! int!; + r18 "r18" bytes4! int!; + r17 "r17" bytes4! int!; + r16 "r16" bytes4! int!; + r15 "r15" bytes4! int!; + r14 "r14" bytes4! int!; - f14 "14" bytes4! float! volatile; - f13 "13" bytes4! float! volatile; - f12 "12" bytes4! float! volatile; - f11 "11" bytes4! float! volatile; - f10 "10" bytes4! float! volatile; - f9 "9" bytes4! float! volatile; - f8 "8" bytes4! float! volatile; - f7 "7" bytes4! float! volatile; - f6 "6" bytes4! float! volatile; - f5 "5" bytes4! float! volatile; - f4 "4" bytes4! float! volatile; - f3 "3" bytes4! float! volatile; - f2 "2" bytes4! float! volatile; - f1 "1" bytes4! float! volatile; - f0 "0" bytes4! float! volatile; + f14 "f14" bytes4! float! volatile; + f13 "f13" bytes4! float! volatile; + f12 "f12" bytes4! float! volatile; + f11 "f11" bytes4! float! volatile; + f10 "f10" bytes4! float! volatile; + f9 "f9" bytes4! float! volatile; + f8 "f8" bytes4! float! volatile; + f7 "f7" bytes4! float! volatile; + f6 "f6" bytes4! float! volatile; + f5 "f5" bytes4! float! volatile; + f4 "f4" bytes4! float! volatile; + f3 "f3" bytes4! float! volatile; + f2 "f2" bytes4! float! volatile; + f1 "f1" bytes4! float! volatile; + f0 "f0" bytes4! float! volatile; - f31 "31" bytes4! float!; - f30 "30" bytes4! float!; - f29 "29" bytes4! float!; - f28 "28" bytes4! float!; - f27 "27" bytes4! float!; - f26 "26" bytes4! float!; - f25 "25" bytes4! float!; - f24 "24" bytes4! float!; - f23 "23" bytes4! float!; - f22 "22" bytes4! float!; - f21 "21" bytes4! float!; - f20 "20" bytes4! float!; - f19 "19" bytes4! float!; - f18 "18" bytes4! float!; - f17 "17" bytes4! float!; - f16 "16" bytes4! float!; - f15 "15" bytes4! float!; + f31 "f31" bytes4! float!; + f30 "f30" bytes4! float!; + f29 "f29" bytes4! float!; + f28 "f28" bytes4! float!; + f27 "f27" bytes4! float!; + f26 "f26" bytes4! float!; + f25 "f25" bytes4! float!; + f24 "f24" bytes4! float!; + f23 "f23" bytes4! float!; + f22 "f22" bytes4! float!; + f21 "f21" bytes4! float!; + f20 "f20" bytes4! float!; + f19 "f19" bytes4! float!; + f18 "f18" bytes4! float!; + f17 "f17" bytes4! float!; + f16 "f16" bytes4! float!; + f15 "f15" bytes4! float!; cr0 "cr0" cr!; @@ -109,10 +109,6 @@ PATTERNS emit "addi sp, sp, 4" cost 8; - RET - emit "ret" - cost 4; - SETRET4(in:(ret)reg) emit "! setret4" cost 4; @@ -402,6 +398,11 @@ PATTERNS emit "addi %out, %left, $right" cost 4; + out:(int)reg = ADD4(left:CONST4, right:(int)reg) + when signed_constant(%left, 16) + emit "addi %out, %right, $left" + cost 4; + out:(int)reg = SUB4(left:(int)reg, right:(int)reg) emit "subf %out, %left, %right" cost 4; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 7f0abd19d..80433ec7d 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1,5 +1,6 @@ #include "mcg.h" +static struct procedure* current_proc; static struct basicblock* current_bb; static int stackptr; @@ -712,9 +713,25 @@ static void insn_ivalue(int opcode, arith value) ); } + if (!current_proc->exit) + { + current_proc->exit = bb_get(NULL); + array_append(¤t_proc->blocks, current_proc->exit); + + /* This is actually ignored --- the entire block gets special + * treatment. But a lot of the rest of the code assumes that + * all basic blocks have one instruction, so we insert one. */ + array_append(¤t_proc->exit->irs, + new_ir0( + IR_RET, 0 + ) + ); + } + appendir( - new_ir0( - IR_RET, 0 + new_ir1( + IR_JUMP, 0, + new_bbir(current_proc->exit) ) ); break; @@ -971,10 +988,11 @@ static void generate_tree(struct basicblock* bb) assert(stackptr == 0); } -void tb_procedure(struct procedure* current_proc) +void tb_procedure(struct procedure* proc) { int i; + current_proc = proc; for (i=0; iblocks.count; i++) generate_tree(current_proc->blocks.item[i]); diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index aa575667a..8606755c7 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -70,13 +70,14 @@ definerule("mcgg", cwd = e.cwd, outleaves = { "tables.c", + "tables.h", }, ins = { "util/mcgg+mcgg", e.srcs[1] }, commands = { - "%{ins[1]} -i %{ins[2]} -o %{outs}", + "%{ins[1]} -i %{ins[2]} -o %{outs[1]} -h %{outs[2]}", } } end diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 9155271fc..067ad3d8d 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -180,8 +180,6 @@ predicate_arg #include int errcnt = 0; -FILE *infp = NULL; -FILE *outfp = NULL; static char buf[BUFSIZ], *bp = buf; static int ppercent = 0; diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 390853201..39cdf9729 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -20,6 +20,10 @@ static char rcsid[] = "$Id$"; int maxcost = SHRT_MAX / 2; +FILE* infp = NULL; +FILE* outfp = NULL; +FILE* hdrfp = NULL; + static char* prefix = "burm"; static int Tflag = 1; /* tracing */ static int ntnumber = 0; @@ -32,8 +36,8 @@ static int nrules; static SMAPOF(struct reg) registers; static SMAPOF(struct regattr) registerattrs; -static void print(char* fmt, ...); -static void ckreach(Nonterm p); +static void print(const char* fmt, ...); +static void printh(const char* fmt, ...); static void registerterminals(void); static struct regattr* makeregattr(const char* id); static void emitclosure(Nonterm nts); @@ -72,11 +76,12 @@ int main(int argc, char* argv[]) infp = stdin; outfp = stdout; + hdrfp = NULL; yy_flex_debug = 0; for (;;) { - int opt = getopt(argc, argv, "p:i:o:yf"); + int opt = getopt(argc, argv, "p:i:o:h:yf"); if (opt == -1) break; @@ -104,6 +109,15 @@ int main(int argc, char* argv[]) } break; + case 'h': + hdrfp = fopen(optarg, "w"); + if (!hdrfp) + { + yyerror("cannot open output header file: %s\n", strerror(errno)); + exit(1); + } + break; + case 'y': { extern int yydebug; @@ -138,25 +152,19 @@ int main(int argc, char* argv[]) const static struct terminfo reg = { "reg", NULL, "" }; const static struct terminfo REG = { "REG", NULL, NULL }; const static struct terminfo NOP = { "NOP", NULL, NULL }; + const static struct terminfo RET = { "RET", NULL, NULL }; nonterm("reg", true); rule(NULL, tree(®, NULL, NULL))->cost = 1; rule(®, tree(®, NULL, NULL))->cost = 1; rule(®, tree(&NOP, tree(®, NULL, NULL), NULL))->cost = 1; + rule(NULL, tree(&RET, NULL, NULL))->cost = 1; } yyin = infp; yyparse(); - if (start) - ckreach(start); - #if 0 - for (p = nts; p; p = p->link) - if (!p->reached) - yyerror("can't reach non-terminal `%s'\n", p->name); - #endif - emitregisterattrs(); emitregisters(); emitdefs(nts, ntnumber); @@ -177,6 +185,13 @@ int main(int argc, char* argv[]) emitfuncs(); print("#endif\n"); print("#include \"mcgg_generated_footer.h\"\n"); + printh("#endif\n"); + + if (outfp) + fclose(outfp); + if (hdrfp) + fclose(hdrfp); + return errcnt > 0; } @@ -470,29 +485,30 @@ Rule rule(const struct terminfo* ti, Tree pattern) } /* print - formatted output */ -static void print(char* fmt, ...) -{ - va_list ap; - va_start(ap, fmt); +static void printto(FILE* fp, const char* fmt, va_list ap) +{ + if (!fp) + return; + for (; *fmt; fmt++) if (*fmt == '%') switch (*++fmt) { case 'd': - fprintf(outfp, "%d", va_arg(ap, int)); + fprintf(fp, "%d", va_arg(ap, int)); break; case 'x': - fprintf(outfp, "%x", va_arg(ap, uint32_t)); + fprintf(fp, "%x", va_arg(ap, uint32_t)); break; case 's': - fputs(va_arg(ap, char*), outfp); + fputs(va_arg(ap, char*), fp); break; case 'P': - fprintf(outfp, "%s_", prefix); + fprintf(fp, "%s_", prefix); break; case 'T': @@ -514,7 +530,7 @@ static void print(char* fmt, ...) } case 'S': - fputs(va_arg(ap, Term)->name, outfp); + fputs(va_arg(ap, Term)->name, fp); break; case '1': @@ -525,46 +541,32 @@ static void print(char* fmt, ...) { int n = *fmt - '0'; while (n-- > 0) - putc('\t', outfp); + putc('\t', fp); break; } default: - putc(*fmt, outfp); + putc(*fmt, fp); break; } else - putc(*fmt, outfp); + putc(*fmt, fp); +} + +static void print(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + printto(outfp, fmt, ap); va_end(ap); } -void printlineno(void) +static void printh(const char* fmt, ...) { - //print("#line %d\n", yylineno); -} - -/* reach - mark all non-terminals in tree t as reachable */ -static void reach(Tree t) -{ - Nonterm p = t->op; - - if (p->kind == NONTERM) - if (!p->reached) - ckreach(p); - if (t->left) - reach(t->left); - if (t->right) - reach(t->right); -} - -/* ckreach - mark all non-terminals reachable from p */ -static void ckreach(Nonterm p) -{ - Rule r; - - p->reached = 1; - for (r = p->rules; r; r = r->decode) - reach(r->pattern); + va_list ap; + va_start(ap, fmt); + printto(hdrfp, fmt, ap); + va_end(ap); } static void emitregisterattrs(void) @@ -578,8 +580,10 @@ static void emitregisterattrs(void) assert(rc->number == i); print("%1\"%s\",\n", rc->name); + printh("#define %P%s_ATTR (1U<<%d)\n", rc->name, rc->number); } print("};\n\n"); + printh("\n"); } static void emitregisters(void) @@ -713,9 +717,12 @@ static void emitdefs(Nonterm nts, int ntnumber) { Nonterm p; + printh("enum {\n"); for (p = nts; p; p = p->link) - print("#define %P%S_NT %d\n", p, p->number); - print("#define %Pmax_nt %d\n\n", ntnumber); + printh("%1%P%S_NT = %d,\n", p, p->number); + printh("%1%Pmax_nt = %d\n", ntnumber); + printh("};\n\n"); + print("const char *%Pntname[] = {\n%10,\n"); for (p = nts; p; p = p->link) print("%1\"%S\",\n", p); @@ -744,6 +751,9 @@ static void emitheader(void) print("#include \"mcgg_generated_header.h\"\n"); if (Tflag) print("static NODEPTR_TYPE %Pnp;\n\n"); + + printh("#ifndef MCG_DEFS_H\n"); + printh("#define MCG_DEFS_H\n\n"); } /* computekids - compute paths to kids in tree t */ @@ -1343,11 +1353,6 @@ static void emitterms(Term terms) Term p; int k; - print("enum {\n"); - for (k = 0, p = terms; p; p = p->link) - print("%1%S = %d,\n", p, p->esn); - print("};\n\n"); - print("static const char %Parity[] = {\n"); for (k = 0, p = terms; p; p = p->link) { diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 48397c21e..d12985eb6 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -143,6 +143,7 @@ void yywarn(char* fmt, ...); extern int errcnt; extern FILE* infp; extern FILE* outfp; +extern FILE* hdrfp; /* Stupid flex imports --- why mo header file? */ From 0eb32e7553b0e2e161a4f9802e3a1d98681bf235 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 19:14:25 +0200 Subject: [PATCH 114/230] Fix yet another bug to do with IR register outputs. --- mach/proto/mcg/pass_instructionselection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 752648de5..52adc7b34 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -205,7 +205,7 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) hop_print('I', current_hop); array_append(¤t_bb->hops, current_hop); - if (goal != burm_stmt_NT) + if ((goal != burm_stmt_NT) && !insn->ir->result) insn->ir->result = insn->hop->output; } } From 7aa60a645136f18174ce4b8b2a87404c6d676aea Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 22:53:56 +0200 Subject: [PATCH 115/230] Register spilling to the stack frame works, more or less. --- mach/proto/mcg/hop.c | 45 +++++++ mach/proto/mcg/hop.h | 7 + mach/proto/mcg/mcg.h | 3 +- mach/proto/mcg/parse_em.c | 2 +- mach/proto/mcg/pass_instructionselection.c | 21 +++ mach/proto/mcg/pass_phigroups.c | 5 +- mach/proto/mcg/pass_registerallocator.c | 142 ++++++++++++++++----- mach/proto/mcg/powerpc.c | 41 ++++-- mach/proto/mcg/procedure.c | 7 +- mach/proto/mcg/procedure.h | 7 +- mach/proto/mcg/reg.c | 7 +- mach/proto/mcg/reg.h | 5 +- mach/proto/mcg/treebuilder.c | 1 + 13 files changed, 242 insertions(+), 51 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 3797d7b24..b5eaa0292 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -52,6 +52,27 @@ void hop_add_value_insel(struct hop* hop, struct ir* ir) array_append(&hop->insels, insel); } +void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg) +{ + struct insel* insel = new_insel(INSEL_ST_OFFSET); + insel->u.hreg = hreg; + array_append(&hop->insels, insel); +} + +void hop_add_ab_offset_insel(struct hop* hop, int offset) +{ + struct insel* insel = new_insel(INSEL_AB_OFFSET); + insel->u.offset = offset; + array_append(&hop->insels, insel); +} + +void hop_add_lb_offset_insel(struct hop* hop, int offset) +{ + struct insel* insel = new_insel(INSEL_LB_OFFSET); + insel->u.offset = offset; + array_append(&hop->insels, insel); +} + void hop_add_eoi_insel(struct hop* hop) { struct insel* insel = new_insel(INSEL_EOI); @@ -74,6 +95,18 @@ void hop_add_insel(struct hop* hop, const char* fmt, ...) hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int))); break; + case 'S': + hop_add_st_offset_insel(hop, va_arg(ap, struct hreg*)); + break; + + case 'A': + hop_add_ab_offset_insel(hop, va_arg(ap, int)); + break; + + case 'L': + hop_add_lb_offset_insel(hop, va_arg(ap, int)); + break; + case 'H': hop_add_hreg_insel(hop, va_arg(ap, struct hreg*)); break; @@ -193,6 +226,18 @@ char* hop_render(struct hop* hop) appendf("%s", insel->u.string); break; + case INSEL_ST_OFFSET: + appendf("(st+%d)", insel->u.hreg->offset); + break; + + case INSEL_AB_OFFSET: + appendf("(ab+%d)", insel->u.offset); + break; + + case INSEL_LB_OFFSET: + appendf("(lb+%d)", insel->u.offset); + break; + case INSEL_VALUE: { struct ir* ir = insel->u.value; diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index dcc6fe03b..e1f2f6d92 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -7,6 +7,9 @@ enum insel_type INSEL_HREG, INSEL_VREG, INSEL_VALUE, + INSEL_ST_OFFSET, + INSEL_AB_OFFSET, + INSEL_LB_OFFSET, INSEL_EOI }; @@ -19,6 +22,7 @@ struct insel struct hreg* hreg; struct vreg* vreg; struct ir* value; + int offset; } u; }; @@ -53,6 +57,9 @@ extern void hop_add_string_insel(struct hop* hop, const char* string); extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg); extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); extern void hop_add_value_insel(struct hop* hop, struct ir* ir); +extern void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg); +extern void hop_add_ab_offset_insel(struct hop* hop, int offset); +extern void hop_add_lb_offset_insel(struct hop* hop, int offset); extern void hop_add_eoi_insel(struct hop* hop); extern void hop_add_insel(struct hop* hop, const char* fmt, ...); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 5cd875ef4..005324d0d 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -112,7 +112,7 @@ extern void pass_instruction_selector(void); extern void pass_live_vreg_analysis(void); extern void pass_add_prologue_epilogue(struct procedure* proc); extern void pass_promote_float_ops(struct procedure* proc); -extern void pass_register_allocator(void); +extern void pass_register_allocator(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_remove_dead_phis(void); extern void pass_split_critical_edges(struct procedure* proc); @@ -120,6 +120,7 @@ extern void pass_split_critical_edges(struct procedure* proc); extern struct hop* platform_prologue(struct procedure* proc); extern struct hop* platform_epilogue(struct procedure* proc); extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest); +extern void platform_calculate_offsets(struct procedure* proc); extern FILE* outputfile; extern FILE* dominance_dot_file; diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 2b88eac81..eaa712a4f 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -308,7 +308,7 @@ static void parse_pseu(void) current_proc = calloc(sizeof(struct procedure), 1); current_proc->name = strdup(em.em_pnam); current_proc->entry = bb_get(current_proc->name); - current_proc->nlocals = em.em_nlocals; + current_proc->locals_size = em.em_nlocals; code_bb = current_proc->entry; code_bb->is_root = true; array_append(¤t_proc->blocks, code_bb); diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 52adc7b34..82d7f9875 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -100,6 +100,26 @@ static void constrain_input_reg(int child, uint32_t attr) get_constraint(vreg)->attrs = attr; } +static uint32_t find_type_from_constraint(uint32_t attr) +{ + /* Looks through the registers and finds a concrete register implementing + * that attribute, and returns the type. We assume that all registers + * implementing an attribute (which anyone is going to ask for, 'volatile' + * doesn't count) will have the same type. TODO: mcgg should check for + * this. */ + + const struct burm_register_data* brd = burm_register_data; + while (brd->name) + { + if (brd->attrs & attr) + return brd->type; + brd++; + } + + fatal("unable to find a register matching attribute 0x%x", attr); + return 0; +} + static void constrain_output_reg(uint32_t attr) { struct vreg* vreg = current_hop->output; @@ -109,6 +129,7 @@ static void constrain_output_reg(uint32_t attr) array_appendu(¤t_hop->outs, vreg); vreg->defined = current_hop; + vreg->type = find_type_from_constraint(attr); get_constraint(vreg)->attrs = attr; } diff --git a/mach/proto/mcg/pass_phigroups.c b/mach/proto/mcg/pass_phigroups.c index c773aa5ad..41fa6e093 100644 --- a/mach/proto/mcg/pass_phigroups.c +++ b/mach/proto/mcg/pass_phigroups.c @@ -34,8 +34,9 @@ static void recursively_associate_group(struct phicongruence* c, struct vreg* vr if (vreg->defined) { struct constraint* constraint = pmap_findleft(&vreg->defined->constraints, vreg); - if ((c->attrs == 0) || (constraint->attrs < c->attrs)) - c->attrs = constraint->attrs; + if (c->type == 0) + c->type = vreg->type; + assert(c->type == vreg->type); array_appendu(&c->definitions, vreg->defined); } diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index f967e3136..6dadc2c76 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -6,6 +6,8 @@ struct assignment struct vreg* out; }; +static struct procedure* current_proc; + static ARRAYOF(struct hreg) hregs; static PMAPOF(struct vreg, struct hreg) evicted; @@ -42,7 +44,7 @@ static void wire_up_blocks_ins_outs(void) } static struct hreg* allocate_phi_hreg(register_assignment_t* regs, - struct vreg* vreg, uint32_t attrs) + struct vreg* vreg, uint32_t type) { int i; @@ -52,7 +54,7 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs, for (i=0; iattrs & attrs)) + if (!pmap_findleft(regs, hreg) && (hreg->type == type)) { /* This one is unused. Use it. */ return hreg; @@ -99,19 +101,39 @@ static struct hreg* evict(struct vreg* vreg) assert(false); } -static bool allocatable_input(struct hreg* hreg, struct vreg* vreg) +static bool type_match(struct hreg* hreg, struct vreg* vreg) { struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + if (c) + return (hreg->attrs & c->attrs); + if (vreg->congruence) + return (hreg->type == vreg->congruence->type); + return (hreg->type == vreg->type); +} + +static bool allocatable_stackable_input(struct hreg* hreg, struct vreg* vreg) +{ return !pmap_findleft(current_ins, hreg) && - (!c || (hreg->attrs & c->attrs)); + type_match(hreg, vreg); +} + +static bool allocatable_stackable_output(struct hreg* hreg, struct vreg* vreg) +{ + return !pmap_findleft(current_outs, hreg) && + type_match(hreg, vreg) && + !(hreg->attrs & current_hop->insndata->corrupts); +} + +static bool allocatable_input(struct hreg* hreg, struct vreg* vreg) +{ + return allocatable_stackable_input(hreg, vreg) && + !hreg->is_stacked; } static bool allocatable_output(struct hreg* hreg, struct vreg* vreg) { - struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); - return !pmap_findleft(current_outs, hreg) && - (!c || (hreg->attrs & c->attrs)) && - !(hreg->attrs & current_hop->insndata->corrupts); + return allocatable_stackable_output(hreg, vreg) && + !hreg->is_stacked; } static struct hreg* find_input_reg(struct vreg* vreg) @@ -174,7 +196,32 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg) if (hreg) { - if (pmap_findleft(current_ins, hreg) == vreg) + if (hreg->is_stacked) + { + /* This vreg is stacked; we need to put it in a register. That's + * slightly exciting because the vreg might be a through, which + * means we need an output register too... which we might not be + * able to allocate. */ + + if (array_contains(¤t_hop->throughs, vreg)) + { + struct hreg* src = hreg; + hreg = find_through_reg(vreg); + assert(hreg); + pmap_remove(current_ins, src, vreg); + pmap_remove(current_outs, src, vreg); + pmap_add(current_ins, hreg, vreg); + pmap_add(current_outs, hreg, vreg); + return; + } + else + { + /* Not a through. */ + pmap_remove(current_ins, hreg, vreg); + hreg = NULL; + } + } + else if (pmap_findleft(current_ins, hreg) == vreg) { /* Yup, already there. */ } @@ -213,7 +260,7 @@ static void add_output_register(struct vreg* vreg) c = pmap_findleft(¤t_hop->constraints, vreg); if (c->equals_to) { - tracef('R', "R: outputput equality constraint of %%%d to %%%d\n", + tracef('R', "R: output equality constraint of %%%d to %%%d\n", vreg->id, c->equals_to->id); /* This output register is constrained to be in the same hreg as an @@ -262,28 +309,31 @@ static void add_through_register(struct vreg* vreg, struct hreg* hreg) if (hreg) { - bool infree = allocatable_input(hreg, vreg); - bool outfree = allocatable_output(hreg, vreg); + bool infree = allocatable_stackable_input(hreg, vreg); + bool outfree = allocatable_stackable_output(hreg, vreg); + struct vreg* inuse = pmap_findleft(current_ins, hreg); + struct vreg* outuse = pmap_findleft(current_outs, hreg); - if (infree && outfree) + if ((infree || (inuse == vreg)) && + (outfree || (outuse == vreg))) { - /* Register unused --- use it. */ - } - if ((infree || pmap_findleft(current_ins, hreg) == vreg) && - (outfree || pmap_findleft(current_outs, hreg) == vreg)) - { - /* Input and output are either free or already assigned. */ + /* Input and output are either free or already assigned to this + * vreg. */ } else { - /* Nope, can't honour the hint. */ - hreg = NULL; + /* Nope, can't honour the hint. Mark the register as evicted; we'll + * put it in something later (probably a stack slot). */ + + tracef('R', "R: cannot place %%%d in %s, evicting\n", vreg->id, hreg->name); + pmap_put(&evicted, vreg, hreg); + pmap_remove(current_ins, hreg, vreg); + pmap_remove(current_outs, hreg, vreg); + return; } } - if (!hreg) - hreg = find_through_reg(vreg); - + assert(hreg); pmap_put(current_ins, hreg, vreg); pmap_put(current_outs, hreg, vreg); } @@ -302,8 +352,8 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s { hreg = hregs.item[i]; if ((hreg->type == src->type) && - allocatable_input(hreg, vreg) && - allocatable_output(hreg, vreg)) + allocatable_stackable_input(hreg, vreg) && + allocatable_stackable_output(hreg, vreg)) { goto found; } @@ -311,7 +361,8 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s /* No more registers --- allocate a stack slot. */ - assert(false); + hreg = new_stacked_hreg(src->type); + array_append(&hregs, hreg); found: tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->name); @@ -442,7 +493,7 @@ static void assign_hregs_to_vregs(void) if (!pmap_findright(old, vreg)) { struct phicongruence* c = vreg->congruence; - struct hreg* hreg = allocate_phi_hreg(old, vreg, c->attrs); + struct hreg* hreg = allocate_phi_hreg(old, vreg, c->type); tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n", hreg->name, vreg->id, phi->prev->name); @@ -551,7 +602,8 @@ static int insert_moves(struct basicblock* bb, int index, else { /* Swap. */ - + + assert(false); src = copies.item[0].left; dest = pmap_findleft(&copies, src); hop = create_swap(bb, src, dest); @@ -626,13 +678,43 @@ static void insert_phi_copies(void) } } -void pass_register_allocator(void) +static int pack_stackframe(int stacksize, int size, uint32_t attr) { + int i; + + for (i=0; iis_stacked && (hreg->type & attr)) + { + hreg->offset = stacksize; + stacksize += size; + } + } + + return stacksize; +} + +static void layout_stack_frame(void) +{ + int stacksize = 0; + stacksize = pack_stackframe(stacksize, 8, burm_bytes8_ATTR); + stacksize = pack_stackframe(stacksize, 4, burm_bytes4_ATTR); + stacksize = pack_stackframe(stacksize, 2, burm_bytes2_ATTR); + stacksize = pack_stackframe(stacksize, 1, burm_bytes1_ATTR); + current_proc->spills_size = stacksize; +} + +void pass_register_allocator(struct procedure* proc) +{ + current_proc = proc; + populate_hregs(); wire_up_blocks_ins_outs(); assign_hregs_to_vregs(); insert_phi_copies(); + layout_stack_frame(); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/powerpc.c b/mach/proto/mcg/powerpc.c index b5c606110..8cd2e269f 100644 --- a/mach/proto/mcg/powerpc.c +++ b/mach/proto/mcg/powerpc.c @@ -1,17 +1,35 @@ #include "mcg.h" +/* mcg stack frames are laid out as: + * + * | ...params... + * | --------------- <- ap + * | saved regs + * | --------------- <- st + * | spills + * | --------------- <- fp (a.k.a. lb) + * | locals + * | --------------- <- sp + * V ...user area... + * + */ + +void platform_calculate_offsets(struct procedure* proc) +{ + proc->fp_to_st = proc->spills_size; + proc->fp_to_ap = proc->fp_to_st + proc->saved_size + 8; + proc->fp_to_lb = 0; +} + struct hop* platform_prologue(struct procedure* proc) { - int framesize = proc->nlocals + 8; - int retbase = proc->nlocals; - struct hop* hop = new_hop(proc->entry, NULL); - hop_add_insel(hop, "addi sp, fp, %d", -framesize); + hop_add_insel(hop, "addi sp, sp, %d", proc->fp_to_ap + proc->locals_size); hop_add_insel(hop, "mfspr 0, lr"); - hop_add_insel(hop, "stw fp, %d(sp)", retbase); - hop_add_insel(hop, "stw 0, %d(sp)", retbase+4); - hop_add_insel(hop, "addi fp, sp, retbase"); + hop_add_insel(hop, "stw fp, %d(sp)", proc->fp_to_st + proc->locals_size); + hop_add_insel(hop, "stw 0, %d(sp)", proc->fp_to_st + proc->locals_size + 4); + hop_add_insel(hop, "addi fp, sp, %d", proc->locals_size); return hop; } @@ -30,7 +48,14 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* struct hop* hop = new_hop(bb, NULL); if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR)) - hop_add_insel(hop, "mr %H, %H", dest, src); + { + if (src->is_stacked) + hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src); + else if (dest->is_stacked) + hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest); + else + hop_add_insel(hop, "mr %H, %H", dest, src); + } else fatal("cannot generate move from %s to %s", src->name, dest->name); diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index d6382b06d..00c1a457b 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -1,5 +1,7 @@ #include "mcg.h" +extern struct procedure* current_proc; + static void print_blocks(char k, struct procedure* proc) { int i; @@ -157,8 +159,6 @@ static void write_dominance_graph(const char* name) void procedure_compile(struct procedure* proc) { - int i; - pass_group_irs(proc); print_blocks('1', proc); @@ -189,10 +189,11 @@ void procedure_compile(struct procedure* proc) pass_find_phi_congruence_groups(); pass_live_vreg_analysis(); print_hops('8', proc); - pass_register_allocator(); + pass_register_allocator(proc); pass_add_prologue_epilogue(proc); print_hops('9', proc); + platform_calculate_offsets(proc); emit_procedure(proc); if (cfg_dot_file) diff --git a/mach/proto/mcg/procedure.h b/mach/proto/mcg/procedure.h index 9d653b3f4..f0c6b3be3 100644 --- a/mach/proto/mcg/procedure.h +++ b/mach/proto/mcg/procedure.h @@ -13,7 +13,12 @@ struct procedure const char* name; struct basicblock* entry; struct basicblock* exit; - size_t nlocals; + int locals_size; + int spills_size; + int saved_size; + int fp_to_st; + int fp_to_ap; + int fp_to_lb; ARRAYOF(struct basicblock) blocks; IMAPOF(struct local) locals; }; diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c index 2cb523764..25ec0b607 100644 --- a/mach/proto/mcg/reg.c +++ b/mach/proto/mcg/reg.c @@ -20,15 +20,16 @@ struct hreg* new_hreg(const struct burm_register_data* brd) return hreg; } -struct hreg* new_stacked_hreg(int offset, uint32_t type) +struct hreg* new_stacked_hreg(uint32_t type) { + static int hreg_count = 1; struct hreg* hreg = calloc(1, sizeof *hreg); - hreg->name = aprintf("stacked_%d", offset); + hreg->name = aprintf("stacked_%d_id_%d", type, hreg_count++); hreg->realname = hreg->name; hreg->type = type; hreg->attrs = type; hreg->is_stacked = true; - hreg->offset = offset; + hreg->offset = -1; return hreg; } diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index 0f47dfd03..e71864f3a 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -8,7 +8,7 @@ struct phicongruence int id; ARRAYOF(struct vreg) vregs; ARRAYOF(struct hop) definitions; - uint32_t attrs; + uint32_t type; }; struct hreg @@ -24,6 +24,7 @@ struct hreg struct vreg { int id; + uint32_t type; struct phicongruence* congruence; struct hop* defined; ARRAYOF(struct hop) used; @@ -34,7 +35,7 @@ typedef PMAPOF(struct hreg, struct vreg) register_assignment_t; extern struct vreg* new_vreg(void); extern struct hreg* new_hreg(const struct burm_register_data* brd); -extern struct hreg* new_stacked_hreg(int offset, uint32_t type); +extern struct hreg* new_stacked_hreg(uint32_t type); #endif diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 80433ec7d..f4a81752e 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -721,6 +721,7 @@ static void insn_ivalue(int opcode, arith value) /* This is actually ignored --- the entire block gets special * treatment. But a lot of the rest of the code assumes that * all basic blocks have one instruction, so we insert one. */ + array_append(¤t_proc->exit->irs, new_ir0( IR_RET, 0 From a8ee82d197171c7c4e045bb693b9ef078e5ea80e Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 23:19:44 +0200 Subject: [PATCH 116/230] Stop passing proc around, and use a global instead --- much cleaner. --- mach/proto/mcg/graph.c | 24 ++++----- mach/proto/mcg/graph.h | 2 +- mach/proto/mcg/mcg.h | 26 ++++----- mach/proto/mcg/parse_em.c | 3 +- mach/proto/mcg/pass_convertstackops.c | 8 +-- mach/proto/mcg/pass_eliminatetrivialblocks.c | 6 +-- mach/proto/mcg/pass_groupirs.c | 10 ++-- mach/proto/mcg/pass_prologueepilogue.c | 16 +++--- mach/proto/mcg/pass_promotefloatops.c | 10 ++-- mach/proto/mcg/pass_registerallocator.c | 6 +-- mach/proto/mcg/pass_removedeadblocks.c | 8 +-- mach/proto/mcg/pass_splitcriticaledges.c | 10 ++-- mach/proto/mcg/pass_ssa.c | 6 +-- mach/proto/mcg/powerpc.c | 24 ++++----- mach/proto/mcg/procedure.c | 57 ++++++++++---------- mach/proto/mcg/procedure.h | 2 + mach/proto/mcg/table | 2 + mach/proto/mcg/treebuilder.c | 4 +- 18 files changed, 108 insertions(+), 116 deletions(-) diff --git a/mach/proto/mcg/graph.c b/mach/proto/mcg/graph.c index 395b7bfca..4be0a548b 100644 --- a/mach/proto/mcg/graph.c +++ b/mach/proto/mcg/graph.c @@ -18,26 +18,26 @@ static bool collect_outputs_cb(struct ir* ir, void* user) return false; } -static void update_block_pointers_from_ir(struct procedure* proc) +static void update_block_pointers_from_ir(void) { int i, j; - for (i=0; iblocks.count; i++) + for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks.item[i]; + struct basicblock* bb = current_proc->blocks.item[i]; bb->prevs.count = bb->nexts.count = 0; } - for (i=0; iblocks.count; i++) + for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks.item[i]; + struct basicblock* bb = current_proc->blocks.item[i]; for (j=0; jirs.count; j++) ir_walk(bb->irs.item[j], collect_outputs_cb, bb); } - for (i=0; iblocks.count; i++) + for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks.item[i]; + struct basicblock* bb = current_proc->blocks.item[i]; for (j=0; jnexts.count; j++) { @@ -189,15 +189,15 @@ static void walk_dominance_graph(void) } } -void update_graph_data(struct procedure* proc) +void update_graph_data(void) { - cfg.entry = proc->blocks.item[0]; + cfg.entry = current_proc->blocks.item[0]; cfg.graph.count = 0; - update_block_pointers_from_ir(proc); + update_block_pointers_from_ir(); walk_cfg_graph(); - assert(cfg.postorder.count == proc->blocks.count); - assert(cfg.preorder.count == proc->blocks.count); + assert(cfg.postorder.count == current_proc->blocks.count); + assert(cfg.preorder.count == current_proc->blocks.count); calculate_dominance_graph(); diff --git a/mach/proto/mcg/graph.h b/mach/proto/mcg/graph.h index 93991b82f..ed8e8ba21 100644 --- a/mach/proto/mcg/graph.h +++ b/mach/proto/mcg/graph.h @@ -19,7 +19,7 @@ struct dominance_data extern struct graph_data cfg; extern struct dominance_data dominance; -extern void update_graph_data(struct procedure* proc); +extern void update_graph_data(void); #endif diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 005324d0d..78c7f0456 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -99,28 +99,28 @@ extern void data_bss(arith size, int init); extern void tb_filestart(void); extern void tb_fileend(void); -extern void tb_procedure(struct procedure* proc); +extern void tb_procedure(void); extern void tb_regvar(struct procedure* proc, arith offset, int size, int type, int priority); -extern void pass_convert_locals_to_ssa(struct procedure* proc); -extern void pass_convert_stack_ops(struct procedure* proc); -extern void pass_eliminate_trivial_blocks(struct procedure* proc); +extern void pass_convert_locals_to_ssa(void); +extern void pass_convert_stack_ops(void); +extern void pass_eliminate_trivial_blocks(void); extern void pass_find_phi_congruence_groups(void); -extern void pass_group_irs(struct procedure* proc); +extern void pass_group_irs(void); extern void pass_insert_moves(void); extern void pass_instruction_selector(void); extern void pass_live_vreg_analysis(void); -extern void pass_add_prologue_epilogue(struct procedure* proc); -extern void pass_promote_float_ops(struct procedure* proc); -extern void pass_register_allocator(struct procedure* proc); -extern void pass_remove_dead_blocks(struct procedure* proc); +extern void pass_add_prologue_epilogue(void); +extern void pass_promote_float_ops(void); +extern void pass_register_allocator(void); +extern void pass_remove_dead_blocks(void); extern void pass_remove_dead_phis(void); -extern void pass_split_critical_edges(struct procedure* proc); +extern void pass_split_critical_edges(void); -extern struct hop* platform_prologue(struct procedure* proc); -extern struct hop* platform_epilogue(struct procedure* proc); +extern void platform_calculate_offsets(void); +extern struct hop* platform_prologue(void); +extern struct hop* platform_epilogue(void); extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest); -extern void platform_calculate_offsets(struct procedure* proc); extern FILE* outputfile; extern FILE* dominance_dot_file; diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index eaa712a4f..c49922ac8 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -1,7 +1,6 @@ #include "mcg.h" static struct e_instr em; -static struct procedure* current_proc; static struct basicblock* code_bb; static struct basicblock* data_bb; @@ -321,7 +320,7 @@ static void parse_pseu(void) } case ps_end: /* procedure end */ - tb_procedure(current_proc); + tb_procedure(); current_proc = NULL; code_bb = NULL; diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index 64bca0762..692a11a62 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -40,7 +40,7 @@ static struct ir* get_first_pop(struct basicblock* bb) return NULL; } -static void convert_block(struct procedure* proc, struct basicblock* bb) +static void convert_block(struct basicblock* bb) { int i, j; struct ir* ir; @@ -108,12 +108,12 @@ static void convert_block(struct procedure* proc, struct basicblock* bb) } } -void pass_convert_stack_ops(struct procedure* proc) +void pass_convert_stack_ops(void) { int i; - for (i=0; iblocks.count; i++) - convert_block(proc, proc->blocks.item[i]); + for (i=0; iblocks.count; i++) + for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks.item[i]; + struct basicblock* bb = current_proc->blocks.item[i]; rewrite_jumps(bb); } } diff --git a/mach/proto/mcg/pass_groupirs.c b/mach/proto/mcg/pass_groupirs.c index ac86ff230..57b850a9b 100644 --- a/mach/proto/mcg/pass_groupirs.c +++ b/mach/proto/mcg/pass_groupirs.c @@ -14,14 +14,14 @@ static void addall(struct ir* ir) addall(ir->right); } -static void collect_irs(struct procedure* proc) +static void collect_irs(void) { int i; allirs.count = rootirs.count = 0; - for (i=0; iblocks.count; i++) + for (i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks.item[i]; + struct basicblock* bb = current_proc->blocks.item[i]; int j; for (j=0; jirs.count; j++) @@ -82,9 +82,9 @@ static void find_non_roots(void) } } -void pass_group_irs(struct procedure* proc) +void pass_group_irs(void) { - collect_irs(proc); + collect_irs(); clear_roots(); find_roots(); find_non_roots(); diff --git a/mach/proto/mcg/pass_prologueepilogue.c b/mach/proto/mcg/pass_prologueepilogue.c index 056630707..53cc498ec 100644 --- a/mach/proto/mcg/pass_prologueepilogue.c +++ b/mach/proto/mcg/pass_prologueepilogue.c @@ -1,19 +1,17 @@ #include "mcg.h" -void pass_add_prologue_epilogue(struct procedure* proc) +void pass_add_prologue_epilogue(void) { - struct hop* prologue = platform_prologue(proc); - array_insert(&proc->entry->hops, prologue, 0); + platform_calculate_offsets(); - if (proc->exit) + array_insert(¤t_proc->entry->hops, platform_prologue(), 0); + + if (current_proc->exit) { - struct hop* epilogue = platform_epilogue(proc); - - proc->exit->hops.count = 0; - array_append(&proc->exit->hops, epilogue); + current_proc->exit->hops.count = 0; + array_append(¤t_proc->exit->hops, platform_epilogue()); } } /* vim: set sw=4 ts=4 expandtab : */ - diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c index 1fdff6f4a..33992145c 100644 --- a/mach/proto/mcg/pass_promotefloatops.c +++ b/mach/proto/mcg/pass_promotefloatops.c @@ -14,15 +14,15 @@ static void addall(struct ir* ir) addall(ir->right); } -static void collect_irs(struct procedure* proc) +static void collect_irs(void) { int i; pending.count = 0; promotable.count = 0; - for (i=0; iblocks.count; i++) + for (i=0; iblocks.item[i]; + struct basicblock* bb = cfg.preorder.item[i]; int j; for (j=0; jirs.count; j++) @@ -87,9 +87,9 @@ static void modify_promotable_irs(void) } } -void pass_promote_float_ops(struct procedure* proc) +void pass_promote_float_ops(void) { - collect_irs(proc); + collect_irs(); search_for_promotable_irs(); modify_promotable_irs(); } diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 6dadc2c76..393395e37 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -6,8 +6,6 @@ struct assignment struct vreg* out; }; -static struct procedure* current_proc; - static ARRAYOF(struct hreg) hregs; static PMAPOF(struct vreg, struct hreg) evicted; @@ -705,10 +703,8 @@ static void layout_stack_frame(void) current_proc->spills_size = stacksize; } -void pass_register_allocator(struct procedure* proc) +void pass_register_allocator(void) { - current_proc = proc; - populate_hregs(); wire_up_blocks_ins_outs(); diff --git a/mach/proto/mcg/pass_removedeadblocks.c b/mach/proto/mcg/pass_removedeadblocks.c index 24cb41889..8a9a07fb4 100644 --- a/mach/proto/mcg/pass_removedeadblocks.c +++ b/mach/proto/mcg/pass_removedeadblocks.c @@ -24,16 +24,16 @@ static void walk_blocks(struct basicblock* bb) } } -void pass_remove_dead_blocks(struct procedure* proc) +void pass_remove_dead_blocks(void) { int i, j; used.count = 0; - walk_blocks(proc->blocks.item[0]); + walk_blocks(current_proc->blocks.item[0]); - proc->blocks.count = 0; + current_proc->blocks.count = 0; for (i=0; iblocks, used.item[i]); + array_append(¤t_proc->blocks, used.item[i]); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_splitcriticaledges.c b/mach/proto/mcg/pass_splitcriticaledges.c index 38628d995..27e832e44 100644 --- a/mach/proto/mcg/pass_splitcriticaledges.c +++ b/mach/proto/mcg/pass_splitcriticaledges.c @@ -12,8 +12,6 @@ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.749 */ -static struct procedure* current_proc; - struct rewrite_params { struct basicblock* find; @@ -85,19 +83,17 @@ static bool consider_edges_leading_from(struct basicblock* bb) return changed; } -void pass_split_critical_edges(struct procedure* proc) +void pass_split_critical_edges(void) { int i; bool changed; - current_proc = proc; - do { changed = false; - for (i=0; iblocks.count; i++) - changed |= consider_edges_leading_from(proc->blocks.item[i]); + for (i=0; iblocks.count; i++) + changed |= consider_edges_leading_from(current_proc->blocks.item[i]); } while (changed); diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 9bf2d777b..99f4928ef 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -213,15 +213,15 @@ static void ssa_convert(void) recursively_rewrite_tree(cfg.entry); } -void pass_convert_locals_to_ssa(struct procedure* proc) +void pass_convert_locals_to_ssa(void) { int i; calculate_dominance_frontier_graph(); - for (i=0; ilocals.count; i++) + for (i=0; ilocals.count; i++) { - current_local = proc->locals.item[i].right; + current_local = current_proc->locals.item[i].right; if (current_local->is_register) ssa_convert(); } diff --git a/mach/proto/mcg/powerpc.c b/mach/proto/mcg/powerpc.c index 8cd2e269f..a47d8a8cc 100644 --- a/mach/proto/mcg/powerpc.c +++ b/mach/proto/mcg/powerpc.c @@ -14,29 +14,29 @@ * */ -void platform_calculate_offsets(struct procedure* proc) +void platform_calculate_offsets(void) { - proc->fp_to_st = proc->spills_size; - proc->fp_to_ap = proc->fp_to_st + proc->saved_size + 8; - proc->fp_to_lb = 0; + current_proc->fp_to_st = current_proc->spills_size; + current_proc->fp_to_ap = current_proc->fp_to_st + current_proc->saved_size + 8; + current_proc->fp_to_lb = 0; } -struct hop* platform_prologue(struct procedure* proc) +struct hop* platform_prologue(void) { - struct hop* hop = new_hop(proc->entry, NULL); + struct hop* hop = new_hop(current_proc->entry, NULL); - hop_add_insel(hop, "addi sp, sp, %d", proc->fp_to_ap + proc->locals_size); + hop_add_insel(hop, "addi sp, sp, %d", current_proc->fp_to_ap + current_proc->locals_size); hop_add_insel(hop, "mfspr 0, lr"); - hop_add_insel(hop, "stw fp, %d(sp)", proc->fp_to_st + proc->locals_size); - hop_add_insel(hop, "stw 0, %d(sp)", proc->fp_to_st + proc->locals_size + 4); - hop_add_insel(hop, "addi fp, sp, %d", proc->locals_size); + hop_add_insel(hop, "stw fp, %d(sp)", current_proc->fp_to_st + current_proc->locals_size); + hop_add_insel(hop, "stw 0, %d(sp)", current_proc->fp_to_st + current_proc->locals_size + 4); + hop_add_insel(hop, "addi fp, sp, %d", current_proc->locals_size); return hop; } -struct hop* platform_epilogue(struct procedure* proc) +struct hop* platform_epilogue(void) { - struct hop* hop = new_hop(proc->exit, NULL); + struct hop* hop = new_hop(current_proc->exit, NULL); hop_add_insel(hop, "b .ret"); diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 00c1a457b..1484c2af9 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -1,15 +1,15 @@ #include "mcg.h" -extern struct procedure* current_proc; +struct procedure* current_proc; -static void print_blocks(char k, struct procedure* proc) +static void print_blocks(char k) { int i; - tracef(k, "%c: procedure %s\n", k, proc->name); - for (int i=0; iblocks.count; i++) + tracef(k, "%c: procedure %s\n", k, current_proc->name); + for (int i=0; iblocks.count; i++) { - struct basicblock* bb = proc->blocks.item[i]; + struct basicblock* bb = current_proc->blocks.item[i]; int j; tracef(k, "%c:\n", k); @@ -38,11 +38,11 @@ static void print_blocks(char k, struct procedure* proc) } } -static void print_hops(char k, struct procedure* proc) +static void print_hops(char k) { int i; - tracef(k, "%c: procedure %s\n", k, proc->name); + tracef(k, "%c: procedure %s\n", k, current_proc->name); for (int i=0; iblocks.count; i++) generate_tree(current_proc->blocks.item[i]); From b36897c299c0513c953a74639db09d7f57a774c5 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 23:33:30 +0200 Subject: [PATCH 117/230] References to the stack frame are now rendered properly. --- mach/proto/mcg/hop.c | 12 +++++++++--- mach/proto/mcg/powerpc.c | 16 ++++++++++------ mach/proto/mcg/procedure.h | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index b5eaa0292..7bdb232ff 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -227,15 +227,15 @@ char* hop_render(struct hop* hop) break; case INSEL_ST_OFFSET: - appendf("(st+%d)", insel->u.hreg->offset); + appendf("%d", current_proc->fp_to_st + insel->u.hreg->offset); break; case INSEL_AB_OFFSET: - appendf("(ab+%d)", insel->u.offset); + appendf("%d", current_proc->fp_to_ab + insel->u.offset); break; case INSEL_LB_OFFSET: - appendf("(lb+%d)", insel->u.offset); + appendf("%d", current_proc->fp_to_lb + insel->u.offset); break; case INSEL_VALUE: @@ -252,6 +252,12 @@ char* hop_render(struct hop* hop) break; case IR_LOCAL: + if (ir->u.ivalue >= 0) + appendf("%d", current_proc->fp_to_ab + ir->u.ivalue); + else + appendf("%d", current_proc->fp_to_lb + ir->u.ivalue); + break; + case IR_CONST: appendf("%d", ir->u.ivalue); break; diff --git a/mach/proto/mcg/powerpc.c b/mach/proto/mcg/powerpc.c index a47d8a8cc..fbd669e3e 100644 --- a/mach/proto/mcg/powerpc.c +++ b/mach/proto/mcg/powerpc.c @@ -3,21 +3,22 @@ /* mcg stack frames are laid out as: * * | ...params... - * | --------------- <- ap + * | --------------- <- ab * | saved regs - * | --------------- <- st + * | --------------- * | spills - * | --------------- <- fp (a.k.a. lb) + * | --------------- <- st, fp (a.k.a. lb) * | locals * | --------------- <- sp * V ...user area... * + * st indexes up; lb indexes down. */ void platform_calculate_offsets(void) { - current_proc->fp_to_st = current_proc->spills_size; - current_proc->fp_to_ap = current_proc->fp_to_st + current_proc->saved_size + 8; + current_proc->fp_to_st = 0; + current_proc->fp_to_ab = current_proc->spills_size + current_proc->saved_size + 8; current_proc->fp_to_lb = 0; } @@ -25,7 +26,10 @@ struct hop* platform_prologue(void) { struct hop* hop = new_hop(current_proc->entry, NULL); - hop_add_insel(hop, "addi sp, sp, %d", current_proc->fp_to_ap + current_proc->locals_size); + hop_add_insel(hop, "! saved_size = %d+8 bytes", current_proc->saved_size); + hop_add_insel(hop, "! spills_size = %d bytes", current_proc->spills_size); + hop_add_insel(hop, "! locals_size = %d bytes", current_proc->locals_size); + hop_add_insel(hop, "addi sp, sp, %d", -(current_proc->fp_to_ab + current_proc->locals_size)); hop_add_insel(hop, "mfspr 0, lr"); hop_add_insel(hop, "stw fp, %d(sp)", current_proc->fp_to_st + current_proc->locals_size); hop_add_insel(hop, "stw 0, %d(sp)", current_proc->fp_to_st + current_proc->locals_size + 4); diff --git a/mach/proto/mcg/procedure.h b/mach/proto/mcg/procedure.h index 0cec9891f..2c0baf816 100644 --- a/mach/proto/mcg/procedure.h +++ b/mach/proto/mcg/procedure.h @@ -17,7 +17,7 @@ struct procedure int spills_size; int saved_size; int fp_to_st; - int fp_to_ap; + int fp_to_ab; int fp_to_lb; ARRAYOF(struct basicblock) blocks; IMAPOF(struct local) locals; From 286435a2ed157a8cb620f8b268445ccb85e4924b Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 23:34:54 +0200 Subject: [PATCH 118/230] Oops, forgot to add the output option spec to the string! --- mach/proto/mcg/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 1c0d7065c..36696bca4 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -46,7 +46,7 @@ int main(int argc, char* const argv[]) opterr = 1; for (;;) { - int c = getopt(argc, argv, "-d:D:C:"); + int c = getopt(argc, argv, "-d:D:C:o:"); if (c == -1) break; From 6a23906ad890612fe8c0af54ca76db8e0c232f21 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 23:39:38 +0200 Subject: [PATCH 119/230] Various bits of cleanup; we should almost be ready to try sending this to the assembler soon... --- mach/proto/mcg/main.c | 2 ++ mach/proto/mcg/powerpc.c | 4 ++-- mach/proto/mcg/procedure.c | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 36696bca4..b518bff59 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -101,6 +101,8 @@ int main(int argc, char* const argv[]) else outputfile = stdout; + fprintf(outputfile, ".sect .text\n.sect .rom\n.sect .data\n.sect .bss\n"); + /* Reads in the EM, outputs the data sections, parses any code and * generates IR trees. */ diff --git a/mach/proto/mcg/powerpc.c b/mach/proto/mcg/powerpc.c index fbd669e3e..1c900bea0 100644 --- a/mach/proto/mcg/powerpc.c +++ b/mach/proto/mcg/powerpc.c @@ -30,9 +30,9 @@ struct hop* platform_prologue(void) hop_add_insel(hop, "! spills_size = %d bytes", current_proc->spills_size); hop_add_insel(hop, "! locals_size = %d bytes", current_proc->locals_size); hop_add_insel(hop, "addi sp, sp, %d", -(current_proc->fp_to_ab + current_proc->locals_size)); - hop_add_insel(hop, "mfspr 0, lr"); + hop_add_insel(hop, "mfspr r0, lr"); hop_add_insel(hop, "stw fp, %d(sp)", current_proc->fp_to_st + current_proc->locals_size); - hop_add_insel(hop, "stw 0, %d(sp)", current_proc->fp_to_st + current_proc->locals_size + 4); + hop_add_insel(hop, "stw r0, %d(sp)", current_proc->fp_to_st + current_proc->locals_size + 4); hop_add_insel(hop, "addi fp, sp, %d", current_proc->locals_size); return hop; diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 1484c2af9..320dedf7b 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -110,6 +110,7 @@ static void emit_procedure(struct procedure* proc) { int i, j; + fprintf(outputfile, "\n.sect .text\n"); for (i=0; i Date: Sun, 16 Oct 2016 17:58:01 +0200 Subject: [PATCH 120/230] Add missing header that was causing builds to fail on Travis. --- util/mcgg/scan.l | 1 + 1 file changed, 1 insertion(+) diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index d6a60d361..d26dfac81 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -1,5 +1,6 @@ %{ #include +#include #include "iburg.h" #include "y.tab.h" From 1e1792120849fab66aa2a9d1fc80368638e721b3 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 16 Oct 2016 22:37:42 +0200 Subject: [PATCH 121/230] Implement saving of dirty registers onto the stack. --- mach/proto/mcg/pass_prologueepilogue.c | 19 +++++++++ mach/proto/mcg/powerpc.c | 54 ++++++++++++++++++++++++-- mach/proto/mcg/procedure.h | 1 + 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/mach/proto/mcg/pass_prologueepilogue.c b/mach/proto/mcg/pass_prologueepilogue.c index 53cc498ec..9a5762e8d 100644 --- a/mach/proto/mcg/pass_prologueepilogue.c +++ b/mach/proto/mcg/pass_prologueepilogue.c @@ -2,6 +2,25 @@ void pass_add_prologue_epilogue(void) { + int i, j, k; + + current_proc->usedregs.count = 0; + for (i=0; ihops.count; j++) + { + struct hop* hop = bb->hops.item[j]; + + for (k=0; kregsin.count; k++) + array_appendu(¤t_proc->usedregs, hop->regsin.item[k].left); + + for (k=0; kregsout.count; k++) + array_appendu(¤t_proc->usedregs, hop->regsout.item[k].left); + } + } + platform_calculate_offsets(); array_insert(¤t_proc->entry->hops, platform_prologue(), 0); diff --git a/mach/proto/mcg/powerpc.c b/mach/proto/mcg/powerpc.c index 1c900bea0..ab08209f3 100644 --- a/mach/proto/mcg/powerpc.c +++ b/mach/proto/mcg/powerpc.c @@ -15,8 +15,25 @@ * st indexes up; lb indexes down. */ +static ARRAYOF(struct hreg) saved_regs; + void platform_calculate_offsets(void) { + int i; + + saved_regs.count = 0; + for (i=0; iusedregs.count; i++) + { + struct hreg* hreg = current_proc->usedregs.item[i]; + + if (!(hreg->attrs & burm_volatile_ATTR) && + ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) + { + current_proc->saved_size += 4; + array_append(&saved_regs, hreg); + } + } + current_proc->fp_to_st = 0; current_proc->fp_to_ab = current_proc->spills_size + current_proc->saved_size + 8; current_proc->fp_to_lb = 0; @@ -24,6 +41,8 @@ void platform_calculate_offsets(void) struct hop* platform_prologue(void) { + int i; + int saved_offset; struct hop* hop = new_hop(current_proc->entry, NULL); hop_add_insel(hop, "! saved_size = %d+8 bytes", current_proc->saved_size); @@ -31,18 +50,47 @@ struct hop* platform_prologue(void) hop_add_insel(hop, "! locals_size = %d bytes", current_proc->locals_size); hop_add_insel(hop, "addi sp, sp, %d", -(current_proc->fp_to_ab + current_proc->locals_size)); hop_add_insel(hop, "mfspr r0, lr"); - hop_add_insel(hop, "stw fp, %d(sp)", current_proc->fp_to_st + current_proc->locals_size); - hop_add_insel(hop, "stw r0, %d(sp)", current_proc->fp_to_st + current_proc->locals_size + 4); + + hop_add_insel(hop, "stw r0, %d(sp)", current_proc->locals_size + current_proc->spills_size); + hop_add_insel(hop, "stw fp, %d(sp)", current_proc->locals_size + current_proc->spills_size + 4); hop_add_insel(hop, "addi fp, sp, %d", current_proc->locals_size); + saved_offset = current_proc->spills_size + 8; + for (i=0; itype & burm_int_ATTR) + hop_add_insel(hop, "stw %H, %d(fp)", hreg, saved_offset); + else if (hreg->type & burm_float_ATTR) + hop_add_insel(hop, "stfs %H, %d(fp)", hreg, saved_offset); + saved_offset += 4; + } return hop; } struct hop* platform_epilogue(void) { struct hop* hop = new_hop(current_proc->exit, NULL); + int i; + int saved_offset; - hop_add_insel(hop, "b .ret"); + saved_offset = current_proc->spills_size + 8; + for (i=0; itype & burm_int_ATTR) + hop_add_insel(hop, "lwz %H, %d(fp)", hreg, saved_offset); + else if (hreg->type & burm_float_ATTR) + hop_add_insel(hop, "lfs %H, %d(fp)", hreg, saved_offset); + saved_offset += 4; + } + + hop_add_insel(hop, "lwz r0, %d(fp)", current_proc->spills_size); + hop_add_insel(hop, "mtspr lr, r0"); + hop_add_insel(hop, "lwz r0, %d(fp)", current_proc->spills_size + 4); + hop_add_insel(hop, "addi sp, fp, %d", current_proc->fp_to_ab); + hop_add_insel(hop, "mr fp, r0"); + hop_add_insel(hop, "blr"); return hop; } diff --git a/mach/proto/mcg/procedure.h b/mach/proto/mcg/procedure.h index 2c0baf816..ead7abc9b 100644 --- a/mach/proto/mcg/procedure.h +++ b/mach/proto/mcg/procedure.h @@ -21,6 +21,7 @@ struct procedure int fp_to_lb; ARRAYOF(struct basicblock) blocks; IMAPOF(struct local) locals; + ARRAYOF(struct hreg) usedregs; }; extern void procedure_compile(struct procedure* proc); From 5f0164db620c65f403dc650a82c30103c3c87f11 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 17 Oct 2016 00:06:06 +0200 Subject: [PATCH 122/230] Bolt mcg into the PowerPC backend. It doesn't build yet, but it is generating *some* code. --- build.lua | 1 - first/ackbuilder.lua | 2 +- .../mcg/powerpc.c => powerpc/mcg/platform.c} | 0 mach/{proto => powerpc}/mcg/table | 4 + mach/proto/mcg/build.lua | 82 ++++++++++--------- mach/proto/mcg/treebuilder.c | 5 +- plat/build.lua | 1 + plat/linuxppc/build-tools.lua | 6 +- plat/linuxppc/descr | 2 +- 9 files changed, 58 insertions(+), 45 deletions(-) rename mach/{proto/mcg/powerpc.c => powerpc/mcg/platform.c} (100%) rename mach/{proto => powerpc}/mcg/table (99%) diff --git a/build.lua b/build.lua index 46d5b63d9..05a4eafcd 100644 --- a/build.lua +++ b/build.lua @@ -33,7 +33,6 @@ installable { "util/misc+pkg", "util/opt+pkg", "examples+pkg", - "mach/proto/mcg+pkg", plat_packages } } diff --git a/first/ackbuilder.lua b/first/ackbuilder.lua index 282e6f185..274ef112f 100644 --- a/first/ackbuilder.lua +++ b/first/ackbuilder.lua @@ -453,7 +453,7 @@ loadtarget = function(targetname) target = targets[targetname] if not target then error(string.format("build file '%s' contains no target '%s'", - filename, targetpart)) + filepart, targetpart)) end end diff --git a/mach/proto/mcg/powerpc.c b/mach/powerpc/mcg/platform.c similarity index 100% rename from mach/proto/mcg/powerpc.c rename to mach/powerpc/mcg/platform.c diff --git a/mach/proto/mcg/table b/mach/powerpc/mcg/table similarity index 99% rename from mach/proto/mcg/table rename to mach/powerpc/mcg/table index d744dbbf7..95ba2a9fd 100644 --- a/mach/proto/mcg/table +++ b/mach/powerpc/mcg/table @@ -423,6 +423,10 @@ PATTERNS emit "subf %out, %out, %left" cost 12; + out:(int)reg = MUL4(left:(int)reg, right:(int)reg) + emit "mullw %out, %left, %right" + cost 4; + out:(int)reg = DIV4(left:(int)reg, right:(int)reg) emit "divw %out, %left, %right" cost 4; diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index 8fc41be95..387d14d26 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -1,43 +1,51 @@ include("util/mcgg/build.lua") -mcgg { - name = "mcgg_c", - srcs = { "./table" } -} - -cprogram { - name = "mcg", - srcs = { - "./*.c", - matching(filenamesof("+mcgg_c"), "%.c$"), +definerule("build_mcg", + { + arch = { type="string" } }, - deps = { - "+mcgg_c", - "./*.h", - "h+emheaders", - "modules+headers", - "modules/src/alloc+lib", - "modules/src/data+lib", - "modules/src/em_code+lib_k", - "modules/src/em_data+lib", - "modules/src/idf+lib", - "modules/src/read_em+lib_ev", - "modules/src/string+lib", - "modules/src/system+lib", - "util/mcgg+lib", - }, - vars = { - ["+cflags"] = { - "-Werror-implicit-function-declaration", + function(e) + -- Remember this is executed from the caller's directory; local + -- target names will resolve there + local headers = clibrary { + name = e.name.."/headers", + srcs = {}, + hdrs = { + "mach/proto/mcg/*.h", + "mach/"..e.arch.."/mcg/*.h", + } } - } -} --- Just for test purposes for now -installable { - name = "pkg", - map = { - ["$(PLATDEP)/mcg"] = "+mcg" - } -} + local tables = mcgg { + name = e.name.."/tables", + srcs = { "mach/"..e.arch.."/mcg/table" } + } + + return cprogram { + name = e.name, + srcs = { + "mach/proto/mcg/*.c", + "mach/"..e.arch.."/mcg/platform.c", + matching(filenamesof(tables), "%.c$") + }, + deps = { + "h+emheaders", + "modules+headers", + "modules/src/alloc+lib", + "modules/src/data+lib", + "modules/src/em_code+lib_k", + "modules/src/em_data+lib", + "modules/src/flt_arith+lib", + "modules/src/idf+lib", + "modules/src/object+lib", + "modules/src/read_em+lib_kv", + "modules/src/string+lib", + "modules/src/system+lib", + "util/mcgg+lib", + headers, + tables, -- for .h file + } + } + end +) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index cf25de4b9..e3d0f521d 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -441,12 +441,13 @@ static void insn_ivalue(int opcode, arith value) case op_rmi: simple_alu2(opcode, value, IR_MOD); break; case op_sli: simple_alu2(opcode, value, IR_ASL); break; case op_sri: simple_alu2(opcode, value, IR_ASR); break; - case op_slu: simple_alu2(opcode, value, IR_LSL); break; - case op_sru: simple_alu2(opcode, value, IR_LSR); break; case op_ngi: simple_alu1(opcode, value, IR_NEG); break; case op_adu: simple_alu2(opcode, value, IR_ADD); break; case op_sbu: simple_alu2(opcode, value, IR_SUB); break; + case op_mlu: simple_alu2(opcode, value, IR_MUL); break; + case op_slu: simple_alu2(opcode, value, IR_LSL); break; + case op_sru: simple_alu2(opcode, value, IR_LSR); break; case op_and: simple_alu2(opcode, value, IR_AND); break; case op_ior: simple_alu2(opcode, value, IR_OR); break; diff --git a/plat/build.lua b/plat/build.lua index dc0e87c5e..a6774b920 100644 --- a/plat/build.lua +++ b/plat/build.lua @@ -1,5 +1,6 @@ include("mach/proto/as/build.lua") include("mach/proto/ncg/build.lua") +include("mach/proto/mcg/build.lua") include("mach/proto/top/build.lua") definerule("ackfile", diff --git a/plat/linuxppc/build-tools.lua b/plat/linuxppc/build-tools.lua index 4d0f0048d..84f6e774d 100644 --- a/plat/linuxppc/build-tools.lua +++ b/plat/linuxppc/build-tools.lua @@ -5,8 +5,8 @@ build_as { arch = "powerpc", } -build_ncg { - name = "ncg", +build_mcg { + name = "mcg", arch = "powerpc", } @@ -14,7 +14,7 @@ return installable { name = "tools", map = { ["$(PLATDEP)/linuxppc/as"] = "+as", - ["$(PLATDEP)/linuxppc/ncg"] = "+ncg", + ["$(PLATDEP)/linuxppc/mcg"] = "+mcg", ["$(PLATIND)/descr/linuxppc"] = "./descr", "util/opt+pkg", } diff --git a/plat/linuxppc/descr b/plat/linuxppc/descr index b70680201..770e8834f 100644 --- a/plat/linuxppc/descr +++ b/plat/linuxppc/descr @@ -35,7 +35,7 @@ var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi name be from .m.g to .s - program {EM}/lib/ack/{PLATFORM}/ncg + program {EM}/lib/ack/{PLATFORM}/mcg mapflag -gdb GF=-gdb args {GF?} < stdout From 4a093b9eba1005e285b01747e4d7ccf5fff3d4c4 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 18 Oct 2016 00:21:32 +0200 Subject: [PATCH 123/230] Add li and mr pseudoinstructions. --- mach/powerpc/as/mach0.c | 2 ++ mach/powerpc/as/mach2.c | 1 + mach/powerpc/as/mach3.c | 2 ++ mach/powerpc/as/mach4.c | 14 +++++++++++--- mach/proto/as/comm0.h | 2 ++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/mach/powerpc/as/mach0.c b/mach/powerpc/as/mach0.c index 3a42f1dd8..325c08910 100644 --- a/mach/powerpc/as/mach0.c +++ b/mach/powerpc/as/mach0.c @@ -19,6 +19,8 @@ #undef word_t #define word_t long +typedef uint32_t quad; + #undef ALIGNWORD #define ALIGNWORD 4 diff --git a/mach/powerpc/as/mach2.c b/mach/powerpc/as/mach2.c index d1a959fc3..8d72daef3 100644 --- a/mach/powerpc/as/mach2.c +++ b/mach/powerpc/as/mach2.c @@ -49,6 +49,7 @@ %token OP_RS_RA_NB %token OP_RS_RA_RB %token OP_RS_RA_RB_C +%token OP_RS_RA_RA_C %token OP_RS_RA_RB_MB5_ME5_C %token OP_RS_RA_RB_MB6_C %token OP_RS_RA_RB_ME6_C diff --git a/mach/powerpc/as/mach3.c b/mach/powerpc/as/mach3.c index 278a7e607..7fc5d87f0 100644 --- a/mach/powerpc/as/mach3.c +++ b/mach/powerpc/as/mach3.c @@ -99,6 +99,8 @@ /* Special instructions */ 0, OP_LA, 0, "la", +0, OP_LA, 0, "li", +0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr", /* Branch processor instructions (page 20) */ diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c index acb4abf1b..31d85dd99 100644 --- a/mach/powerpc/as/mach4.c +++ b/mach/powerpc/as/mach4.c @@ -44,6 +44,7 @@ operation | OP_RS_RA_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); } | OP_RS_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_RS_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } + | OP_RS_RA_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); } | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } | OP_RS_RA_RB_MB6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } | OP_RS_RA_RB_ME6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } @@ -196,9 +197,16 @@ bda la : GPR ',' expr { - newrelo($3.typ, RELOPPC | FIXUPFLAGS); - emit4((15<<26) | ($1<<21) | (0<<16) | ($3.val >> 16)); /* addis */ - emit4((24<<26) | ($1<<21) | ($1<<16) | ($3.val & 0xffff)); /* ori */ + quad type = $3.typ & S_TYP; + quad val = $3.val; + if ((type == S_ABS) && (val <= 0xffff)) + emit4((14<<26) | ($1<<21) | (0<<16) | val); /* addi */ + else + { + newrelo($3.typ, RELOPPC | FIXUPFLAGS); + emit4((15<<26) | ($1<<21) | (0<<16) | (val >> 16)); /* addis */ + emit4((24<<26) | ($1<<21) | ($1<<16) | (val & 0xffff)); /* ori */ + } } ; diff --git a/mach/proto/as/comm0.h b/mach/proto/as/comm0.h index 4996350ac..dedafa4c7 100644 --- a/mach/proto/as/comm0.h +++ b/mach/proto/as/comm0.h @@ -8,6 +8,8 @@ * All preprocessor based options/constants/functions */ +#include + /* ========== ON/OFF options (use #define in mach0.c) ========== */ /* From 938fb8c2fc4bc4fb9d6447d8e3cc8542786e388e Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 18 Oct 2016 00:31:26 +0200 Subject: [PATCH 124/230] Lots more opcodes. --- mach/powerpc/mcg/platform.c | 2 +- mach/powerpc/mcg/table | 30 ++++++--- mach/proto/mcg/treebuilder.c | 119 ++++++++++++++++++++++++++++++++++- 3 files changed, 141 insertions(+), 10 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index ab08209f3..2e598335a 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -90,7 +90,7 @@ struct hop* platform_epilogue(void) hop_add_insel(hop, "lwz r0, %d(fp)", current_proc->spills_size + 4); hop_add_insel(hop, "addi sp, fp, %d", current_proc->fp_to_ab); hop_add_insel(hop, "mr fp, r0"); - hop_add_insel(hop, "blr"); + hop_add_insel(hop, "bclr 20, 0, 0"); return hop; } diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 95ba2a9fd..93bdb1929 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -269,7 +269,7 @@ PATTERNS /* Locals */ out:(int)reg = in:LOCAL4 - emit "addi %out, fp, #$in" + emit "addi %out, fp, $in" cost 4; address = in:LOCAL4 @@ -295,17 +295,17 @@ PATTERNS cost 4; CJUMPEQ(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) - emit "bc IFTRUE, EQ, $true" + emit "bc 12, 2, $true" /* IFTRUE EQ */ emit "b $false" cost 8; CJUMPLE(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) - emit "bc IFTRUE, LE, $true" + emit "bc 4, 1, $true" /* IFFALSE GT */ emit "b $false" cost 8; CJUMPLT(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) - emit "bc IFTRUE, LT, $true" + emit "bc 12, 0, $true" /* IFTRUE LT */ emit "b $false" cost 8; @@ -317,7 +317,7 @@ PATTERNS CALL(dest:(int)reg) with corrupted(volatile) emit "mtspr ctr, %dest" - emit "bcctrl ALWAYS, 0, 0" + emit "bcctrl 20, 0, 0" cost 8; JUMP(dest:LABEL4) @@ -381,11 +381,13 @@ PATTERNS /* Conversions */ out:(int)reg = CIU44(in:(int)reg) - emit "mr %out, %in ! ciu44" + with %out == %in + emit "! ciu44" cost 4; out:(int)reg = CUI44(in:(int)reg) - emit "mr %out, %in ! cui44" + with %out == %in + emit "! cui44" cost 4; @@ -410,7 +412,7 @@ PATTERNS cost 4; out:(int)reg = SUB4(left:(int)reg, right:CONST4) - emit "addi %out, %left, -($right)" + emit "addi %out, %left, -[$right]" cost 4; out:(int)reg = MUL4(left:(int)reg, right:(int)reg) @@ -439,6 +441,18 @@ PATTERNS emit "neg %out, %left" cost 4; + out:(int)reg = AND4(left:CONST4, right:(int)reg) + emit "andi. %out, %right, $left" + cost 4; + + out:(int)reg = AND4(left:(int)reg, right:CONST4) + emit "andi. %out, %left, $right" + cost 4; + + out:(int)reg = AND4(left:(int)reg, right:(int)reg) + emit "and %out, %left, %right" + cost 4; + out:(int)reg = OR4(left:(int)reg, right:(int)reg) emit "or %out, %right, %left" cost 4; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index e3d0f521d..9fbae16d1 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -528,6 +528,47 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_loe: + push( + new_ir1( + IR_LOAD, EM_wordsize, + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(".hol0"), + new_wordir(value) + ) + ) + ); + break; + + case op_ste: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(".hol0"), + new_wordir(value) + ), + pop(EM_wordsize) + ) + ); + break; + + case op_zre: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(".hol0"), + new_wordir(value) + ), + new_wordir(0) + ) + ); + break; + case op_loc: push( new_wordir(value) @@ -577,7 +618,7 @@ static void insn_ivalue(int opcode, arith value) case op_stf: { struct ir* ptr = pop(EM_pointersize); - struct ir* val = pop(value); + struct ir* val = pop(EM_wordsize); appendir( new_ir2( @@ -854,6 +895,48 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_fef: + { + struct ir* e; + struct ir* f = pop(value); + /* fef is implemented by synthesising a call to frexp. */ + push( + new_labelir(".fef_exp") + ); + push( + f + ); + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir((value == 4) ? "frexpf" : "frexp") + ) + ); + appendir( + new_ir1( + IR_STACKADJUST, EM_wordsize, + new_wordir(4 + value) + ) + ); + e = appendir( + new_ir0( + IR_GETRET, value + ) + ); + push( + new_ir1( + IR_LOAD, EM_wordsize, + new_labelir(".fef_exp") + ) + ); + push( + e + ); + + break; + } + case op_lin: { /* Set line number --- ignore. */ @@ -905,6 +988,40 @@ static void insn_lvalue(int opcode, const char* label, arith offset) ); break; + case op_ine: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_external(label, offset), + new_ir2( + IR_ADD, EM_wordsize, + new_ir1( + IR_LOAD, EM_wordsize, + address_of_external(label, offset) + ), + new_wordir(1) + ) + ) + ); + break; + + case op_dee: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_external(label, offset), + new_ir2( + IR_ADD, EM_wordsize, + new_ir1( + IR_LOAD, EM_wordsize, + address_of_external(label, offset) + ), + new_wordir(-1) + ) + ) + ); + break; + case op_cal: assert(offset == 0); materialise_stack(); From 3520704ea8e745175c3ce4910547893821f5e0ee Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 18 Oct 2016 22:29:42 +0200 Subject: [PATCH 125/230] Add support for floating point constants. --- mach/proto/mcg/data.c | 25 +++++++++++++++++++++++++ mach/proto/mcg/mcg.h | 2 ++ mach/proto/mcg/parse_em.c | 6 ++++++ 3 files changed, 33 insertions(+) diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index 0f79cb767..38525b724 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -1,6 +1,13 @@ #include "mcg.h" #include +#define IEEEFLOAT +#define FL_MSL_AT_LOW_ADDRESS 1 +#define FL_MSW_AT_LOW_ADDRESS 1 +#define FL_MSB_AT_LOW_ADDRESS 1 + +#include "con_float" + static struct symbol* pending; void data_label(const char* label) @@ -49,6 +56,24 @@ void data_int(arith data, size_t size, bool is_ro) fprintf(outputfile, "\t.data%d 0x%0*lld\n", size, size*2, data); } +void data_float(const char* data, size_t size, bool is_ro) +{ + unsigned char buffer[8]; + int i; + + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + assert((size == 4) || (size == 8)); + + if (float_cst(data, size, (char*) buffer)) + fatal("cannot parse floating point constant %s sz %d", data, size); + + fprintf(outputfile, "\t!float %s sz %d\n", data, size); + fprintf(outputfile, "\t.data1 0x%02x", buffer[0]); + for (i=1; i #include #include +#include "flt_arith.h" #include "em_arith.h" #include "em_label.h" #include "em.h" @@ -93,6 +94,7 @@ extern struct symbol* symbol_walk(symbol_walker_t* walker, void* user); extern void data_label(const char* name); extern void data_int(arith data, size_t size, bool is_ro); +extern void data_float(const char* data, size_t size, bool is_ro); extern void data_block(const uint8_t* data, size_t size, bool is_ro); extern void data_offset(const char* label, arith offset, bool is_ro); extern void data_bss(arith size, int init); diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index c49922ac8..9551ecd02 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -230,6 +230,12 @@ static void parse_pseu(void) break; } + case fco_ptyp: + { + data_float(em.em_string, em.em_size, ro); + break; + } + case str_ptyp: data_block(strdup(em.em_string), em.em_size, ro); break; From 5413d470290d2872d2ab04af6ade8e09eee89445 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 18 Oct 2016 22:32:09 +0200 Subject: [PATCH 126/230] '!' tracing is now always emitted; tracing goes to stderr. --- mach/proto/mcg/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index b518bff59..cf8a4435f 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -10,6 +10,8 @@ FILE* cfg_dot_file = NULL; bool tracing(char k) { + if (k == '!') + return true; if (!tracechars) return false; @@ -23,7 +25,7 @@ void tracef(char k, const char* fmt, ...) if (tracing(k)) { va_start(ap, fmt); - vprintf(fmt, ap); + vfprintf(stderr, fmt, ap); va_end(ap); } } From d5071e7df1ae9b28b3bb2039b6461890cf3178a8 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 18 Oct 2016 23:58:03 +0200 Subject: [PATCH 127/230] Promote values accessed via NOP. --- mach/proto/mcg/pass_promotefloatops.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c index 33992145c..ffea3f0dc 100644 --- a/mach/proto/mcg/pass_promotefloatops.c +++ b/mach/proto/mcg/pass_promotefloatops.c @@ -40,6 +40,10 @@ static void promote(struct ir* ir) array_appendu(&promotable, ir); break; + case IR_NOP: + promote(ir->left); + break; + case IR_PHI: { int i; From ffb1eabf4525d5e5c9e6d62894f63c775f876eab Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 19 Oct 2016 23:27:53 +0200 Subject: [PATCH 128/230] Floating point promotion is less buggy. --- mach/proto/mcg/pass_promotefloatops.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c index ffea3f0dc..87db1e47d 100644 --- a/mach/proto/mcg/pass_promotefloatops.c +++ b/mach/proto/mcg/pass_promotefloatops.c @@ -86,8 +86,21 @@ static void modify_promotable_irs(void) { struct ir* ir = promotable.item[i]; - if (ir->opcode != IR_PHI) - ir->opcode++; + switch (ir->opcode) + { + case IR_ADDF: + case IR_SUBF: + case IR_MULF: + case IR_DIVF: + case IR_NEGF: + case IR_PHI: + case IR_NOP: + break; + + default: + ir->opcode++; + break; + } } } From e4fec71f9c5d0911f6f9075cffcfb9eaad20962a Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 19 Oct 2016 23:29:05 +0200 Subject: [PATCH 129/230] Lots more opcodes; better eviction behaviour; better register moves. Lots more PowerPC stuff (some working). --- mach/powerpc/mcg/platform.c | 45 +++++++++++++++++++--- mach/powerpc/mcg/table | 34 +++++++++++++++- mach/proto/mcg/pass_instructionselection.c | 2 +- mach/proto/mcg/pass_prologueepilogue.c | 12 +++++- mach/proto/mcg/pass_registerallocator.c | 33 ++++++++++------ mach/proto/mcg/treebuilder.c | 30 ++++++++------- util/mcgg/ir.dat | 11 ++++++ 7 files changed, 131 insertions(+), 36 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 2e598335a..0feaf0da7 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -99,14 +99,47 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* { struct hop* hop = new_hop(bb, NULL); - if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR)) - { - if (src->is_stacked) - hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src); - else if (dest->is_stacked) + if (!src->is_stacked && dest->is_stacked) + { + if (src->type & burm_int_ATTR) hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest); - else + else if (src->type & burm_float_ATTR) + hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest); + else + assert(false); + } + else if (src->is_stacked && !dest->is_stacked) + { + if (src->type & burm_int_ATTR) + hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src); + else if (src->type & burm_float_ATTR) + hop_add_insel(hop, "lfs %H, %S(fp) ! %H", dest, src, src); + else + assert(false); + } + else if (!src->is_stacked && !dest->is_stacked) + { + if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR)) hop_add_insel(hop, "mr %H, %H", dest, src); + else if ((src->type & burm_float_ATTR) && (dest->type & burm_float_ATTR)) + hop_add_insel(hop, "fmr %H, %H", dest, src); + else + { + if (src->type & burm_int_ATTR) + hop_add_insel(hop, "stwu %H, -4(sp)", src); + else if (src->type & burm_float_ATTR) + hop_add_insel(hop, "stfsu %H, -4(sp)", src); + else + assert(false); + + if (dest->type & burm_int_ATTR) + hop_add_insel(hop, "lwz %H, 0(sp)", dest); + else if (dest->type & burm_float_ATTR) + hop_add_insel(hop, "lfs %H, 0(sp)", dest); + else + assert(false); + hop_add_insel(hop, "addi sp, sp, 4"); + } } else fatal("cannot generate move from %s to %s", src->name, dest->name); diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 93bdb1929..3a1da6fd6 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -16,7 +16,7 @@ REGISTERS r6 "r6" bytes4! int! volatile; r5 "r5" bytes4! int! volatile; r4 "r4" bytes4! int! volatile; - r3 "r3" bytes4! int! ret volatile; + r3 "r3" bytes4! int! volatile ret; r31 "r31" bytes4! int!; r30 "r30" bytes4! int!; @@ -48,7 +48,7 @@ REGISTERS f6 "f6" bytes4! float! volatile; f5 "f5" bytes4! float! volatile; f4 "f4" bytes4! float! volatile; - f3 "f3" bytes4! float! volatile; + f3 "f3" bytes4! float! volatile fret; f2 "f2" bytes4! float! volatile; f1 "f1" bytes4! float! volatile; f0 "f0" bytes4! float! volatile; @@ -476,6 +476,10 @@ PATTERNS /* FPU operations */ + out:(float)reg = LOADF4(addr:address) + emit "lfs %out, %addr" + cost 4; + out:(float)reg = value:CONSTF4 emit "lfs %out, address-containing-$value" cost 8; @@ -488,6 +492,32 @@ PATTERNS emit "fsubs %out, %left, %right" cost 4; + out:(float)reg = MULF4(left:(float)reg, right:(float)reg) + emit "fmuls %out, %left, %right" + cost 4; + + out:(float)reg = NEGF4(left:(float)reg) + emit "fneg %out, %left" + cost 4; + + cr:(cr)cr = COMPAREF4(left:(float)reg, right:(float)reg) + emit "fcmpu %cr, %left, %right" + cost 4; + + cr:(cr)cr = COMPARES4(COMPAREF4(left:(float)reg, right:(float)reg), result:CONST4) + when specific_constant(%result, 0) + emit "fcmpu %cr, %left, %right" + cost 4; + + out:(ret)reg = CFI44(val:(fret)reg) + with corrupted(volatile) + emit "bl .cfi4" + cost 4; + + out:(fret)reg = CIF44(val:(ret)reg) + with corrupted(volatile) + emit "bl .cif4" + cost 4; /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 82d7f9875..fcfb55182 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -27,7 +27,7 @@ void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) { void burm_panic_cannot_match(struct burm_node* node) { fprintf(stderr, "could not find any patterns to match:\n"); - ir_print(0, node->ir); + ir_print('!', node->ir); fprintf(stderr, "aborting!\n"); exit(1); } diff --git a/mach/proto/mcg/pass_prologueepilogue.c b/mach/proto/mcg/pass_prologueepilogue.c index 9a5762e8d..3b0c517cb 100644 --- a/mach/proto/mcg/pass_prologueepilogue.c +++ b/mach/proto/mcg/pass_prologueepilogue.c @@ -14,10 +14,18 @@ void pass_add_prologue_epilogue(void) struct hop* hop = bb->hops.item[j]; for (k=0; kregsin.count; k++) - array_appendu(¤t_proc->usedregs, hop->regsin.item[k].left); + { + struct hreg* hreg = hop->regsin.item[k].left; + if (!hreg->is_stacked) + array_appendu(¤t_proc->usedregs, hreg); + } for (k=0; kregsout.count; k++) - array_appendu(¤t_proc->usedregs, hop->regsout.item[k].left); + { + struct hreg* hreg = hop->regsout.item[k].left; + if (!hreg->is_stacked) + array_appendu(¤t_proc->usedregs, hreg); + } } } diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 393395e37..93a9b1dad 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -16,6 +16,8 @@ static register_assignment_t* current_outs; static int insert_moves(struct basicblock* bb, int index, register_assignment_t* srcregs, register_assignment_t* destregs); +static bool type_match(struct hreg* hreg, struct vreg* vreg); + static void populate_hregs(void) { const struct burm_register_data* brd = burm_register_data; @@ -65,9 +67,7 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs, static bool evictable(struct hreg* hreg, struct vreg* vreg) { - struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); - return (hreg->attrs & c->attrs) && !array_contains(¤t_hop->ins, vreg); - /* Find an unused output register of the right class which is not also being used as an input register. */ + return type_match(hreg, vreg) && !array_contains(¤t_hop->ins, vreg); } static struct hreg* evict(struct vreg* vreg) @@ -81,17 +81,26 @@ static struct hreg* evict(struct vreg* vreg) for (i=0; iid, hreg->name); - pmap_put(&evicted, candidate, hreg); - pmap_remove(current_ins, hreg, candidate); - pmap_remove(current_outs, hreg, candidate); - return hreg; + if (!candidatein && !candidateout) + { + /* This hreg is unused, so we don't need to evict anything. + * Shouldn't really happen in real life. */ + return hreg; + } + if (candidatein == candidateout) + { + /* This is a through register. */ + tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->name); + pmap_put(&evicted, candidatein, hreg); + pmap_remove(current_ins, hreg, candidatein); + pmap_remove(current_outs, hreg, candidatein); + return hreg; + } } } diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 9fbae16d1..8684f1fd5 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -197,6 +197,8 @@ static void insn_simple(int opcode) case op_cii: simple_convert(IR_CII1); break; case op_ciu: simple_convert(IR_CIU1); break; case op_cui: simple_convert(IR_CUI1); break; + case op_cfi: simple_convert(IR_CFI1); break; + case op_cif: simple_convert(IR_CIF1); break; case op_cmp: push( @@ -460,6 +462,11 @@ static void insn_ivalue(int opcode, arith value) case op_dvf: simple_alu2(opcode, value, IR_DIVF); break; case op_ngf: simple_alu1(opcode, value, IR_NEGF); break; + case op_cmu: /* fall through */ + case op_cms: push(tristate_compare(value, IR_COMPAREU)); break; + case op_cmi: push(tristate_compare(value, IR_COMPARES)); break; + case op_cmf: push(tristate_compare(value, IR_COMPAREF)); break; + case op_lol: push( new_ir1( @@ -469,6 +476,15 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_ldl: + push( + new_ir1( + IR_LOAD, EM_wordsize*2, + new_localir(value) + ) + ); + break; + case op_stl: appendir( new_ir2( @@ -634,19 +650,6 @@ static void insn_ivalue(int opcode, arith value) break; } - case op_cmi: - push( - tristate_compare(value, IR_COMPARES) - ); - break; - - case op_cmu: - case op_cms: - push( - tristate_compare(value, IR_COMPAREU) - ); - break; - case op_ads: { struct ir* off = pop(value); @@ -953,6 +956,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset) { switch (opcode) { + case op_lpi: case op_lae: push( address_of_external(label, offset) diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 44e28e9f8..6f40ae3c0 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -63,9 +63,20 @@ S CUI2 S CUI4 S CUI8 +S CFI1 +S CFI2 +S CFI4 +S CFI8 + +S CIF1 +S CIF2 +S CIF4 +S CIF8 + # Tristate comparisons S COMPARES S COMPAREU +S COMPAREF # Boolean comparisons S IFEQ From d6984d60acf3a66c22ef547066dabbd3b2dd437b Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 20 Oct 2016 21:47:28 +0200 Subject: [PATCH 130/230] Add parsing support for register aliases. --- util/mcgg/gram.y | 8 ++++++++ util/mcgg/iburg.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- util/mcgg/iburg.h | 12 +++++++----- util/mcgg/mcgg.h | 1 + util/mcgg/scan.l | 1 + 5 files changed, 59 insertions(+), 8 deletions(-) diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 067ad3d8d..e6b1c2fd0 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -25,6 +25,7 @@ extern int yylex(void); struct constraint* constraint; } +%term ALIASES %term COPY %term CORRUPTED %term COST @@ -43,6 +44,7 @@ extern int yylex(void); %token ID %token QFRAGMENT +%type aliases; %type constraint %type constraints %type predicate @@ -72,10 +74,16 @@ registers register : ID QFRAGMENT { $$ = makereg($1, $2); } + | register ALIASES '(' aliases ')' { $$ = $1; addregaliases($$, $4); } | register ID { $$ = $1; addregattr($1, $2, false); } | register ID '!' { $$ = $1; addregattr($1, $2, true); } ; +aliases + : ID { $$ = calloc(1, sizeof(*$$)); stringlist_add($$, $1); } + | aliases ',' ID { $$ = $1; stringlist_add($$, $3); } + ; + declarations : /* nothing */ | declarations declaration ';' diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 39cdf9729..cf7950b26 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -279,6 +279,7 @@ struct reg* makereg(const char* id, const char* realname) p->name = id; p->realname = realname; p->number = number++; + array_append(&p->aliases, p); smap_put(®isters, id, p); return p; @@ -311,6 +312,34 @@ void addregattr(struct reg* reg, const char* id, bool exact) reg->type |= 1<<(p->number); } +void addregalias(struct reg* r1, struct reg* r2) +{ + if (!array_appendu(&r1->aliases, r2)) + { + int i; + + for (i=0; ialiases.count; i++) + addregalias(r1->aliases.item[i], r2); + } +} + +void addregaliases(struct reg* reg, struct stringlist* aliases) +{ + struct stringfragment* f = aliases->first; + + while (f) + { + struct reg* r = smap_get(®isters, f->data); + if (!r) + yyerror("register '%s' is not defined here", f->data); + + array_appendu(®->aliases, r); + array_appendu(&r->aliases, reg); + + f = f->next; + } +} + struct regattr* getregattr(const char* id) { struct regattr* p = smap_get(®isterattrs, id); @@ -588,7 +617,17 @@ static void emitregisterattrs(void) static void emitregisters(void) { - int i; + int i, j; + + for (i=0; iname); + for (j=0; jaliases.count; j++) + print("&%Pregister_data[%d], ", r->aliases.item[j]->number); + print("NULL\n};\n"); + } print("const struct %Pregister_data %Pregister_data[] = {\n"); for (i=0; inumber == i); - print("%1{ \"%s\", \"%s\", 0x%x, 0x%x },\n", - r->name, r->realname, r->type, r->attrs); + print("%1{ \"%s\", \"%s\", 0x%x, 0x%x, %Pregister_aliases_%d_%s },\n", + r->name, r->realname, r->type, r->attrs, i, r->name); } print("%1{ NULL }\n"); print("};\n\n"); diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index d12985eb6..f50e4c9da 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -58,11 +58,12 @@ struct terminfo struct reg { - const char* name; /* friendly register name */ - const char* realname; /* name used in assembly output */ - int number; /* identifying number */ - uint32_t attrs; /* bitfield of register attributes */ - uint32_t type; /* register type */ + const char* name; /* friendly register name */ + const char* realname; /* name used in assembly output */ + int number; /* identifying number */ + uint32_t attrs; /* bitfield of register attributes */ + uint32_t type; /* register type */ + ARRAYOF(struct reg) aliases; /* registers that this one aliases */ }; struct regattr @@ -73,6 +74,7 @@ struct regattr extern struct reg* makereg(const char* name, const char* realname); extern void addregattr(struct reg* reg, const char* regattr, bool exact); +extern void addregaliases(struct reg* reg, struct stringlist* aliases); extern struct regattr* getregattr(const char* name); struct term diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 2631e0097..211aaf1cc 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -67,6 +67,7 @@ struct burm_register_data const char* realname; uint32_t type; uint32_t attrs; + const struct burm_register_data** aliases; }; extern const struct burm_register_data burm_register_data[]; diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index d26dfac81..44a582456 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -39,6 +39,7 @@ static int braces = 0; "DECLARATIONS" return DECLARATIONS; "PATTERNS" return PATTERNS; "REGISTERS" return REGISTERS; +"aliases" return ALIASES; "corrupted" return CORRUPTED; "cost" return COST; "emit" return EMIT; From 4db402f22989bfd80f08a077c6ef0ecd8c09acbc Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 21 Oct 2016 23:31:00 +0200 Subject: [PATCH 131/230] Add (pretty crummy) support for register aliases and static pairs of registers. We should have enough functionality now for rather buggy 8-bit ints and doubles. Rework the table and the platform.c to match. --- mach/powerpc/mcg/platform.c | 147 +++++++++++---- mach/powerpc/mcg/table | 208 ++++++++++++++------- mach/proto/mcg/hop.c | 14 +- mach/proto/mcg/hop.h | 5 +- mach/proto/mcg/pass_instructionselection.c | 10 +- mach/proto/mcg/pass_promotefloatops.c | 2 +- mach/proto/mcg/pass_registerallocator.c | 67 +++++-- mach/proto/mcg/reg.c | 9 +- mach/proto/mcg/reg.h | 5 +- mach/proto/mcg/treebuilder.c | 29 +++ util/mcgg/gram.y | 12 +- util/mcgg/iburg.c | 58 ++++-- util/mcgg/iburg.h | 5 +- util/mcgg/ir.dat | 1 + util/mcgg/mcgg.h | 8 +- util/mcgg/scan.l | 3 +- 16 files changed, 422 insertions(+), 161 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 0feaf0da7..e3ab26913 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -98,51 +98,122 @@ struct hop* platform_epilogue(void) struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest) { struct hop* hop = new_hop(bb, NULL); + const uint32_t type_attrs = + burm_int_ATTR | burm_pair_ATTR | burm_float_ATTR | burm_double_ATTR; - if (!src->is_stacked && dest->is_stacked) + if ((src->type & type_attrs) != (dest->type & type_attrs)) { - if (src->type & burm_int_ATTR) - hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest); - else if (src->type & burm_float_ATTR) - hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest); - else - assert(false); - } - else if (src->is_stacked && !dest->is_stacked) - { - if (src->type & burm_int_ATTR) - hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src); - else if (src->type & burm_float_ATTR) - hop_add_insel(hop, "lfs %H, %S(fp) ! %H", dest, src, src); - else - assert(false); - } - else if (!src->is_stacked && !dest->is_stacked) - { - if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR)) - hop_add_insel(hop, "mr %H, %H", dest, src); - else if ((src->type & burm_float_ATTR) && (dest->type & burm_float_ATTR)) - hop_add_insel(hop, "fmr %H, %H", dest, src); - else + assert(!src->is_stacked); + assert(!dest->is_stacked); + + switch (src->type & type_attrs) { - if (src->type & burm_int_ATTR) + case burm_int_ATTR: hop_add_insel(hop, "stwu %H, -4(sp)", src); - else if (src->type & burm_float_ATTR) - hop_add_insel(hop, "stfsu %H, -4(sp)", src); - else - assert(false); + break; - if (dest->type & burm_int_ATTR) - hop_add_insel(hop, "lwz %H, 0(sp)", dest); - else if (dest->type & burm_float_ATTR) - hop_add_insel(hop, "lfs %H, 0(sp)", dest); - else + case burm_float_ATTR: + hop_add_insel(hop, "stfsu %H, -4(sp)", src); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "stfdu %H, -8(sp)", src); + break; + + default: assert(false); - hop_add_insel(hop, "addi sp, sp, 4"); } - } - else - fatal("cannot generate move from %s to %s", src->name, dest->name); + + switch (dest->type & type_attrs) + { + case burm_int_ATTR: + hop_add_insel(hop, "lwz %H, 0(sp)", dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "lfs %H, 0(sp)", dest); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "lfd %H, 0(sp)", dest); + break; + + default: + assert(false); + } + + switch (dest->type & type_attrs) + { + case burm_int_ATTR: + case burm_float_ATTR: + hop_add_insel(hop, "addi sp, sp, 4"); + break; + + case burm_double_ATTR: + case burm_pair_ATTR: + hop_add_insel(hop, "addi sp, sp, 8"); + break; + + default: + assert(false); + } + } + else + { + uint32_t type = src->type & type_attrs; + + if (!src->is_stacked && dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest); + break; + + default: + assert(false); + } + } + else if (src->is_stacked && !dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "lfs %H, %S(fp) ! %H", dest, src, src); + break; + + default: + assert(false); + } + } + else if (!src->is_stacked && !dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "mr %H, %H", dest, src); + break; + + case burm_float_ATTR: + case burm_double_ATTR: + hop_add_insel(hop, "fmr %H, %H", dest, src); + break; + + default: + assert(false); + } + } + else + assert(false); + } return hop; } diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 3a1da6fd6..236f5c7c1 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -7,71 +7,122 @@ REGISTERS * a register into another register (e.g. for eviction). */ - r12 "r12" bytes4! int! volatile; - r11 "r11" bytes4! int! volatile; - r10 "r10" bytes4! int! volatile; - r9 "r9" bytes4! int! volatile; - r8 "r8" bytes4! int! volatile; - r7 "r7" bytes4! int! volatile; - r6 "r6" bytes4! int! volatile; - r5 "r5" bytes4! int! volatile; - r4 "r4" bytes4! int! volatile; - r3 "r3" bytes4! int! volatile ret; + r12 bytes4! int! volatile; + r11 bytes4! int! volatile; + r10 bytes4! int! volatile; + r9 bytes4! int! volatile; + r8 bytes4! int! volatile; + r7 bytes4! int! volatile; + r6 bytes4! int! volatile; + r5 bytes4! int! volatile; + r4 bytes4! int! volatile; + r3 bytes4! int! volatile ret; - r31 "r31" bytes4! int!; - r30 "r30" bytes4! int!; - r29 "r29" bytes4! int!; - r28 "r28" bytes4! int!; - r27 "r27" bytes4! int!; - r26 "r26" bytes4! int!; - r25 "r25" bytes4! int!; - r24 "r24" bytes4! int!; - r23 "r23" bytes4! int!; - r22 "r22" bytes4! int!; - r21 "r21" bytes4! int!; - r20 "r20" bytes4! int!; - r19 "r19" bytes4! int!; - r18 "r18" bytes4! int!; - r17 "r17" bytes4! int!; - r16 "r16" bytes4! int!; - r15 "r15" bytes4! int!; - r14 "r14" bytes4! int!; + r31 bytes4! int!; + r30 bytes4! int!; + r29 bytes4! int!; + r28 bytes4! int!; + r27 bytes4! int!; + r26 bytes4! int!; + r25 bytes4! int!; + r24 bytes4! int!; + r23 bytes4! int!; + r22 bytes4! int!; + r21 bytes4! int!; + r20 bytes4! int!; + r19 bytes4! int!; + r18 bytes4! int!; + r17 bytes4! int!; + r16 bytes4! int!; + r15 bytes4! int!; + r14 bytes4! int!; + r13 bytes4! int!; - f14 "f14" bytes4! float! volatile; - f13 "f13" bytes4! float! volatile; - f12 "f12" bytes4! float! volatile; - f11 "f11" bytes4! float! volatile; - f10 "f10" bytes4! float! volatile; - f9 "f9" bytes4! float! volatile; - f8 "f8" bytes4! float! volatile; - f7 "f7" bytes4! float! volatile; - f6 "f6" bytes4! float! volatile; - f5 "f5" bytes4! float! volatile; - f4 "f4" bytes4! float! volatile; - f3 "f3" bytes4! float! volatile fret; - f2 "f2" bytes4! float! volatile; - f1 "f1" bytes4! float! volatile; - f0 "f0" bytes4! float! volatile; + r11r12 named("r11", "r12") aliases(r11, r12) bytes8! pair! volatile; + r9r10 named("r9", "r10") aliases(r9, r10) bytes8! pair! volatile; + r7r8 named("r7", "r8") aliases(r7, r8) bytes8! pair! volatile; + r5r6 named("r5", "r6") aliases(r6, r6) bytes8! pair! volatile; + r3r4 named("r3", "r4") aliases(r3, r4) bytes8! pair! volatile pret; - f31 "f31" bytes4! float!; - f30 "f30" bytes4! float!; - f29 "f29" bytes4! float!; - f28 "f28" bytes4! float!; - f27 "f27" bytes4! float!; - f26 "f26" bytes4! float!; - f25 "f25" bytes4! float!; - f24 "f24" bytes4! float!; - f23 "f23" bytes4! float!; - f22 "f22" bytes4! float!; - f21 "f21" bytes4! float!; - f20 "f20" bytes4! float!; - f19 "f19" bytes4! float!; - f18 "f18" bytes4! float!; - f17 "f17" bytes4! float!; - f16 "f16" bytes4! float!; - f15 "f15" bytes4! float!; - - cr0 "cr0" cr!; + r29r30 named("r29", "r30") aliases(r29, r30) bytes8! pair!; + r27r28 named("r27", "r28") aliases(r27, r28) bytes8! pair!; + r25r26 named("r25", "r26") aliases(r25, r26) bytes8! pair!; + r23r24 named("r23", "r24") aliases(r23, r24) bytes8! pair!; + r21r22 named("r21", "r22") aliases(r21, r22) bytes8! pair!; + r19r20 named("r19", "r20") aliases(r19, r20) bytes8! pair!; + r17r18 named("r17", "r18") aliases(r17, r18) bytes8! pair!; + r15r16 named("r15", "r16") aliases(r15, r16) bytes8! pair!; + r13r14 named("r13", "r14") aliases(r13, r14) bytes8! pair!; + + f14 bytes4! float! volatile; + f13 bytes4! float! volatile; + f12 bytes4! float! volatile; + f11 bytes4! float! volatile; + f10 bytes4! float! volatile; + f9 bytes4! float! volatile; + f8 bytes4! float! volatile; + f7 bytes4! float! volatile; + f6 bytes4! float! volatile; + f5 bytes4! float! volatile; + f4 bytes4! float! volatile; + f3 bytes4! float! volatile fret; + f2 bytes4! float! volatile; + f1 bytes4! float! volatile; + f0 bytes4! float! volatile; + + f31 bytes4! float!; + f30 bytes4! float!; + f29 bytes4! float!; + f28 bytes4! float!; + f27 bytes4! float!; + f26 bytes4! float!; + f25 bytes4! float!; + f24 bytes4! float!; + f23 bytes4! float!; + f22 bytes4! float!; + f21 bytes4! float!; + f20 bytes4! float!; + f19 bytes4! float!; + f18 bytes4! float!; + f17 bytes4! float!; + f16 bytes4! float!; + f15 bytes4! float!; + + d14 named("f14") aliases(f14) bytes8! double! volatile; + d13 named("f13") aliases(f13) bytes8! double! volatile; + d12 named("f12") aliases(f12) bytes8! double! volatile; + d11 named("f11") aliases(f11) bytes8! double! volatile; + d10 named("f10") aliases(f10) bytes8! double! volatile; + d9 named("f9") aliases(f9) bytes8! double! volatile; + d8 named("f8") aliases(f8) bytes8! double! volatile; + d7 named("f7") aliases(f7) bytes8! double! volatile; + d6 named("f6") aliases(f6) bytes8! double! volatile; + d5 named("f5") aliases(f5) bytes8! double! volatile; + d4 named("f4") aliases(f4) bytes8! double! volatile; + d3 named("f3") aliases(f3) bytes8! double! volatile dret; + d2 named("f2") aliases(f2) bytes8! double! volatile; + d1 named("f1") aliases(f1) bytes8! double! volatile; + d0 named("f0") aliases(f0) bytes8! double! volatile; + + d31 named("f31") aliases(f31) bytes8! double!; + d30 named("f30") aliases(f30) bytes8! double!; + d29 named("f29") aliases(f29) bytes8! double!; + d28 named("f28") aliases(f28) bytes8! double!; + d27 named("f27") aliases(f27) bytes8! double!; + d26 named("f26") aliases(f26) bytes8! double!; + d25 named("f25") aliases(f25) bytes8! double!; + d24 named("f24") aliases(f24) bytes8! double!; + d23 named("f23") aliases(f23) bytes8! double!; + d22 named("f22") aliases(f22) bytes8! double!; + d21 named("f21") aliases(f21) bytes8! double!; + d20 named("f20") aliases(f20) bytes8! double!; + d19 named("f19") aliases(f19) bytes8! double!; + d18 named("f18") aliases(f18) bytes8! double!; + d17 named("f17") aliases(f17) bytes8! double!; + d16 named("f16") aliases(f16) bytes8! double!; + d15 named("f15") aliases(f15) bytes8! double!; + + cr0 cr!; @@ -101,6 +152,11 @@ PATTERNS emit "stwu %in, -4(sp)" cost 4; + PUSH8(in:(pair)reg) + emit "stwu %in.0, -4(sp)" + emit "stwu %in.1, -4(sp)" + cost 8; + out:(int)reg = POP4 emit "lwz %out, 0(sp)" emit "addi sp, sp, 4" @@ -113,12 +169,20 @@ PATTERNS SETRET4(in:(ret)reg) emit "! setret4" - cost 4; + cost 1; + + SETRET8(in:(pret)reg) + emit "! setret8" + cost 1; (ret)reg = GETRET4 emit "! getret4" cost 1; + (pret)reg = GETRET8 + emit "! getret8" + cost 1; + STACKADJUST4(delta:CONST4) when signed_constant(%delta, 16) emit "addi sp, sp, $delta" @@ -142,6 +206,11 @@ PATTERNS /* Stores */ + STORE8(addr:address, value:(pair)reg) + emit "stw %value.0, 4+%addr" + emit "stw %value.1, 0+%addr" + cost 4; + STORE4(addr:address, value:(int)reg) emit "stw %value, %addr" cost 4; @@ -168,6 +237,11 @@ PATTERNS emit "lwz %out, %addr" cost 4; + out:(pair)reg = LOAD8(addr:address) + emit "lwz %out.0, 4+%addr" + emit "lwz %out.1, 0+%addr" + cost 8; + out:(int)ushort0 = LOAD2(addr:address) emit "lhz %out, %addr" cost 4; @@ -480,6 +554,10 @@ PATTERNS emit "lfs %out, %addr" cost 4; + out:(double)reg = LOADF8(addr:address) + emit "lfd %out, %addr" + cost 4; + out:(float)reg = value:CONSTF4 emit "lfs %out, address-containing-$value" cost 8; @@ -488,6 +566,10 @@ PATTERNS emit "fadds %out, %left, %right" cost 4; + out:(double)reg = ADDF8(left:(double)reg, right:(double)reg) + emit "fadd %out, %left, %right" + cost 4; + out:(float)reg = SUBF4(left:(float)reg, right:(float)reg) emit "fsubs %out, %left, %right" cost 4; diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 7bdb232ff..9dbb010cc 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -31,17 +31,19 @@ void hop_add_string_insel(struct hop* hop, const char* string) array_append(&hop->insels, insel); } -void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg) +void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index) { struct insel* insel = new_insel(INSEL_HREG); insel->u.hreg = hreg; + insel->index = index; array_append(&hop->insels, insel); } -void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg) +void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index) { struct insel* insel = new_insel(INSEL_VREG); insel->u.vreg = vreg; + insel->index = index; array_append(&hop->insels, insel); } @@ -108,11 +110,11 @@ void hop_add_insel(struct hop* hop, const char* fmt, ...) break; case 'H': - hop_add_hreg_insel(hop, va_arg(ap, struct hreg*)); + hop_add_hreg_insel(hop, va_arg(ap, struct hreg*), 0); break; case 'V': - hop_add_vreg_insel(hop, va_arg(ap, struct vreg*)); + hop_add_vreg_insel(hop, va_arg(ap, struct vreg*), 0); break; } } @@ -205,7 +207,7 @@ char* hop_render(struct hop* hop) case INSEL_HREG: { struct hreg* hreg = insel->u.hreg; - appendf("%s", hreg->realname); + appendf("%s", hreg->brd->names[insel->index]); break; } @@ -216,7 +218,7 @@ char* hop_render(struct hop* hop) if (!hreg) hreg = pmap_findright(&hop->regsout, vreg); if (hreg) - appendf("%s", hreg->realname); + appendf("%s", hreg->brd->names[insel->index]); else appendf("%%%d", vreg->id); break; diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index e1f2f6d92..0cc5dc0b1 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -16,6 +16,7 @@ enum insel_type struct insel { enum insel_type type; + int index; union { const char* string; @@ -54,8 +55,8 @@ struct hop extern struct hop* new_hop(struct basicblock* bb, struct ir* ir); extern void hop_add_string_insel(struct hop* hop, const char* string); -extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg); -extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); +extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index); +extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index); extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg); extern void hop_add_ab_offset_insel(struct hop* hop, int offset); diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index fcfb55182..863ed56e9 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -32,9 +32,9 @@ void burm_panic_cannot_match(struct burm_node* node) exit(1); } -static void emit_return_reg(void) +static void emit_return_reg(int index) { - hop_add_vreg_insel(current_hop, current_hop->output); + hop_add_vreg_insel(current_hop, current_hop->output, index); } static struct vreg* find_vreg_of_child(int child) @@ -47,13 +47,13 @@ static struct vreg* find_vreg_of_child(int child) return insn->ir->result; } -static void emit_reg(int child) +static void emit_reg(int child, int index) { struct vreg* vreg = find_vreg_of_child(child); if (vreg) { - hop_add_vreg_insel(current_hop, vreg); + hop_add_vreg_insel(current_hop, vreg, index); array_appendu(&vreg->used, current_hop); } } @@ -109,7 +109,7 @@ static uint32_t find_type_from_constraint(uint32_t attr) * this. */ const struct burm_register_data* brd = burm_register_data; - while (brd->name) + while (brd->id) { if (brd->attrs & attr) return brd->type; diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c index 87db1e47d..2708c7fda 100644 --- a/mach/proto/mcg/pass_promotefloatops.c +++ b/mach/proto/mcg/pass_promotefloatops.c @@ -48,7 +48,7 @@ static void promote(struct ir* ir) { int i; for (i=0; iu.phivalue.count; i++) - array_appendu(&promotable, ir->u.phivalue.item[i].right); + promote(ir->u.phivalue.item[i].right); break; } } diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 93a9b1dad..5d9e702fc 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -20,14 +20,30 @@ static bool type_match(struct hreg* hreg, struct vreg* vreg); static void populate_hregs(void) { + int i; const struct burm_register_data* brd = burm_register_data; hregs.count = 0; - while (brd->name) + while (brd->id) { array_append(&hregs, new_hreg(brd)); brd++; } + + /* Wire up the register aliases. */ + + for (i=0; ibrd->aliases; + + while (*alias) + { + int index = *alias - burm_register_data; + array_append(&hreg->aliases, hregs.item[index]); + alias++; + } + } } static void wire_up_blocks_ins_outs(void) @@ -43,6 +59,20 @@ static void wire_up_blocks_ins_outs(void) } } +static bool register_used(register_assignment_t* regs, struct hreg* hreg) +{ + int i; + + for (i=0; ialiases.count; i++) + { + struct hreg* alias = hreg->aliases.item[i]; + if (pmap_findleft(regs, alias)) + return true; + } + + return false; +} + static struct hreg* allocate_phi_hreg(register_assignment_t* regs, struct vreg* vreg, uint32_t type) { @@ -54,7 +84,7 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs, for (i=0; itype == type)) + if (!register_used(regs, hreg) && (hreg->type == type)) { /* This one is unused. Use it. */ return hreg; @@ -86,7 +116,10 @@ static struct hreg* evict(struct vreg* vreg) if (evictable(hreg, vreg)) { - if (!candidatein && !candidateout) + if (!candidatein && + !candidateout && + !register_used(current_ins, hreg) && + !register_used(current_outs, hreg)) { /* This hreg is unused, so we don't need to evict anything. * Shouldn't really happen in real life. */ @@ -95,7 +128,7 @@ static struct hreg* evict(struct vreg* vreg) if (candidatein == candidateout) { /* This is a through register. */ - tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->name); + tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->id); pmap_put(&evicted, candidatein, hreg); pmap_remove(current_ins, hreg, candidatein); pmap_remove(current_outs, hreg, candidatein); @@ -120,13 +153,13 @@ static bool type_match(struct hreg* hreg, struct vreg* vreg) static bool allocatable_stackable_input(struct hreg* hreg, struct vreg* vreg) { - return !pmap_findleft(current_ins, hreg) && + return !register_used(current_ins, hreg) && type_match(hreg, vreg); } static bool allocatable_stackable_output(struct hreg* hreg, struct vreg* vreg) { - return !pmap_findleft(current_outs, hreg) && + return !register_used(current_outs, hreg) && type_match(hreg, vreg) && !(hreg->attrs & current_hop->insndata->corrupts); } @@ -295,7 +328,7 @@ static void add_output_register(struct vreg* vreg) pmap_add(current_outs, hreg, vreg); tracef('R', "R: output equality constraint requires extra move of %%%d => %s\n", - c->equals_to->id, hreg->name); + c->equals_to->id, hreg->id); pmap_add(current_ins, hreg, c->equals_to); } else @@ -332,7 +365,7 @@ static void add_through_register(struct vreg* vreg, struct hreg* hreg) /* Nope, can't honour the hint. Mark the register as evicted; we'll * put it in something later (probably a stack slot). */ - tracef('R', "R: cannot place %%%d in %s, evicting\n", vreg->id, hreg->name); + tracef('R', "R: cannot place %%%d in %s, evicting\n", vreg->id, hreg->id); pmap_put(&evicted, vreg, hreg); pmap_remove(current_ins, hreg, vreg); pmap_remove(current_outs, hreg, vreg); @@ -372,7 +405,7 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s array_append(&hregs, hreg); found: - tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->name); + tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->id); pmap_add(current_ins, hreg, vreg); pmap_add(current_outs, hreg, vreg); } @@ -452,7 +485,7 @@ static void assign_hregs_to_vregs(void) if (hreg) { tracef('R', "R: import hreg %s for input %%%d from %s\n", - hreg->name, vreg->id, prevbb->name); + hreg->id, vreg->id, prevbb->name); assert(!pmap_findleft(old, hreg)); pmap_put(old, hreg, vreg); goto nextvreg; @@ -482,7 +515,7 @@ static void assign_hregs_to_vregs(void) if (hreg && !pmap_findleft(old, hreg)) { tracef('R', "R: import hreg %s for phi input %%%d from %s\n", - hreg->name, vreg->id, phi->prev->name); + hreg->id, vreg->id, phi->prev->name); pmap_put(old, hreg, vreg); } } @@ -503,7 +536,7 @@ static void assign_hregs_to_vregs(void) struct hreg* hreg = allocate_phi_hreg(old, vreg, c->type); tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n", - hreg->name, vreg->id, phi->prev->name); + hreg->id, vreg->id, phi->prev->name); pmap_add(old, hreg, vreg); } } @@ -525,7 +558,7 @@ static void assign_hregs_to_vregs(void) struct vreg* vreg = hop->regsin.item[k].right; if (k != 0) tracef('R', " "); - tracef('R', "%%%d=>%s", vreg->id, hreg->name); + tracef('R', "%%%d=>%s", vreg->id, hreg->id); } tracef('R', "] ["); for (k=0; kregsout.count; k++) @@ -534,7 +567,7 @@ static void assign_hregs_to_vregs(void) struct vreg* vreg = hop->regsout.item[k].right; if (k != 0) tracef('R', " "); - tracef('R', "%%%d=>%s", vreg->id, hreg->name); + tracef('R', "%%%d=>%s", vreg->id, hreg->id); } tracef('R', "]\n"); @@ -551,9 +584,9 @@ static struct hop* create_swap(struct basicblock* bb, struct hreg* src, struct h struct hop* hop = new_hop(bb, NULL); hop_add_string_insel(hop, "! swap "); - hop_add_hreg_insel(hop, src); + hop_add_hreg_insel(hop, src, 0); hop_add_string_insel(hop, " <-> "); - hop_add_hreg_insel(hop, dest); + hop_add_hreg_insel(hop, dest, 0); hop_add_eoi_insel(hop); return hop; @@ -661,7 +694,7 @@ static void insert_phi_copies(void) tracef('R', "R: map %%%d -> %%%d (%s)\n", phi->ir->result->id, - vreg->id, dest->name); + vreg->id, dest->id); pmap_put(&destregs, dest, phi->ir->result); } diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c index 25ec0b607..8af8079e2 100644 --- a/mach/proto/mcg/reg.c +++ b/mach/proto/mcg/reg.c @@ -12,11 +12,12 @@ struct vreg* new_vreg(void) struct hreg* new_hreg(const struct burm_register_data* brd) { struct hreg* hreg = calloc(1, sizeof *hreg); - hreg->name = brd->name; - hreg->realname = brd->realname; + hreg->id = brd->id; + hreg->brd = brd; hreg->type = brd->type; hreg->attrs = brd->attrs; hreg->is_stacked = false; + /* The aliases array needs to be initialised later. */ return hreg; } @@ -24,12 +25,12 @@ struct hreg* new_stacked_hreg(uint32_t type) { static int hreg_count = 1; struct hreg* hreg = calloc(1, sizeof *hreg); - hreg->name = aprintf("stacked_%d_id_%d", type, hreg_count++); - hreg->realname = hreg->name; + hreg->id = aprintf("stacked_%d_id_%d", type, hreg_count++); hreg->type = type; hreg->attrs = type; hreg->is_stacked = true; hreg->offset = -1; + array_append(&hreg->aliases, hreg); return hreg; } diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index e71864f3a..f449b7e19 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -13,12 +13,13 @@ struct phicongruence struct hreg { - const char* name; - const char* realname; + const char* id; + const struct burm_register_data* brd; uint32_t type; uint32_t attrs; bool is_stacked; int offset; + ARRAYOF(struct hreg) aliases; }; struct vreg diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 8684f1fd5..7b9ba842c 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -495,6 +495,16 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_sdl: + appendir( + new_ir2( + IR_STORE, EM_wordsize*2, + new_localir(value), + pop(EM_wordsize*2) + ) + ); + break; + case op_lal: push( new_localir(value) @@ -972,6 +982,15 @@ static void insn_lvalue(int opcode, const char* label, arith offset) ); break; + case op_lde: + push( + new_ir1( + IR_LOAD, EM_wordsize*2, + address_of_external(label, offset) + ) + ); + break; + case op_ste: appendir( new_ir2( @@ -982,6 +1001,16 @@ static void insn_lvalue(int opcode, const char* label, arith offset) ); break; + case op_sde: + appendir( + new_ir2( + IR_STORE, EM_wordsize*2, + address_of_external(label, offset), + pop(EM_wordsize*2) + ) + ); + break; + case op_zre: appendir( new_ir2( diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index e6b1c2fd0..4844da073 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -33,6 +33,7 @@ extern int yylex(void); %term EMIT %term EQUALS %term FRAGMENT +%term NAMED %term NOTEQUALS %term PATTERNS %term PREFERS @@ -44,7 +45,6 @@ extern int yylex(void); %token ID %token QFRAGMENT -%type aliases; %type constraint %type constraints %type predicate @@ -55,6 +55,8 @@ extern int yylex(void); %type pattern %type pattern_constraints %type pattern_emit +%type aliases; +%type names; %type qfragments %type terminfo %type rhs @@ -73,12 +75,18 @@ registers ; register - : ID QFRAGMENT { $$ = makereg($1, $2); } + : ID { $$ = makereg($1); } + | register NAMED '(' names ')' { $$ = $1; setregnames($$, $4); } | register ALIASES '(' aliases ')' { $$ = $1; addregaliases($$, $4); } | register ID { $$ = $1; addregattr($1, $2, false); } | register ID '!' { $$ = $1; addregattr($1, $2, true); } ; +names + : QFRAGMENT { $$ = calloc(1, sizeof(*$$)); stringlist_add($$, $1); } + | names ',' QFRAGMENT { $$ = $1; stringlist_add($$, $3); } + ; + aliases : ID { $$ = calloc(1, sizeof(*$$)); stringlist_add($$, $1); } | aliases ',' ID { $$ = $1; stringlist_add($$, $3); } diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index cf7950b26..146f920c3 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -268,7 +268,7 @@ static void* install(const char* name) return &p->sym; } -struct reg* makereg(const char* id, const char* realname) +struct reg* makereg(const char* id) { struct reg* p = smap_get(®isters, id); static int number = 0; @@ -277,7 +277,6 @@ struct reg* makereg(const char* id, const char* realname) yyerror("redefinition of '%s'", id); p = calloc(1, sizeof(*p)); p->name = id; - p->realname = realname; p->number = number++; array_append(&p->aliases, p); smap_put(®isters, id, p); @@ -285,6 +284,14 @@ struct reg* makereg(const char* id, const char* realname) return p; } +void setregnames(struct reg* reg, struct stringlist* names) +{ + if (reg->names) + yyerror("you can only set one set of register names"); + + reg->names = names; +} + struct regattr* makeregattr(const char* id) { struct regattr* p = smap_get(®isterattrs, id); @@ -629,14 +636,33 @@ static void emitregisters(void) print("NULL\n};\n"); } + for (i=0; iname); + if (r->names) + { + struct stringfragment* f = r->names->first; + while (f) + { + print("\"%s\", ", f->data); + f = f->next; + } + } + else + print("\"%s\", ", r->name); + print("NULL\n};\n"); + } + print("const struct %Pregister_data %Pregister_data[] = {\n"); for (i=0; inumber == i); - print("%1{ \"%s\", \"%s\", 0x%x, 0x%x, %Pregister_aliases_%d_%s },\n", - r->name, r->realname, r->type, r->attrs, i, r->name); + print("%1{ \"%s\", 0x%x, 0x%x, %Pregister_names_%d_%s, %Pregister_aliases_%d_%s },\n", + r->name, r->type, r->attrs, i, r->name, i, r->name); } print("%1{ NULL }\n"); print("};\n\n"); @@ -1215,14 +1241,18 @@ static void emitinsndata(Rule rules) while (f) { - switch (f->data[0]) + char* data = strdup(f->data); + int type = *data++; + char* label = strtok(data, "."); + char* nameindex_s = strtok(NULL, "."); + int nameindex = nameindex_s ? atoi(nameindex_s) : 0; + + switch (type) { case '%': { - const char* label = f->data + 1; - if (r->label && (strcmp(label, r->label) == 0)) - print("%1data->emit_return_reg();\n", label); + print("%1data->emit_return_reg(%d);\n", nameindex); else { Tree node; @@ -1234,25 +1264,25 @@ static void emitinsndata(Rule rules) if (nt->kind == NONTERM) { if (nt->is_fragment) - print("%1data->emit_fragment("); + print("%1data->emit_fragment(%d);\n", index); else - print("%1data->emit_reg("); + print("%1data->emit_reg(%d, %d);\n", index, nameindex); } else - print("%1data->emit_reg("); - - print("%d);\n", index); + print("%1data->emit_reg(%d, %d);\n", index, nameindex); } break; } case '$': { - const char* label = f->data + 1; int index = 0; if (!find_child_index(r->pattern, label, &index, NULL)) label_not_found(r, label); + if (nameindex != 0) + yyerror("indices other than 0 make no sense for $-values"); + print("%1data->emit_value(%d);\n", index); break; } diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index f50e4c9da..e0bbeef57 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -59,10 +59,10 @@ struct terminfo struct reg { const char* name; /* friendly register name */ - const char* realname; /* name used in assembly output */ int number; /* identifying number */ uint32_t attrs; /* bitfield of register attributes */ uint32_t type; /* register type */ + struct stringlist* names; /* register names */ ARRAYOF(struct reg) aliases; /* registers that this one aliases */ }; @@ -72,7 +72,8 @@ struct regattr int number; /* identifying number */ }; -extern struct reg* makereg(const char* name, const char* realname); +extern struct reg* makereg(const char* name); +extern void setregnames(struct reg* reg, struct stringlist* names); extern void addregattr(struct reg* reg, const char* regattr, bool exact); extern void addregaliases(struct reg* reg, struct stringlist* aliases); extern struct regattr* getregattr(const char* name); diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 6f40ae3c0..576587247 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -23,6 +23,7 @@ S POPF S LOAD # must be followed by float form S LOADF S STORE +S STOREF # Arithemetic operations S ADD diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 211aaf1cc..da0c8b1a1 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -40,8 +40,8 @@ struct burm_emitter_data { void (*emit_string)(const char* data); void (*emit_fragment)(int child); - void (*emit_return_reg)(void); - void (*emit_reg)(int child); + void (*emit_return_reg)(int index); + void (*emit_reg)(int child, int index); void (*emit_value)(int child); void (*emit_eoi)(void); void (*constrain_input_reg)(int child, uint32_t attr); @@ -63,10 +63,10 @@ extern const struct burm_instruction_data burm_instruction_data[]; struct burm_register_data { - const char* name; - const char* realname; + const char* id; uint32_t type; uint32_t attrs; + const char** names; const struct burm_register_data** aliases; }; diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 44a582456..272dd2bf1 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -21,7 +21,7 @@ static int braces = 0; "\"" BEGIN(QSTRING); "\"" BEGIN(INITIAL); -[%$][a-zA-Z_][a-zA_Z_0-9]+ { +[%$][a-zA-Z_][a-zA_Z_0-9]+(\.[0-9]+)? { yylval.string = strdup(yytext); return QFRAGMENT; } @@ -44,6 +44,7 @@ static int braces = 0; "cost" return COST; "emit" return EMIT; "fragment" return FRAGMENT; +"named" return NAMED; "prefers" return PREFERS; "when" return WHEN; "with" return WITH; From d535be87b1014d1a444b7c08f2a44b2d98aa2454 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 22 Oct 2016 00:02:15 +0200 Subject: [PATCH 132/230] fef4 and fef8 is now cleaner, albeit slower; add some more register alias stuff. --- mach/powerpc/mcg/platform.c | 5 +++++ mach/powerpc/mcg/table | 6 ++++++ mach/proto/mcg/hop.c | 22 ++++++++++++++++--- mach/proto/mcg/treebuilder.c | 41 ++++++++++-------------------------- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index e3ab26913..e0a7c1a2c 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -202,6 +202,11 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "mr %H, %H", dest, src); break; + case burm_pair_ATTR: + hop_add_insel(hop, "mr %0H, %0H", dest, src); + hop_add_insel(hop, "mr %1H, %1H", dest, src); + break; + case burm_float_ATTR: case burm_double_ATTR: hop_add_insel(hop, "fmr %H, %H", dest, src); diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 236f5c7c1..f1bc27a47 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -162,6 +162,12 @@ PATTERNS emit "addi sp, sp, 4" cost 8; + out:(pair)reg = POP8 + emit "lwz %out.0, 4(sp)" + emit "lwz %out.1, 0(sp)" + emit "addi sp, sp, 8" + cost 12; + out:(float)reg = POPF4 emit "lfs %out, 0(sp)" emit "addi sp, sp, 4" diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 9dbb010cc..32bd44d3b 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -90,9 +90,25 @@ void hop_add_insel(struct hop* hop, const char* fmt, ...) { if (*fmt == '%') { + int index = 0; fmt += 2; + again: switch (fmt[-1]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + index = fmt[-1] - '0'; + fmt++; + goto again; + case 'd': hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int))); break; @@ -110,11 +126,11 @@ void hop_add_insel(struct hop* hop, const char* fmt, ...) break; case 'H': - hop_add_hreg_insel(hop, va_arg(ap, struct hreg*), 0); + hop_add_hreg_insel(hop, va_arg(ap, struct hreg*), index); break; case 'V': - hop_add_vreg_insel(hop, va_arg(ap, struct vreg*), 0); + hop_add_vreg_insel(hop, va_arg(ap, struct vreg*), index); break; } } @@ -220,7 +236,7 @@ char* hop_render(struct hop* hop) if (hreg) appendf("%s", hreg->brd->names[insel->index]); else - appendf("%%%d", vreg->id); + appendf("%%%d.%d", vreg->id, insel->index); break; } diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 7b9ba842c..180f41000 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -516,7 +516,7 @@ static void insn_ivalue(int opcode, arith value) new_ir1( IR_LOAD, EM_wordsize, new_ir1( - IR_LOAD, EM_wordsize, + IR_LOAD, EM_pointersize, new_localir(value) ) ) @@ -528,7 +528,7 @@ static void insn_ivalue(int opcode, arith value) new_ir2( IR_STORE, EM_wordsize, new_ir1( - IR_LOAD, EM_wordsize, + IR_LOAD, EM_pointersize, new_localir(value) ), pop(EM_wordsize) @@ -912,41 +912,22 @@ static void insn_ivalue(int opcode, arith value) { struct ir* e; struct ir* f = pop(value); - /* fef is implemented by synthesising a call to frexp. */ - push( - new_labelir(".fef_exp") - ); - push( - f - ); + /* fef is implemented by calling a helper function which then mutates + * the stack. We read the return values off the stack when retracting + * the stack pointer. */ + + push(f); + push(new_wordir(0)); + materialise_stack(); appendir( new_ir1( IR_CALL, 0, - new_labelir((value == 4) ? "frexpf" : "frexp") + new_labelir((value == 4) ? ".fef4" : ".fef8") ) ); - appendir( - new_ir1( - IR_STACKADJUST, EM_wordsize, - new_wordir(4 + value) - ) - ); - e = appendir( - new_ir0( - IR_GETRET, value - ) - ); - push( - new_ir1( - IR_LOAD, EM_wordsize, - new_labelir(".fef_exp") - ) - ); - push( - e - ); + /* exit, leaving an int and then a float (or double) on the stack. */ break; } From f851ab83afa650b476f8a4f9819b60c1aa22a4a3 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 22 Oct 2016 00:48:26 +0200 Subject: [PATCH 133/230] Better (and more correct) floating point conversions; fif; various new opcodes. --- mach/powerpc/mcg/platform.c | 18 +++++++ mach/powerpc/mcg/table | 65 ++++++++++++++++--------- mach/proto/mcg/hop.c | 5 +- mach/proto/mcg/pass_promotefloatops.c | 8 ++++ mach/proto/mcg/treebuilder.c | 69 ++++++++++++++++++++++----- util/mcgg/ir.dat | 22 +++++++-- 6 files changed, 148 insertions(+), 39 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index e0a7c1a2c..2b22ec1f3 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -112,6 +112,11 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "stwu %H, -4(sp)", src); break; + case burm_pair_ATTR: + hop_add_insel(hop, "stwu %0H, -4(sp)", src); + hop_add_insel(hop, "stwu %1H, -4(sp)", src); + break; + case burm_float_ATTR: hop_add_insel(hop, "stfsu %H, -4(sp)", src); break; @@ -130,6 +135,11 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "lwz %H, 0(sp)", dest); break; + case burm_pair_ATTR: + hop_add_insel(hop, "lwz %0H, 4(sp)", dest); + hop_add_insel(hop, "lwz %1H, 0(sp)", dest); + break; + case burm_float_ATTR: hop_add_insel(hop, "lfs %H, 0(sp)", dest); break; @@ -174,6 +184,10 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest); break; + case burm_double_ATTR: + hop_add_insel(hop, "stfd %H, %S(fp) ! %H", src, dest, dest); + break; + default: assert(false); } @@ -190,6 +204,10 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "lfs %H, %S(fp) ! %H", dest, src, src); break; + case burm_double_ATTR: + hop_add_insel(hop, "lfd %H, %S(fp) ! %H", dest, src, src); + break; + default: assert(false); } diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index f1bc27a47..632a47ef8 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -408,38 +408,28 @@ PATTERNS /* Comparisons */ - cr:(cr)cr = COMPARES4(left:(int)reg, right:(int)reg) + cr:(cr)cr = COMPARES44(left:(int)reg, right:(int)reg) emit "cmp %cr, 0, %left, %right" cost 4; - cr:(cr)cr = COMPARES4(left:(int)reg, right:CONST4) + cr:(cr)cr = COMPARES44(left:(int)reg, right:CONST4) when signed_constant(%right, 16) emit "cmpi %cr, 0, %left, $right" cost 4; - cr:(cr)cr = COMPAREU4(left:(int)reg, right:(int)reg) + cr:(cr)cr = COMPAREU44(left:(int)reg, right:(int)reg) emit "cmpl %cr, 0, %left, %right" cost 4; - cr:(cr)cr = COMPAREU4(left:(int)reg, right:CONST4) + cr:(cr)cr = COMPAREU44(left:(int)reg, right:CONST4) when signed_constant(%right, 16) emit "cmpli %cr, 0, %left, $right" cost 4; - cr:(cr)cr = COMPARES4(COMPARES4(left:(int)reg, right:(int)reg), result:CONST4) + out:(cr)cr = COMPARES44(in:(cr)cr, result:CONST4) when specific_constant(%result, 0) - emit "cmp %cr, 0, %left, %right" - cost 4; - - cr:(cr)cr = COMPARES4(COMPARES4(left:(int)reg, right:CONST4), result:CONST4) - when specific_constant(%result, 0) - when signed_constant(%right, 16) - emit "cmpi %cr, 0, %left, $right" - cost 4; - - cr:(cr)cr = COMPARES4(COMPAREU4(left:(int)reg, right:(int)reg), result:CONST4) - when specific_constant(%result, 0) - emit "cmpl %cr, 0, %left, %right" + with %out == %in + emit "! COMPARES(cr, 0)" cost 4; @@ -580,32 +570,61 @@ PATTERNS emit "fsubs %out, %left, %right" cost 4; + out:(double)reg = SUBF8(left:(double)reg, right:(double)reg) + emit "fsub %out, %left, %right" + cost 4; + out:(float)reg = MULF4(left:(float)reg, right:(float)reg) emit "fmuls %out, %left, %right" cost 4; + out:(double)reg = MULF8(left:(double)reg, right:(double)reg) + emit "fmul %out, %left, %right" + cost 4; + out:(float)reg = NEGF4(left:(float)reg) emit "fneg %out, %left" cost 4; - cr:(cr)cr = COMPAREF4(left:(float)reg, right:(float)reg) + out:(double)reg = NEGF8(left:(double)reg) + emit "fneg %out, %left" + cost 4; + + cr:(cr)cr = COMPAREF44(left:(float)reg, right:(float)reg) emit "fcmpu %cr, %left, %right" cost 4; - cr:(cr)cr = COMPARES4(COMPAREF4(left:(float)reg, right:(float)reg), result:CONST4) - when specific_constant(%result, 0) + cr:(cr)cr = COMPAREF84(left:(double)reg, right:(double)reg) emit "fcmpu %cr, %left, %right" - cost 4; + cost 4; out:(ret)reg = CFI44(val:(fret)reg) with corrupted(volatile) - emit "bl .cfi4" + emit "bl .cfi44" cost 4; out:(fret)reg = CIF44(val:(ret)reg) with corrupted(volatile) - emit "bl .cif4" + emit "bl .cif44" cost 4; + out:(ret)reg = CFI84(val:(dret)reg) + with corrupted(volatile) + emit "bl .cfi84" + cost 4; + + out:(dret)reg = CIF48(val:(ret)reg) + with corrupted(volatile) + emit "bl .cif48" + cost 4; + + out:(float)reg = CFF84(val:(double)reg) + emit "frsp %out, %val" + cost 4; + + out:(double)reg = CFF48(val:(float)reg) + emit "fmr %out, %val" + cost 1; + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 32bd44d3b..02f6b2930 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -223,7 +223,10 @@ char* hop_render(struct hop* hop) case INSEL_HREG: { struct hreg* hreg = insel->u.hreg; - appendf("%s", hreg->brd->names[insel->index]); + if (hreg->brd) + appendf("%s", hreg->brd->names[insel->index]); + else + appendf("%s.%d", hreg->id, insel->index); break; } diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c index 2708c7fda..7e5f87c19 100644 --- a/mach/proto/mcg/pass_promotefloatops.c +++ b/mach/proto/mcg/pass_promotefloatops.c @@ -69,6 +69,14 @@ static void search_for_promotable_irs(void) case IR_MULF: case IR_DIVF: case IR_NEGF: + case IR_COMPAREF1: + case IR_COMPAREF2: + case IR_COMPAREF4: + case IR_COMPAREF8: + case IR_CFF1: + case IR_CFF2: + case IR_CFF4: + case IR_CFF8: if (ir->left) promote(ir->left); if (ir->right) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 180f41000..a48f59e9c 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -149,10 +149,18 @@ static struct ir* convert(struct ir* src, int destsize, int opcode) ); } -static struct ir* tristate_compare(int size, int opcode) +static struct ir* compare(struct ir* left, struct ir* right, + int size, int opcode) { - struct ir* right = pop(size); - struct ir* left = pop(size); + switch (size) + { + case 1: opcode += 0; break; + case 2: opcode += 1; break; + case 4: opcode += 2; break; + case 8: opcode += 3; break; + default: + fatal("can't compare things of size %d", size); + } return new_ir2( @@ -161,6 +169,14 @@ static struct ir* tristate_compare(int size, int opcode) ); } +static struct ir* tristate_compare(int size, int opcode) +{ + struct ir* right = pop(size); + struct ir* left = pop(size); + + return compare(left, right, size, opcode); +} + static void simple_convert(int opcode) { struct ir* destsize = pop(EM_wordsize); @@ -199,10 +215,11 @@ static void insn_simple(int opcode) case op_cui: simple_convert(IR_CUI1); break; case op_cfi: simple_convert(IR_CFI1); break; case op_cif: simple_convert(IR_CIF1); break; + case op_cff: simple_convert(IR_CFF1); break; case op_cmp: push( - tristate_compare(EM_pointersize, IR_COMPAREU) + tristate_compare(EM_pointersize, IR_COMPAREU1) ); break; @@ -276,6 +293,17 @@ static void insn_simple(int opcode) break; } + case op_trp: + { + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(".trp") + ) + ); + } + case op_lni: { /* Increment line number --- ignore. */ @@ -299,10 +327,7 @@ static void simple_branch2(int opcode, int size, appendir( new_ir2( irop, 0, - new_ir2( - IR_COMPARES, size, - left, right - ), + compare(left, right, size, IR_COMPARES1), new_ir2( IR_PAIR, 0, new_bbir(truebb), @@ -463,9 +488,9 @@ static void insn_ivalue(int opcode, arith value) case op_ngf: simple_alu1(opcode, value, IR_NEGF); break; case op_cmu: /* fall through */ - case op_cms: push(tristate_compare(value, IR_COMPAREU)); break; - case op_cmi: push(tristate_compare(value, IR_COMPARES)); break; - case op_cmf: push(tristate_compare(value, IR_COMPAREF)); break; + case op_cms: push(tristate_compare(value, IR_COMPAREU1)); break; + case op_cmi: push(tristate_compare(value, IR_COMPARES1)); break; + case op_cmf: push(tristate_compare(value, IR_COMPAREF1)); break; case op_lol: push( @@ -910,8 +935,8 @@ static void insn_ivalue(int opcode, arith value) case op_fef: { - struct ir* e; struct ir* f = pop(value); + /* fef is implemented by calling a helper function which then mutates * the stack. We read the return values off the stack when retracting * the stack pointer. */ @@ -931,6 +956,26 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_fif: + { + /* fif is implemented by calling a helper function which then mutates + * the stack. We read the return values off the stack when retracting + * the stack pointer. */ + + /* We start with two floats on the stack. */ + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir((value == 4) ? ".fif4" : ".fif8") + ) + ); + + /* exit, leaving two floats (or doubles) on the stack. */ + break; + } + case op_lin: { /* Set line number --- ignore. */ diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 576587247..93f7b3c79 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -74,10 +74,26 @@ S CIF2 S CIF4 S CIF8 +S CFF1 +S CFF2 +S CFF4 +S CFF8 + # Tristate comparisons -S COMPARES -S COMPAREU -S COMPAREF +S COMPARES1 +S COMPARES2 +S COMPARES4 +S COMPARES8 + +S COMPAREU1 +S COMPAREU2 +S COMPAREU4 +S COMPAREU8 + +S COMPAREF1 +S COMPAREF2 +S COMPAREF4 +S COMPAREF8 # Boolean comparisons S IFEQ From 90d0661639e6d9c937a3e2a919d1121144bf73fa Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 22 Oct 2016 00:48:55 +0200 Subject: [PATCH 134/230] Typo fix. --- mach/proto/mcg/treebuilder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index a48f59e9c..12aa5c2da 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -302,6 +302,7 @@ static void insn_simple(int opcode) new_labelir(".trp") ) ); + break; } case op_lni: From 7ae888b7542690fe21924c3e2339700dfbb41ed0 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 22 Oct 2016 10:48:22 +0200 Subject: [PATCH 135/230] Hacky workaround the way the Modula-2 compiler generates non-standard sized loads and saves. More opcodes; simplified table using macros. --- mach/powerpc/mcg/table | 111 ++++++++++++++++------------------- mach/proto/mcg/treebuilder.c | 50 ++++++++++++++-- util/mcgg/build.lua | 8 ++- util/mcgg/ir.dat | 1 + 4 files changed, 102 insertions(+), 68 deletions(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 632a47ef8..15a278e16 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -463,19 +463,29 @@ PATTERNS /* ALU operations */ - out:(int)reg = ADD4(left:(int)reg, right:(int)reg) - emit "add %out, %left, %right" - cost 4; + #define ALUR(name, instr) \ + out:(int)reg = name(left:(int)reg, right:(int)reg) \ + emit instr " %out, %left, %right" \ + cost 4; \ - out:(int)reg = ADD4(left:(int)reg, right:CONST4) - when signed_constant(%right, 16) - emit "addi %out, %left, $right" - cost 4; + #define ALUC(name, instr) \ + out:(int)reg = name(left:(int)reg, right:CONST4) \ + when signed_constant(%right, 16) \ + emit instr " %out, %left, $right" \ + cost 4; \ - out:(int)reg = ADD4(left:CONST4, right:(int)reg) - when signed_constant(%left, 16) - emit "addi %out, %right, $left" - cost 4; + #define ALUC_reversed(name, instr) \ + out:(int)reg = name(left:CONST4, right:(int)reg) \ + when signed_constant(%left, 16) \ + emit instr " %out, %right, $left" \ + cost 4; \ + + #define ALUCC(name, instr) \ + ALUC(name, instr) \ + ALUC_reversed(name, instr) + + ALUR(ADD4, "add") + ALUCC(ADD4, "addi") out:(int)reg = SUB4(left:(int)reg, right:(int)reg) emit "subf %out, %left, %right" @@ -485,51 +495,32 @@ PATTERNS emit "addi %out, %left, -[$right]" cost 4; - out:(int)reg = MUL4(left:(int)reg, right:(int)reg) - emit "mullw %out, %right, %left" - cost 4; - out:(int)reg = MOD4(left:(int)reg, right:(int)reg) emit "divw %out, %left, %right" emit "mullw %out, %out, %right" emit "subf %out, %out, %left" cost 12; - out:(int)reg = MUL4(left:(int)reg, right:(int)reg) - emit "mullw %out, %left, %right" - cost 4; + ALUR(MUL4, "mullw") + ALUCC(MUL4, "mulli") - out:(int)reg = DIV4(left:(int)reg, right:(int)reg) - emit "divw %out, %left, %right" - cost 4; + ALUR(DIV4, "divw") + ALUR(DIVU4, "divwu") - out:(int)reg = ASL4(left:(int)reg, right:(int)reg) - emit "slw %out, %left, %right" - cost 4; + ALUR(ASL4, "slw") out:(int)reg = NEG4(left:(int)reg) emit "neg %out, %left" cost 4; - out:(int)reg = AND4(left:CONST4, right:(int)reg) - emit "andi. %out, %right, $left" - cost 4; + ALUR(AND4, "and") + ALUCC(AND4, "andi.") - out:(int)reg = AND4(left:(int)reg, right:CONST4) - emit "andi. %out, %left, $right" - cost 4; + ALUR(OR4, "or") + ALUCC(OR4, "ori") - out:(int)reg = AND4(left:(int)reg, right:(int)reg) - emit "and %out, %left, %right" - cost 4; - - out:(int)reg = OR4(left:(int)reg, right:(int)reg) - emit "or %out, %right, %left" - cost 4; - - out:(int)reg = EOR4(left:(int)reg, right:(int)reg) - emit "xor %out, %right, %left" - cost 4; + ALUR(EOR4, "xor") + ALUCC(EOR4, "xori") out:(int)reg = value:LABEL4 emit "la %out, $value" @@ -546,6 +537,16 @@ PATTERNS /* FPU operations */ + #define FPU4R(name, instr) \ + out:(float)reg = name(left:(float)reg, right:(float)reg) \ + emit instr " %out, %left, %right" \ + cost 4; \ + + #define FPU8R(name, instr) \ + out:(double)reg = name(left:(double)reg, right:(double)reg) \ + emit instr " %out, %left, %right" \ + cost 4; \ + out:(float)reg = LOADF4(addr:address) emit "lfs %out, %addr" cost 4; @@ -558,29 +559,17 @@ PATTERNS emit "lfs %out, address-containing-$value" cost 8; - out:(float)reg = ADDF4(left:(float)reg, right:(float)reg) - emit "fadds %out, %left, %right" - cost 4; + FPU4R(ADDF4, "fadds") + FPU8R(ADDF8, "fadd") - out:(double)reg = ADDF8(left:(double)reg, right:(double)reg) - emit "fadd %out, %left, %right" - cost 4; + FPU4R(SUBF4, "fsubs") + FPU8R(SUBF8, "fsub") - out:(float)reg = SUBF4(left:(float)reg, right:(float)reg) - emit "fsubs %out, %left, %right" - cost 4; + FPU4R(MULF4, "fmuls") + FPU8R(MULF8, "fmul") - out:(double)reg = SUBF8(left:(double)reg, right:(double)reg) - emit "fsub %out, %left, %right" - cost 4; - - out:(float)reg = MULF4(left:(float)reg, right:(float)reg) - emit "fmuls %out, %left, %right" - cost 4; - - out:(double)reg = MULF8(left:(double)reg, right:(double)reg) - emit "fmul %out, %left, %right" - cost 4; + FPU4R(DIVF4, "fdivs") + FPU8R(DIVF8, "fdiv") out:(float)reg = NEGF4(left:(float)reg) emit "fneg %out, %left" diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 12aa5c2da..4ee49ebba 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -458,6 +458,19 @@ static void change_by(struct ir* address, int amount) ); } +static struct ir* ptradd(struct ir* address, int offset) +{ + if (offset == 0) + return address; + + return + new_ir2( + IR_ADD, EM_pointersize, + address, + new_wordir(offset) + ); +} + static void insn_ivalue(int opcode, arith value) { switch (opcode) @@ -476,6 +489,7 @@ static void insn_ivalue(int opcode, arith value) case op_mlu: simple_alu2(opcode, value, IR_MUL); break; case op_slu: simple_alu2(opcode, value, IR_LSL); break; case op_sru: simple_alu2(opcode, value, IR_LSR); break; + case op_dvu: simple_alu2(opcode, value, IR_DIVU); break; case op_and: simple_alu2(opcode, value, IR_AND); break; case op_ior: simple_alu2(opcode, value, IR_OR); break; @@ -628,13 +642,37 @@ static void insn_ivalue(int opcode, arith value) break; case op_loi: - push( - new_ir1( - IR_LOAD, value, - pop(EM_pointersize) - ) - ); + { + struct ir* ptr = pop(EM_pointersize); + int offset = 0; + + /* FIXME: this is awful; need a better way of dealing with + * non-standard EM sizes. */ + if (value > (EM_wordsize*2)) + appendir(ptr); + + while (value > 0) + { + int s; + if (value > (EM_wordsize*2)) + s = EM_wordsize*2; + else + s = value; + + push( + new_ir1( + IR_LOAD, s, + ptradd(ptr, offset) + ) + ); + + value -= s; + offset += s; + } + + assert(value == 0); break; + } case op_lof: { diff --git a/util/mcgg/build.lua b/util/mcgg/build.lua index 8606755c7..f8055050c 100644 --- a/util/mcgg/build.lua +++ b/util/mcgg/build.lua @@ -65,6 +65,12 @@ definerule("mcgg", error("you must supply exactly one input file") end + local cpptable = cppfile { + name = e.name.."/cpptable", + outleaf = "cpptable", + srcs = e.srcs + } + return normalrule { name = e.name, cwd = e.cwd, @@ -74,7 +80,7 @@ definerule("mcgg", }, ins = { "util/mcgg+mcgg", - e.srcs[1] + cpptable }, commands = { "%{ins[1]} -i %{ins[2]} -o %{outs[1]} -h %{outs[2]}", diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 93f7b3c79..7fe51ed30 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -30,6 +30,7 @@ S ADD S SUB S MUL S DIV +S DIVU S MOD S NEG From ceb938fb3c5b535ddd4e30f34180e6c25ea84511 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 22 Oct 2016 11:26:28 +0200 Subject: [PATCH 136/230] More opcodes. --- mach/powerpc/mcg/table | 12 ++++++ mach/proto/mcg/treebuilder.c | 75 ++++++++++++++++++++++++++++++++++++ util/mcgg/ir.dat | 2 + 3 files changed, 89 insertions(+) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 15a278e16..fe29607c5 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -194,6 +194,10 @@ PATTERNS emit "addi sp, sp, $delta" cost 4; + STACKADJUST4(in:(int)reg) + emit "add sp, sp, %in" + cost 4; + out:(int)reg = GETFP4 emit "mr %out, fp" cost 4; @@ -206,6 +210,14 @@ PATTERNS emit "addi %out, %in, 8" cost 4; + out:(int)reg = GETSP4 + emit "mr %out, sp" + cost 4; + + SETSP4(in:(int)reg) + emit "mr sp, %in" + cost 4; + /* Memory operations */ diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 4ee49ebba..7d2b0b11f 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -817,6 +817,15 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_ass: + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + pop(value) + ) + ); + break; + case op_ret: { if (value > 0) @@ -1015,6 +1024,72 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_lor: + { + switch (value) + { + case 1: + appendir( + new_ir0( + IR_GETSP, EM_pointersize + ) + ); + break; + + default: + fatal("'lor %d' not supported", value); + } + + break; + } + + case op_str: + { + switch (value) + { + case 1: + appendir( + new_ir1( + IR_SETSP, EM_pointersize, + pop(EM_pointersize) + ) + ); + break; + + default: + fatal("'str %d' not supported", value); + } + + break; + } + + case op_blm: + { + /* Input stack: ( src dest -- ) */ + /* Memmove stack: ( size src dest -- ) */ + struct ir* dest = pop(EM_pointersize); + struct ir* src = pop(EM_pointersize); + + push(new_wordir(value)); + push(src); + push(dest); + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir("memmove") + ) + ); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_wordir(EM_pointersize*2 + EM_wordsize) + ) + ); + break; + } + case op_lin: { /* Set line number --- ignore. */ diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 7fe51ed30..2a6fec02d 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -116,6 +116,8 @@ S STACKADJUST S GETRET S SETRET S GETFP +S GETSP +S SETSP S CHAINFP S FPTOARGS From 2d52b1fdaac288c40ff8c7be07198a3454d6caad Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 22 Oct 2016 12:13:57 +0200 Subject: [PATCH 137/230] Remove GETRET; values are now returned directly by CALL. Fix a bug in convertstackops which was resulting in duplicate IR groups. --- mach/powerpc/mcg/table | 38 ++++++++++++++++++--------- mach/proto/mcg/pass_convertstackops.c | 3 ++- mach/proto/mcg/treebuilder.c | 28 ++++++++------------ util/mcgg/ir.dat | 3 +-- 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index fe29607c5..240086b0c 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -130,9 +130,9 @@ DECLARATIONS cr; ubyteX; /* bottom 8 bits valid, the rest undefined */ - ubyte0; /* bottom 8 bits valid, the rest 0 */ + ubyte0; /* bottom 8 bits valid, the rest 0 */ ushortX; /* bottom 16 bits valid, the rest undefined */ - ushort0; /* bottom 16 bits valid, the rest 0 */ + ushort0; /* bottom 16 bits valid, the rest 0 */ address fragment; @@ -181,14 +181,6 @@ PATTERNS emit "! setret8" cost 1; - (ret)reg = GETRET4 - emit "! getret4" - cost 1; - - (pret)reg = GETRET8 - emit "! getret8" - cost 1; - STACKADJUST4(delta:CONST4) when signed_constant(%delta, 16) emit "addi sp, sp, $delta" @@ -401,12 +393,34 @@ PATTERNS emit "b $false" cost 8; - CALL(dest:LABEL4) + CALL1(dest:LABEL4) with corrupted(volatile) emit "bl $dest" cost 4; - CALL(dest:(int)reg) + out:(ret)reg = CALL4(dest:LABEL4) + with corrupted(volatile) + emit "bl $dest" + cost 4; + + out:(pret)reg = CALL8(dest:LABEL4) + with corrupted(volatile) + emit "bl $dest" + cost 4; + + CALL1(dest:(int)reg) + with corrupted(volatile) + emit "mtspr ctr, %dest" + emit "bcctrl 20, 0, 0" + cost 8; + + out:(ret)reg = CALL4(dest:(int)reg) + with corrupted(volatile) + emit "mtspr ctr, %dest" + emit "bcctrl 20, 0, 0" + cost 8; + + out:(pret)reg = CALL8(dest:(int)reg) with corrupted(volatile) emit "mtspr ctr, %dest" emit "bcctrl 20, 0, 0" diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index 692a11a62..a8968c22f 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -88,7 +88,8 @@ static void convert_block(struct basicblock* bb) for (i=0; ileft; + ir->opcode = IR_NOP; + ir->size = 0; } for (i=0; isize = value; + push(lastcall); break; } @@ -918,15 +915,12 @@ static void insn_ivalue(int opcode, arith value) } materialise_stack(); - appendir( - new_ir1( - IR_CALL, 0, - new_labelir(helper) - ) - ); push( - new_ir0( - IR_GETRET, EM_wordsize + appendir( + new_ir1( + IR_CALL, EM_wordsize, + new_labelir(helper) + ) ) ); break; @@ -1198,7 +1192,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset) case op_cal: assert(offset == 0); materialise_stack(); - appendir( + lastcall = appendir( new_ir1( IR_CALL, 0, new_labelir(label) diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 2a6fec02d..6b3c3755e 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -102,7 +102,7 @@ S IFLT S IFLE # Procedures -V CALL +S CALL # Flow control --- these never return V JUMP @@ -113,7 +113,6 @@ V RET # Special S STACKADJUST -S GETRET S SETRET S GETFP S GETSP From 11b0bc1055d1e089608a1f29be84c41938b8d670 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 22 Oct 2016 20:32:51 +0200 Subject: [PATCH 138/230] More opcodes. --- mach/powerpc/mcg/table | 17 +++++- mach/proto/mcg/treebuilder.c | 113 ++++++++++++++++++++++------------- util/mcgg/ir.dat | 3 +- 3 files changed, 90 insertions(+), 43 deletions(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 240086b0c..8a87e079d 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -464,12 +464,12 @@ PATTERNS out:(int)reg = IFEQ4(in:(cr)cr) emit "mfcr %out" /* get cr0 */ - emit "rlwinmi %out, %out, 32-2, 2, 31" /* extract just EQ */ + emit "rlwinm %out, %out, [32-2], 2, 31" /* extract just EQ */ cost 8; out:(int)reg = IFEQ4(in:(int)reg) emit "cntlzw %out, %in" /* returns 0..32 */ - emit "rlwinmi %out, %out, 32-5, 5, 31" /* if 32, return 1, otherwise 0 */ + emit "rlwinm %out, %out, [32-5], 5, 31" /* if 32, return 1, otherwise 0 */ cost 8; @@ -527,6 +527,12 @@ PATTERNS emit "subf %out, %out, %left" cost 12; + out:(int)reg = MODU4(left:(int)reg, right:(int)reg) + emit "divwu %out, %left, %right" + emit "mullw %out, %out, %right" + emit "subf %out, %out, %left" + cost 12; + ALUR(MUL4, "mullw") ALUCC(MUL4, "mulli") @@ -535,10 +541,17 @@ PATTERNS ALUR(ASL4, "slw") + ALUR(LSL4, "slw") + out:(int)reg = NEG4(left:(int)reg) emit "neg %out, %left" cost 4; + out:(int)reg = NOT4(left:(int)reg) + emit "cntlzw %out, %left" + emit "rlwinm %out, %out, 32-5, 5, 31" + cost 8; + ALUR(AND4, "and") ALUCC(AND4, "andi.") diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 91a082655..4ec1b46e0 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -178,6 +178,14 @@ static struct ir* tristate_compare(int size, int opcode) return compare(left, right, size, opcode); } +static struct ir* tristate_compare0(int size, int opcode) +{ + struct ir* right = new_wordir(0); + struct ir* left = pop(size); + + return compare(left, right, size, opcode); +} + static void simple_convert(int opcode) { struct ir* destsize = pop(EM_wordsize); @@ -193,6 +201,60 @@ static void simple_convert(int opcode) ); } +static void simple_branch2(int opcode, int size, + struct basicblock* truebb, struct basicblock* falsebb, + int irop) +{ + struct ir* right = pop(size); + struct ir* left = pop(size); + + materialise_stack(); + appendir( + new_ir2( + irop, 0, + compare(left, right, size, IR_COMPARES1), + new_ir2( + IR_PAIR, 0, + new_bbir(truebb), + new_bbir(falsebb) + ) + ) + ); +} + +static void compare0_branch2(int opcode, + struct basicblock* truebb, struct basicblock* falsebb, + int irop) +{ + push( + new_wordir(0) + ); + + simple_branch2(opcode, EM_wordsize, truebb, falsebb, irop); +} + +static void simple_test(int size, int irop) +{ + push( + new_ir1( + irop, EM_wordsize, + tristate_compare0(size, IR_COMPARES1) + ) + ); +} + +static void simple_test_neg(int size, int irop) +{ + simple_test(size, irop); + + push( + new_ir1( + IR_NOT, EM_wordsize, + pop(EM_wordsize) + ) + ); +} + static void insn_simple(int opcode) { switch (opcode) @@ -224,14 +286,8 @@ static void insn_simple(int opcode) ); break; - case op_teq: - push( - new_ir1( - IR_IFEQ, EM_wordsize, - pop(EM_wordsize) - ) - ); - break; + case op_teq: simple_test(EM_wordsize, IR_IFEQ); break; + case op_tne: simple_test_neg(EM_wordsize, IR_IFEQ); break; case op_cai: { @@ -318,38 +374,6 @@ static void insn_simple(int opcode) } } -static void simple_branch2(int opcode, int size, - struct basicblock* truebb, struct basicblock* falsebb, - int irop) -{ - struct ir* right = pop(size); - struct ir* left = pop(size); - - materialise_stack(); - appendir( - new_ir2( - irop, 0, - compare(left, right, size, IR_COMPARES1), - new_ir2( - IR_PAIR, 0, - new_bbir(truebb), - new_bbir(falsebb) - ) - ) - ); -} - -static void compare0_branch2(int opcode, - struct basicblock* truebb, struct basicblock* falsebb, - int irop) -{ - push( - new_wordir(0) - ); - - simple_branch2(opcode, EM_wordsize, truebb, falsebb, irop); -} - static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock* rightbb) { switch (opcode) @@ -490,6 +514,7 @@ static void insn_ivalue(int opcode, arith value) case op_mlu: simple_alu2(opcode, value, IR_MUL); break; case op_slu: simple_alu2(opcode, value, IR_LSL); break; case op_sru: simple_alu2(opcode, value, IR_LSR); break; + case op_rmu: simple_alu2(opcode, value, IR_MODU); break; case op_dvu: simple_alu2(opcode, value, IR_DIVU); break; case op_and: simple_alu2(opcode, value, IR_AND); break; @@ -595,6 +620,14 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_zrf: + { + struct ir* ir = new_constir(value, 0); + ir->opcode = IR_CONSTF; + push(ir); + break; + } + case op_loe: push( new_ir1( diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 6b3c3755e..5c47c6639 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -32,6 +32,7 @@ S MUL S DIV S DIVU S MOD +S MODU S NEG S ADDF @@ -96,7 +97,7 @@ S COMPAREF2 S COMPAREF4 S COMPAREF8 -# Boolean comparisons +# Tristate to boolean conversion S IFEQ S IFLT S IFLE From b1a3d76d6fe525e0cf5c7ae741c6c78d25b0198e Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 22 Oct 2016 23:04:13 +0200 Subject: [PATCH 139/230] Re-re-add the type inference layer, now I know more about how things work. Remove that terrible float promotion code. --- mach/proto/mcg/ir.c | 4 +- mach/proto/mcg/ir.h | 1 + mach/proto/mcg/mcg.h | 2 +- mach/proto/mcg/pass_promotefloatops.c | 122 ------------ mach/proto/mcg/pass_typeinference.c | 277 ++++++++++++++++++++++++++ mach/proto/mcg/procedure.c | 2 +- util/mcgg/ir.dat | 199 +++++++++--------- util/mcgg/ircodes.h | 3 + util/mcgg/ircodes.sh | 15 +- 9 files changed, 405 insertions(+), 220 deletions(-) delete mode 100644 mach/proto/mcg/pass_promotefloatops.c create mode 100644 mach/proto/mcg/pass_typeinference.c diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index 74fbac060..e30e82a2b 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -105,7 +105,9 @@ struct ir* ir_find(struct ir* ir, int opcode) static void print_expr(char k, const struct ir* ir) { tracef(k, "%s", ir_data[ir->opcode].name); - if (ir->size) + if (ir->type) + tracef(k, ".%c", ir->type); + else if (ir->size) tracef(k, "%d", ir->size); tracef(k, "("); diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 83dd34246..10fa83a48 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -8,6 +8,7 @@ struct ir int id; enum ir_opcode opcode; int size; + char type; struct ir* left; struct ir* right; struct ir* root; diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index f76264813..c60dee9ce 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -109,11 +109,11 @@ extern void pass_convert_stack_ops(void); extern void pass_eliminate_trivial_blocks(void); extern void pass_find_phi_congruence_groups(void); extern void pass_group_irs(void); +extern void pass_infer_types(void); extern void pass_insert_moves(void); extern void pass_instruction_selector(void); extern void pass_live_vreg_analysis(void); extern void pass_add_prologue_epilogue(void); -extern void pass_promote_float_ops(void); extern void pass_register_allocator(void); extern void pass_remove_dead_blocks(void); extern void pass_remove_dead_phis(void); diff --git a/mach/proto/mcg/pass_promotefloatops.c b/mach/proto/mcg/pass_promotefloatops.c deleted file mode 100644 index 7e5f87c19..000000000 --- a/mach/proto/mcg/pass_promotefloatops.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "mcg.h" - -static ARRAYOF(struct ir) pending; -static ARRAYOF(struct ir) promotable; - -static void addall(struct ir* ir) -{ - if (array_appendu(&pending, ir)) - return; - - if (ir->left) - addall(ir->left); - if (ir->right) - addall(ir->right); -} - -static void collect_irs(void) -{ - int i; - - pending.count = 0; - promotable.count = 0; - for (i=0; iirs.count; j++) - addall(bb->irs.item[j]); - } -} - -static void promote(struct ir* ir) -{ - switch (ir->opcode) - { - case IR_CONST: - case IR_POP: - case IR_LOAD: - array_appendu(&promotable, ir); - break; - - case IR_NOP: - promote(ir->left); - break; - - case IR_PHI: - { - int i; - for (i=0; iu.phivalue.count; i++) - promote(ir->u.phivalue.item[i].right); - break; - } - } -} - -static void search_for_promotable_irs(void) -{ - int i; - - for (i=0; iopcode) - { - case IR_ADDF: - case IR_SUBF: - case IR_MULF: - case IR_DIVF: - case IR_NEGF: - case IR_COMPAREF1: - case IR_COMPAREF2: - case IR_COMPAREF4: - case IR_COMPAREF8: - case IR_CFF1: - case IR_CFF2: - case IR_CFF4: - case IR_CFF8: - if (ir->left) - promote(ir->left); - if (ir->right) - promote(ir->right); - break; - } - } -} - -static void modify_promotable_irs(void) -{ - int i; - - for (i=0; iopcode) - { - case IR_ADDF: - case IR_SUBF: - case IR_MULF: - case IR_DIVF: - case IR_NEGF: - case IR_PHI: - case IR_NOP: - break; - - default: - ir->opcode++; - break; - } - } -} - -void pass_promote_float_ops(void) -{ - collect_irs(); - search_for_promotable_irs(); - modify_promotable_irs(); -} - -/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_typeinference.c b/mach/proto/mcg/pass_typeinference.c new file mode 100644 index 000000000..d330152ef --- /dev/null +++ b/mach/proto/mcg/pass_typeinference.c @@ -0,0 +1,277 @@ +#include "mcg.h" + +static bool changed; +static ARRAYOF(struct ir) irs; + +static void addall(struct ir* ir) +{ + if (array_appendu(&irs, ir)) + return; + + if (ir->left) + addall(ir->left); + if (ir->right) + addall(ir->right); +} + +static void collect_irs(void) +{ + int i; + + irs.count = 0; + for (i=0; iirs.count; j++) + addall(bb->irs.item[j]); + } +} + +static char effective_type(struct ir* ir, char type) +{ + switch (type) + { + case 'I': + case 'F': + case 'L': + case 'D': + return type; + + case 'i': + if (ir->size == EM_wordsize) + return 'I'; + else if (ir->size == (EM_wordsize*2)) + return 'L'; + break; + + case 'f': + if (ir->size == EM_wordsize) + return 'F'; + else if (ir->size == (EM_wordsize*2)) + return 'D'; + break; + } + + return 0; +} + +static void scan_irs(void) +{ + int i; + + for (i=0; iopcode == IR_PHI) + { + int j; + + /* Phis are special. We treat them as ?=? for every import value. + * */ + + if (ir->type) + { + /* Push this type to all our children. */ + + for (j=0; ju.phivalue.count; j++) + { + struct ir* child = ir->u.phivalue.item[j].right; + if (!child->type) + { + child->type = ir->type; + changed = true; + } + } + } + else + { + /* Pull our type from the first child with a set type; we + * ignore the rest, as the next iteration will push our type to + * them. It's possible for our children to have conflicting + * types. There's not much we can do about that so we just have + * to live with it and intelligently insert casts. */ + + for (j=0; ju.phivalue.count; j++) + { + struct ir* child = ir->u.phivalue.item[j].right; + if (child->type) + { + /* Found one! */ + ir->type = child->type; + changed = true; + break; + } + } + } + } + else + { + const struct ir_data* ird = &ir_data[ir->opcode]; + + if (!ir->type) + { + char etype = effective_type(ir, ird->returntype); + if (etype) + { + ir->type = etype; + changed = true; + } + } + + if (ir->left && !ir->left->type) + { + const struct ir_data* leftird = &ir_data[ir->left->opcode]; + if (leftird->returntype == '?') + { + char etype = effective_type(ir, ird->lefttype); + if (etype) + { + ir->left->type = etype; + changed = true; + } + } + } + + if (ir->right && !ir->right->type) + { + const struct ir_data* rightird = &ir_data[ir->right->opcode]; + if (rightird->returntype == '?') + { + char etype = effective_type(ir, ird->righttype); + if (etype) + { + ir->right->type = etype; + changed = true; + } + } + } + + if (!ir->type && (ird->returntype == '?')) + { + if ((ird->lefttype == '?') && ir->left->type) + { + ir->type = ir->left->type; + changed = true; + } + + if ((ird->righttype == '?') && ir->right->type) + { + ir->type = ir->right->type; + changed = true; + } + } + + if (ir->type && (ird->lefttype == '?') && !ir->left->type) + { + ir->left->type = ir->type; + changed = true; + } + + if (ir->type && (ird->righttype == '?') && !ir->right->type) + { + ir->right->type = ir->type; + changed = true; + } + } + } +} + +static void propagate_types(void) +{ + do + { + changed = false; + + scan_irs(); + } + while (changed); +} + +static void assign_fallback_types(void) +{ + int i; + + for (i=0; iopcode]; + + if (!ir->type && (ird->returntype == '?')) + ir->type = effective_type(ir, 'i'); + } +} + +static struct ir* new_copy(char wanted, char real, struct ir* ir) +{ + struct ir* copy; + int opcode; + + if ((wanted == 'F') && (real == 'I')) + opcode = IR_COPYI; + else if ((wanted == 'D') && (real == 'L')) + opcode = IR_COPYI; + else if ((wanted == 'I') && (real == 'F')) + opcode = IR_COPYF; + else if ((wanted == 'L') && (real == 'D')) + opcode = IR_COPYF; + else + fatal("type mismatch: parent IR wanted %c, child IR provided %c", + wanted, real); + + copy = new_ir1(opcode, ir->size, ir); + copy->type = wanted; + return copy; +} + +static void insert_copies(void) +{ + int i; + + /* Insert copies for normal IR nodes. */ + + for (i=0; iopcode]; + + if (ir->left) + { + char wanted = effective_type(ir, ird->lefttype); + char real = ir->left->type; + + if (wanted && (wanted != real)) + { + struct ir* copy = new_copy(wanted, real, ir->left); + copy->root = ir->root; + ir->left = copy; + } + } + + if (ir->right) + { + char wanted = effective_type(ir, ird->righttype); + char real = ir->right->type; + + if (wanted && (wanted != real)) + { + struct ir* copy = new_copy(wanted, real, ir->right); + copy->root = ir->root; + ir->right = copy; + } + } + } +} + +void pass_infer_types(void) +{ + collect_irs(); + propagate_types(); + assign_fallback_types(); + insert_copies(); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 320dedf7b..a41dac459 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -184,7 +184,7 @@ void procedure_compile(struct procedure* proc) pass_convert_locals_to_ssa(); print_blocks('5'); pass_remove_dead_phis(); - pass_promote_float_ops(); + pass_infer_types(); print_blocks('6'); pass_instruction_selector(); diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 5c47c6639..8f09d4204 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -1,123 +1,138 @@ # Flags: # S: has size (use in CONST1, CONST2, CONST4, CONST8 forms) # V: has no size (use in JUMP, CJUMP, RET forms) +# +# Types: +# +# I, F, L, D: int, float, long, double +# i, F: int, float; promoted to long, double based on size +# .: ignore this parameter +# ?: pull/push types from other ? parameters # Simple terminals -S CONST # must be followed by float form -S CONSTF -V REG -V NOP -S LABEL -S BLOCK -V PAIR -S ANY -S LOCAL -V PHI +S ?=.. CONST # must be followed by float form +S ?=.. CONSTF +V ?=.. REG +V ?=?. NOP +S I=.. LABEL +S I=.. BLOCK +V ?=.. PAIR +S ?=.. ANY +S ?=.. LOCAL +V ?=.. PHI # Magic stack operations -S PUSH -S POP # must be followed by float form -S POPF +S ?=?. PUSH +S ?=.. POP +S ?=.. POPF -#... Memory operations -S LOAD # must be followed by float form -S LOADF -S STORE -S STOREF +# Memory operations +S ?=I. LOAD # must be followed by float form +S f=I. LOADF +S ?=I? STORE +S ?=If STOREF # Arithemetic operations -S ADD -S SUB -S MUL -S DIV -S DIVU -S MOD -S MODU -S NEG +S i=ii ADD +S i=ii SUB +S i=ii MUL +S i=ii DIV +S i=ii DIVU +S i=ii MOD +S i=ii MODU +S i=ii NEG -S ADDF -S SUBF -S MULF -S DIVF -S NEGF +S f=ff ADDF +S f=ff SUBF +S f=ff MULF +S f=ff DIVF +S f=ff NEGF -S AND -S OR -S EOR -S NOT -S ASL -S ASR -S LSL -S LSR +S i=ii AND +S i=ii OR +S i=ii EOR +S i=ii NOT +S i=ii ASL +S i=ii ASR +S i=ii LSL +S i=ii LSR -# Conversions -S CII1 -S CII2 -S CII4 -S CII8 +# Bitwise conversions +# (Remember, these don't change the value, merely move it) +S i=f. COPYF +S f=i. COPYI -S CIU1 -S CIU2 -S CIU4 -S CIU8 +# Semantic conversions +S F=D. D2F +S D=F. F2D -S CUI1 -S CUI2 -S CUI4 -S CUI8 +S I=I. CII1 +S I=I. CII2 +S I=I. CII4 +S L=L. CII8 -S CFI1 -S CFI2 -S CFI4 -S CFI8 +S I=I. CIU1 +S I=I. CIU2 +S I=I. CIU4 +S L=L. CIU8 -S CIF1 -S CIF2 -S CIF4 -S CIF8 +S I=I. CUI1 +S I=I. CUI2 +S I=I. CUI4 +S L=L. CUI8 -S CFF1 -S CFF2 -S CFF4 -S CFF8 +S I=F. CFI1 +S I=F. CFI2 +S I=F. CFI4 +S L=D. CFI8 + +S I=F. CIF1 +S I=F. CIF2 +S I=F. CIF4 +S L=D. CIF8 + +S F=F. CFF1 +S F=F. CFF2 +S F=F. CFF4 +S D=D. CFF8 # Tristate comparisons -S COMPARES1 -S COMPARES2 -S COMPARES4 -S COMPARES8 +S I=II COMPARES1 +S I=II COMPARES2 +S I=II COMPARES4 +S I=LL COMPARES8 -S COMPAREU1 -S COMPAREU2 -S COMPAREU4 -S COMPAREU8 +S I=II COMPAREU1 +S I=II COMPAREU2 +S I=II COMPAREU4 +S I=LL COMPAREU8 -S COMPAREF1 -S COMPAREF2 -S COMPAREF4 -S COMPAREF8 +S I=FF COMPAREF1 +S I=FF COMPAREF2 +S I=FF COMPAREF4 +S I=DD COMPAREF8 # Tristate to boolean conversion -S IFEQ -S IFLT -S IFLE +S I=I. IFEQ +S I=I. IFLT +S I=I. IFLE # Procedures -S CALL +S i=.. CALL # Flow control --- these never return -V JUMP -V CJUMPEQ -V CJUMPLT -V CJUMPLE -V RET +V .=i. JUMP +V .=i. CJUMPEQ +V .=i. CJUMPLT +V .=i. CJUMPLE +V .=.. RET # Special -S STACKADJUST -S SETRET -S GETFP -S GETSP -S SETSP -S CHAINFP -S FPTOARGS +S ?=i. STACKADJUST +S ?=i. SETRET +S i=.. GETFP +S i=.. GETSP +S ?=i. SETSP +S i=i. CHAINFP +S i=i. FPTOARGS diff --git a/util/mcgg/ircodes.h b/util/mcgg/ircodes.h index c5bbb9f2d..7d91b27fd 100644 --- a/util/mcgg/ircodes.h +++ b/util/mcgg/ircodes.h @@ -10,6 +10,9 @@ struct ir_data { const char* name; int flags; + char returntype; + char lefttype; + char righttype; }; extern const struct ir_data ir_data[]; diff --git a/util/mcgg/ircodes.sh b/util/mcgg/ircodes.sh index 7c9917d12..ff2df4845 100755 --- a/util/mcgg/ircodes.sh +++ b/util/mcgg/ircodes.sh @@ -10,7 +10,7 @@ awk -f - $in >$header << "EOF" } /^ *[^# ]+/ { - print "\tIR_" $2 "," + print "\tIR_" $3 "," } END { @@ -30,9 +30,18 @@ awk -f - $in >$source << "EOF" return "0" } + function char_to_type(c) { + if (c ~ /[A-Za-z]/) return "'"c"'" + if (c == "?") return "'?'" + if (c == ".") return "0" + } + /^ *[^# ]+/ { - printf("\t{ \"%s\", ", $2) - printf("%s", char_to_flags(substr($1, 1, 1))) + printf("\t{ \"%s\", ", $3) + printf("%s, ", char_to_flags(substr($1, 1, 1))) + printf("%s, ", char_to_type(substr($2, 1, 1))) + printf("%s, ", char_to_type(substr($2, 3, 1))) + printf("%s, ", char_to_type(substr($2, 4, 1))) printf(" },\n") } From abd0cedd61aed515f22c75c0e1f85213d377494d Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 23 Oct 2016 21:54:14 +0200 Subject: [PATCH 140/230] Massive change to how IR types are handled; we use the type code for matching rather than the size. Much cleaner and simpler. --- mach/powerpc/mcg/platform.c | 10 +- mach/powerpc/mcg/table | 265 +++++++++++-------- mach/proto/mcg/pass_convertstackops.c | 1 - mach/proto/mcg/pass_instructionselection.c | 12 +- mach/proto/mcg/pass_ssa.c | 4 +- mach/proto/mcg/pass_typeinference.c | 4 +- mach/proto/mcg/treebuilder.c | 282 +++++++++++++-------- util/mcgg/gram.y | 19 +- util/mcgg/iburg.c | 30 ++- util/mcgg/ir.dat | 89 +++---- util/mcgg/mcgg.h | 14 +- 11 files changed, 419 insertions(+), 311 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 2b22ec1f3..664ed3848 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -99,7 +99,7 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* { struct hop* hop = new_hop(bb, NULL); const uint32_t type_attrs = - burm_int_ATTR | burm_pair_ATTR | burm_float_ATTR | burm_double_ATTR; + burm_int_ATTR | burm_long_ATTR | burm_float_ATTR | burm_double_ATTR; if ((src->type & type_attrs) != (dest->type & type_attrs)) { @@ -112,7 +112,7 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "stwu %H, -4(sp)", src); break; - case burm_pair_ATTR: + case burm_long_ATTR: hop_add_insel(hop, "stwu %0H, -4(sp)", src); hop_add_insel(hop, "stwu %1H, -4(sp)", src); break; @@ -135,7 +135,7 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "lwz %H, 0(sp)", dest); break; - case burm_pair_ATTR: + case burm_long_ATTR: hop_add_insel(hop, "lwz %0H, 4(sp)", dest); hop_add_insel(hop, "lwz %1H, 0(sp)", dest); break; @@ -160,7 +160,7 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* break; case burm_double_ATTR: - case burm_pair_ATTR: + case burm_long_ATTR: hop_add_insel(hop, "addi sp, sp, 8"); break; @@ -220,7 +220,7 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "mr %H, %H", dest, src); break; - case burm_pair_ATTR: + case burm_long_ATTR: hop_add_insel(hop, "mr %0H, %0H", dest, src); hop_add_insel(hop, "mr %1H, %1H", dest, src); break; diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 8a87e079d..2c3565a73 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -38,21 +38,21 @@ REGISTERS r14 bytes4! int!; r13 bytes4! int!; - r11r12 named("r11", "r12") aliases(r11, r12) bytes8! pair! volatile; - r9r10 named("r9", "r10") aliases(r9, r10) bytes8! pair! volatile; - r7r8 named("r7", "r8") aliases(r7, r8) bytes8! pair! volatile; - r5r6 named("r5", "r6") aliases(r6, r6) bytes8! pair! volatile; - r3r4 named("r3", "r4") aliases(r3, r4) bytes8! pair! volatile pret; + r11r12 named("r11", "r12") aliases(r11, r12) bytes8! long! volatile; + r9r10 named("r9", "r10") aliases(r9, r10) bytes8! long! volatile; + r7r8 named("r7", "r8") aliases(r7, r8) bytes8! long! volatile; + r5r6 named("r5", "r6") aliases(r6, r6) bytes8! long! volatile; + r3r4 named("r3", "r4") aliases(r3, r4) bytes8! long! volatile pret; - r29r30 named("r29", "r30") aliases(r29, r30) bytes8! pair!; - r27r28 named("r27", "r28") aliases(r27, r28) bytes8! pair!; - r25r26 named("r25", "r26") aliases(r25, r26) bytes8! pair!; - r23r24 named("r23", "r24") aliases(r23, r24) bytes8! pair!; - r21r22 named("r21", "r22") aliases(r21, r22) bytes8! pair!; - r19r20 named("r19", "r20") aliases(r19, r20) bytes8! pair!; - r17r18 named("r17", "r18") aliases(r17, r18) bytes8! pair!; - r15r16 named("r15", "r16") aliases(r15, r16) bytes8! pair!; - r13r14 named("r13", "r14") aliases(r13, r14) bytes8! pair!; + r29r30 named("r29", "r30") aliases(r29, r30) bytes8! long!; + r27r28 named("r27", "r28") aliases(r27, r28) bytes8! long!; + r25r26 named("r25", "r26") aliases(r25, r26) bytes8! long!; + r23r24 named("r23", "r24") aliases(r23, r24) bytes8! long!; + r21r22 named("r21", "r22") aliases(r21, r22) bytes8! long!; + r19r20 named("r19", "r20") aliases(r19, r20) bytes8! long!; + r17r18 named("r17", "r18") aliases(r17, r18) bytes8! long!; + r15r16 named("r15", "r16") aliases(r15, r16) bytes8! long!; + r13r14 named("r13", "r14") aliases(r13, r14) bytes8! long!; f14 bytes4! float! volatile; f13 bytes4! float! volatile; @@ -142,73 +142,90 @@ PATTERNS /* Special */ - PAIR(BLOCK4, BLOCK4); + PAIR(BLOCK.I, BLOCK.I); /* Miscellaneous special things */ - PUSH4(in:(int)reg) + PUSH.I(in:(int)reg) emit "stwu %in, -4(sp)" cost 4; - PUSH8(in:(pair)reg) + PUSH.L(in:(long)reg) emit "stwu %in.0, -4(sp)" emit "stwu %in.1, -4(sp)" cost 8; - out:(int)reg = POP4 + PUSH.D(in:(double)reg) + emit "stfdu %in, -8(sp)" + cost 4; + + out:(int)reg = POP.I emit "lwz %out, 0(sp)" emit "addi sp, sp, 4" cost 8; - out:(pair)reg = POP8 + out:(long)reg = POP.L emit "lwz %out.0, 4(sp)" emit "lwz %out.1, 0(sp)" emit "addi sp, sp, 8" cost 12; - out:(float)reg = POPF4 + out:(float)reg = POP.F emit "lfs %out, 0(sp)" emit "addi sp, sp, 4" cost 8; - SETRET4(in:(ret)reg) + SETRET.I(in:(ret)reg) emit "! setret4" cost 1; - SETRET8(in:(pret)reg) + SETRET.L(in:(pret)reg) emit "! setret8" cost 1; - STACKADJUST4(delta:CONST4) + STACKADJUST.I(delta:CONST.I) when signed_constant(%delta, 16) emit "addi sp, sp, $delta" cost 4; - STACKADJUST4(in:(int)reg) + STACKADJUST.I(in:(int)reg) emit "add sp, sp, %in" cost 4; - out:(int)reg = GETFP4 + out:(int)reg = GETFP.I emit "mr %out, fp" cost 4; - out:(int)reg = FPTOARGS4(GETFP4) + out:(int)reg = FPTOARGS.I(GETFP.I) emit "addi %out, fp, 8" cost 4; - out:(int)reg = FPTOARGS4(in:(int)reg) + out:(int)reg = FPTOARGS.I(in:(int)reg) emit "addi %out, %in, 8" cost 4; - out:(int)reg = GETSP4 + out:(int)reg = GETSP.I emit "mr %out, sp" cost 4; - SETSP4(in:(int)reg) + SETSP.I(in:(int)reg) emit "mr sp, %in" cost 4; + + out:(int)reg = COPYF.I(in:(float)reg) + emit "stfsu %in, -4(sp)" + emit "lwz %out, 0(sp)" + emit "addi sp, sp, 4" + cost 12; + + out:(double)reg = COPYL.D(in:(long)reg) + emit "stwu %in.0, -4(sp)" + emit "stwu %in.1, -4(sp)" + emit "lfd %out, 0(sp)" + emit "addi sp, sp, 8" + cost 16; @@ -216,47 +233,55 @@ PATTERNS /* Stores */ - STORE8(addr:address, value:(pair)reg) + STORE.L(addr:address, value:(long)reg) emit "stw %value.0, 4+%addr" emit "stw %value.1, 0+%addr" cost 4; - STORE4(addr:address, value:(int)reg) + STORE.I(addr:address, value:(int)reg) emit "stw %value, %addr" cost 4; - STORE2(addr:address, value:(int)ushortX) + STOREH.I(addr:address, value:(int)ushortX) emit "sth %value, %addr" cost 4; - STORE2(ADD4(left:(int)reg, right:(int)reg), value:(int)ushortX) + STOREH.I(ADD.I(left:(int)reg, right:(int)reg), value:(int)ushortX) emit "sthx %value, %left, %right" cost 4; - STORE1(addr:address, value:(int)ubyteX) + STOREB.I(addr:address, value:(int)ushortX) + emit "sth %value, %addr" + cost 4; + + STOREB.I(addr:address, value:(int)ubyteX) emit "stb %value, %addr" cost 4; - STORE1(ADD4(left:(int)reg, right:(int)reg), value:(int)ubyteX) + STOREB.I(ADD.I(left:(int)reg, right:(int)reg), value:(int)ubyteX) emit "stbx %value, %left, %right" cost 4; /* Loads */ - out:(int)reg = LOAD4(addr:address) + out:(int)reg = LOAD.I(addr:address) emit "lwz %out, %addr" cost 4; - out:(pair)reg = LOAD8(addr:address) + out:(long)reg = LOAD.L(addr:address) emit "lwz %out.0, 4+%addr" emit "lwz %out.1, 0+%addr" cost 8; - out:(int)ushort0 = LOAD2(addr:address) + out:(double)reg = LOAD.D(addr:address) + emit "lfsd %out, %addr" + cost 4; + + out:(int)ushort0 = LOADH.I(addr:address) emit "lhz %out, %addr" cost 4; - out:(int)ubyte0 = LOAD1(addr:address) + out:(int)ubyte0 = LOADB.I(addr:address) emit "lbz %out, %addr" cost 4; @@ -302,6 +327,38 @@ PATTERNS emit "! reg -> ushortX" cost 1; + +/* Extensions and conversions */ + + out:(int)reg = EXTENDB.I(in:(int)reg) + emit "extsb %out, %in" + cost 4; + + out:(int)reg = EXTENDH.I(in:(int)reg) + emit "extsh %out, %in" + cost 4; + + out:(int)reg = FROMSI.I(in:(int)reg) + with %out == %in + emit "! FROMSI.I(int) -> int" + cost 1; + + out:(int)reg = FROMUI.I(in:(int)reg) + with %out == %in + emit "! FROMUI.I(int) -> int" + cost 1; + + out:(long)reg = FROMSI.L(in:(int)reg) + emit "mr %out.0, %in" + emit "srawi %out.1, %out.0, 31" + cost 8; + + out:(int)reg = FROMD.I(in:(double)reg) + with corrupted(volatile) + emit "bl .fromd2i" + cost 4; + +#if 0 /* byte conversions */ out:(int)ubyte0 = CIU14(in:(int)ubyte0) @@ -348,22 +405,23 @@ PATTERNS out:(int)reg = CII24(in:(int)ushortX) emit "extsh %out, %in" cost 4; +#endif /* Locals */ - out:(int)reg = in:LOCAL4 + out:(int)reg = in:LOCAL.I emit "addi %out, fp, $in" cost 4; - address = in:LOCAL4 + address = in:LOCAL.I emit "$in(fp)"; /* Memory addressing modes */ - address = ADD4(addr:(int)reg, offset:CONST4) + address = ADD.I(addr:(int)reg, offset:CONST.I) when signed_constant(%offset, 16) emit "$offset(%addr)"; @@ -374,59 +432,59 @@ PATTERNS /* Branches */ - JUMP(addr:BLOCK4) + JUMP(addr:BLOCK.I) emit "b $addr" cost 4; - CJUMPEQ(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) + CJUMPEQ(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I)) emit "bc 12, 2, $true" /* IFTRUE EQ */ emit "b $false" cost 8; - CJUMPLE(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) + CJUMPLE(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I)) emit "bc 4, 1, $true" /* IFFALSE GT */ emit "b $false" cost 8; - CJUMPLT(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4)) + CJUMPLT(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I)) emit "bc 12, 0, $true" /* IFTRUE LT */ emit "b $false" cost 8; - CALL1(dest:LABEL4) + CALL(dest:LABEL.I) with corrupted(volatile) emit "bl $dest" cost 4; - out:(ret)reg = CALL4(dest:LABEL4) + out:(ret)reg = CALL.I(dest:LABEL.I) with corrupted(volatile) emit "bl $dest" cost 4; - out:(pret)reg = CALL8(dest:LABEL4) + out:(pret)reg = CALL.L(dest:LABEL.I) with corrupted(volatile) emit "bl $dest" cost 4; - CALL1(dest:(int)reg) + CALL(dest:(int)reg) with corrupted(volatile) emit "mtspr ctr, %dest" emit "bcctrl 20, 0, 0" cost 8; - out:(ret)reg = CALL4(dest:(int)reg) + out:(ret)reg = CALL.I(dest:(int)reg) with corrupted(volatile) emit "mtspr ctr, %dest" emit "bcctrl 20, 0, 0" cost 8; - out:(pret)reg = CALL8(dest:(int)reg) + out:(pret)reg = CALL.L(dest:(int)reg) with corrupted(volatile) emit "mtspr ctr, %dest" emit "bcctrl 20, 0, 0" cost 8; - JUMP(dest:LABEL4) + JUMP(dest:LABEL.I) emit "b $dest" cost 4; @@ -434,40 +492,40 @@ PATTERNS /* Comparisons */ - cr:(cr)cr = COMPARES44(left:(int)reg, right:(int)reg) + cr:(cr)cr = COMPARESI.I(left:(int)reg, right:(int)reg) emit "cmp %cr, 0, %left, %right" cost 4; - cr:(cr)cr = COMPARES44(left:(int)reg, right:CONST4) + cr:(cr)cr = COMPARESI.I(left:(int)reg, right:CONST.I) when signed_constant(%right, 16) emit "cmpi %cr, 0, %left, $right" cost 4; - cr:(cr)cr = COMPAREU44(left:(int)reg, right:(int)reg) + cr:(cr)cr = COMPAREUI.I(left:(int)reg, right:(int)reg) emit "cmpl %cr, 0, %left, %right" cost 4; - cr:(cr)cr = COMPAREU44(left:(int)reg, right:CONST4) + cr:(cr)cr = COMPAREUI.I(left:(int)reg, right:CONST.I) when signed_constant(%right, 16) emit "cmpli %cr, 0, %left, $right" cost 4; - out:(cr)cr = COMPARES44(in:(cr)cr, result:CONST4) + out:(cr)cr = COMPARESI.I(in:(cr)cr, result:CONST.I) when specific_constant(%result, 0) with %out == %in - emit "! COMPARES(cr, 0)" + emit "! COMPARESI.I(cr, 0)" cost 4; /* Booleans */ - out:(int)reg = IFEQ4(in:(cr)cr) + out:(int)reg = IFEQ.I(in:(cr)cr) emit "mfcr %out" /* get cr0 */ emit "rlwinm %out, %out, [32-2], 2, 31" /* extract just EQ */ cost 8; - out:(int)reg = IFEQ4(in:(int)reg) + out:(int)reg = IFEQ.I(in:(int)reg) emit "cntlzw %out, %in" /* returns 0..32 */ emit "rlwinm %out, %out, [32-5], 5, 31" /* if 32, return 1, otherwise 0 */ cost 8; @@ -476,6 +534,7 @@ PATTERNS /* Conversions */ +#if 0 out:(int)reg = CIU44(in:(int)reg) with %out == %in emit "! ciu44" @@ -485,7 +544,7 @@ PATTERNS with %out == %in emit "! cui44" cost 4; - +#endif /* ALU operations */ @@ -495,13 +554,13 @@ PATTERNS cost 4; \ #define ALUC(name, instr) \ - out:(int)reg = name(left:(int)reg, right:CONST4) \ + out:(int)reg = name(left:(int)reg, right:CONST.I) \ when signed_constant(%right, 16) \ emit instr " %out, %left, $right" \ cost 4; \ #define ALUC_reversed(name, instr) \ - out:(int)reg = name(left:CONST4, right:(int)reg) \ + out:(int)reg = name(left:CONST.I, right:(int)reg) \ when signed_constant(%left, 16) \ emit instr " %out, %right, $left" \ cost 4; \ @@ -510,66 +569,66 @@ PATTERNS ALUC(name, instr) \ ALUC_reversed(name, instr) - ALUR(ADD4, "add") - ALUCC(ADD4, "addi") + ALUR(ADD.I, "add") + ALUCC(ADD.I, "addi") - out:(int)reg = SUB4(left:(int)reg, right:(int)reg) + out:(int)reg = SUB.I(left:(int)reg, right:(int)reg) emit "subf %out, %left, %right" cost 4; - out:(int)reg = SUB4(left:(int)reg, right:CONST4) + out:(int)reg = SUB.I(left:(int)reg, right:CONST.I) emit "addi %out, %left, -[$right]" cost 4; - out:(int)reg = MOD4(left:(int)reg, right:(int)reg) + out:(int)reg = MOD.I(left:(int)reg, right:(int)reg) emit "divw %out, %left, %right" emit "mullw %out, %out, %right" emit "subf %out, %out, %left" cost 12; - out:(int)reg = MODU4(left:(int)reg, right:(int)reg) + out:(int)reg = MODU.I(left:(int)reg, right:(int)reg) emit "divwu %out, %left, %right" emit "mullw %out, %out, %right" emit "subf %out, %out, %left" cost 12; - ALUR(MUL4, "mullw") - ALUCC(MUL4, "mulli") + ALUR(MUL.I, "mullw") + ALUCC(MUL.I, "mulli") - ALUR(DIV4, "divw") - ALUR(DIVU4, "divwu") + ALUR(DIV.I, "divw") + ALUR(DIVU.I, "divwu") - ALUR(ASL4, "slw") + ALUR(ASL.I, "slw") - ALUR(LSL4, "slw") + ALUR(LSL.I, "slw") - out:(int)reg = NEG4(left:(int)reg) + out:(int)reg = NEG.I(left:(int)reg) emit "neg %out, %left" cost 4; - out:(int)reg = NOT4(left:(int)reg) + out:(int)reg = NOT.I(left:(int)reg) emit "cntlzw %out, %left" emit "rlwinm %out, %out, 32-5, 5, 31" cost 8; - ALUR(AND4, "and") - ALUCC(AND4, "andi.") + ALUR(AND.I, "and") + ALUCC(AND.I, "andi.") - ALUR(OR4, "or") - ALUCC(OR4, "ori") + ALUR(OR.I, "or") + ALUCC(OR.I, "ori") - ALUR(EOR4, "xor") - ALUCC(EOR4, "xori") + ALUR(EOR.I, "xor") + ALUCC(EOR.I, "xori") - out:(int)reg = value:LABEL4 + out:(int)reg = value:LABEL.I emit "la %out, $value" cost 4; - out:(int)reg = value:BLOCK4 + out:(int)reg = value:BLOCK.I emit "la %out, $value" cost 4; - out:(int)reg = value:CONST4 + out:(int)reg = value:CONST.I emit "li %out, $value" cost 8; @@ -586,46 +645,47 @@ PATTERNS emit instr " %out, %left, %right" \ cost 4; \ - out:(float)reg = LOADF4(addr:address) + out:(float)reg = LOAD.F(addr:address) emit "lfs %out, %addr" cost 4; - out:(double)reg = LOADF8(addr:address) + out:(double)reg = LOAD.D(addr:address) emit "lfd %out, %addr" cost 4; - out:(float)reg = value:CONSTF4 + out:(float)reg = value:CONST.F emit "lfs %out, address-containing-$value" cost 8; - FPU4R(ADDF4, "fadds") - FPU8R(ADDF8, "fadd") + FPU4R(ADDF.F, "fadds") + FPU8R(ADDF.D, "fadd") - FPU4R(SUBF4, "fsubs") - FPU8R(SUBF8, "fsub") + FPU4R(SUBF.F, "fsubs") + FPU8R(SUBF.D, "fsub") - FPU4R(MULF4, "fmuls") - FPU8R(MULF8, "fmul") + FPU4R(MULF.F, "fmuls") + FPU8R(MULF.D, "fmul") - FPU4R(DIVF4, "fdivs") - FPU8R(DIVF8, "fdiv") + FPU4R(DIVF.F, "fdivs") + FPU8R(DIVF.D, "fdiv") - out:(float)reg = NEGF4(left:(float)reg) + out:(float)reg = NEGF.F(left:(float)reg) emit "fneg %out, %left" cost 4; - out:(double)reg = NEGF8(left:(double)reg) + out:(double)reg = NEGF.D(left:(double)reg) emit "fneg %out, %left" cost 4; - cr:(cr)cr = COMPAREF44(left:(float)reg, right:(float)reg) + cr:(cr)cr = COMPAREF.I(left:(float)reg, right:(float)reg) emit "fcmpu %cr, %left, %right" cost 4; - cr:(cr)cr = COMPAREF84(left:(double)reg, right:(double)reg) + cr:(cr)cr = COMPARED.I(left:(double)reg, right:(double)reg) emit "fcmpu %cr, %left, %right" cost 4; + #if 0 out:(ret)reg = CFI44(val:(fret)reg) with corrupted(volatile) emit "bl .cfi44" @@ -653,6 +713,7 @@ PATTERNS out:(double)reg = CFF48(val:(float)reg) emit "fmr %out, %val" cost 1; + #endif /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index a8968c22f..59290d376 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -89,7 +89,6 @@ static void convert_block(struct basicblock* bb) { struct ir* ir = pushes.item[i].right; ir->opcode = IR_NOP; - ir->size = 0; } for (i=0; ilabel) { - case ir_to_esn(IR_REG, 1): - case ir_to_esn(IR_REG, 2): - case ir_to_esn(IR_REG, 4): - case ir_to_esn(IR_REG, 8): + case ir_to_esn(IR_REG, 0): current_hop->output = node->ir->result; break; - case ir_to_esn(IR_NOP, 0): + case ir_to_esn(IR_NOP, 'I'): + case ir_to_esn(IR_NOP, 'F'): + case ir_to_esn(IR_NOP, 'L'): + case ir_to_esn(IR_NOP, 'D'): current_hop->output = node->left->ir->result; break; } @@ -241,7 +241,7 @@ static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir) if (ir->root == root) { - node->label = ir_to_esn(ir->opcode, ir->size); + node->label = ir_to_esn(ir->opcode, ir->type); if (ir->left) node->left = build_shadow_tree(root, ir->left); diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 99f4928ef..260ad9294 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -63,11 +63,10 @@ static bool rewrite_loads_cb(struct ir* ir, void* user) if (ir->right && is_local(ir->right)) ir->right = definition; - /* Otherwise, go via a IR_REG (which should, with luck, turn into no code). */ + /* Otherwise, go via a IR_NOP (which should, with luck, turn into no code). */ if (is_local(ir)) { ir->opcode = IR_NOP; - ir->size = 0; ir->left = definition; ir->right = NULL; } @@ -108,7 +107,6 @@ static void recursively_rewrite_tree(struct basicblock* bb) if (ir->opcode == IR_STORE) { ir->opcode = IR_NOP; - ir->size = 0; ir->left = ir->right; ir->right = NULL; } diff --git a/mach/proto/mcg/pass_typeinference.c b/mach/proto/mcg/pass_typeinference.c index d330152ef..90a0ead1a 100644 --- a/mach/proto/mcg/pass_typeinference.c +++ b/mach/proto/mcg/pass_typeinference.c @@ -212,11 +212,11 @@ static struct ir* new_copy(char wanted, char real, struct ir* ir) if ((wanted == 'F') && (real == 'I')) opcode = IR_COPYI; else if ((wanted == 'D') && (real == 'L')) - opcode = IR_COPYI; + opcode = IR_COPYL; else if ((wanted == 'I') && (real == 'F')) opcode = IR_COPYF; else if ((wanted == 'L') && (real == 'D')) - opcode = IR_COPYF; + opcode = IR_COPYD; else fatal("type mismatch: parent IR wanted %c, child IR provided %c", wanted, real); diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 4ec1b46e0..b1b235f30 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -6,7 +6,7 @@ static int stackptr; static struct ir* stack[64]; static struct ir* lastcall; -static struct ir* convert(struct ir* src, int destsize, int opcodebase); +static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode); static struct ir* appendir(struct ir* ir); static void reset_stack(void) @@ -19,17 +19,22 @@ static void push(struct ir* ir) if (stackptr == sizeof(stack)/sizeof(*stack)) fatal("stack overflow"); +#if 0 /* If we try to push something which is too small, convert it to a word * first. */ if (ir->size < EM_wordsize) - ir = convert(ir, EM_wordsize, IR_CIU1); + ir = convertu(ir, EM_wordsize); +#endif stack[stackptr++] = ir; } static struct ir* pop(int size) { + if (size < EM_wordsize) + size = EM_wordsize; + if (stackptr == 0) { /* Nothing in our fake stack, so we have to read from the real stack. */ @@ -47,10 +52,12 @@ static struct ir* pop(int size) { struct ir* ir = stack[--stackptr]; +#if 0 /* If we try to pop something which is smaller than a word, convert it first. */ if (size < EM_wordsize) - ir = convert(ir, size, IR_CIU1); + ir = convertu(ir, size); +#endif if (ir->size != size) fatal("expected an item on stack of size %d, but got %d\n", size, ir->size); @@ -131,18 +138,39 @@ static struct ir* address_of_external(const char* label, arith offset) new_labelir(label); } -static struct ir* convert(struct ir* src, int destsize, int opcode) +static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode) { - switch (src->size) + if (srcsize == 1) { - case 1: opcode += 0; break; - case 2: opcode += 1; break; - case 4: opcode += 2; break; - case 8: opcode += 3; break; - default: - fatal("can't convert from things of size %d", src->size); + if ((opcode == IR_FROMSI) || (opcode == IR_FROMSL)) + { + src = new_ir1( + IR_EXTENDB, EM_wordsize, + src + ); + } + srcsize = EM_wordsize; } + if ((srcsize == 2) && (srcsize != EM_wordsize)) + { + if ((opcode == IR_FROMSI) || (opcode == IR_FROMSL)) + { + src = new_ir1( + IR_EXTENDH, EM_wordsize, + src + ); + } + srcsize = EM_wordsize; + } + + if (src->size == EM_wordsize) + {} + else if (src->size == (2*EM_wordsize)) + opcode++; + else + fatal("can't convert from %d to %d", src->size, destsize); + return new_ir1( opcode, destsize, @@ -153,15 +181,12 @@ static struct ir* convert(struct ir* src, int destsize, int opcode) static struct ir* compare(struct ir* left, struct ir* right, int size, int opcode) { - switch (size) - { - case 1: opcode += 0; break; - case 2: opcode += 1; break; - case 4: opcode += 2; break; - case 8: opcode += 3; break; - default: - fatal("can't compare things of size %d", size); - } + if (size == EM_wordsize) + {} + else if (size == (2*EM_wordsize)) + opcode++; + else + fatal("can't compare things of size %d", size); return new_ir2( @@ -170,6 +195,66 @@ static struct ir* compare(struct ir* left, struct ir* right, ); } +static struct ir* store(int size, struct ir* address, int offset, struct ir* value) +{ + int opcode; + + if (size == 1) + { + opcode = IR_STOREB; + size = EM_wordsize; + } + else if ((size < EM_wordsize) && (size == 2)) + { + opcode = IR_STOREH; + size = EM_wordsize; + } + else + opcode = IR_STORE; + + if (offset > 0) + address = new_ir2( + IR_ADD, EM_pointersize, + address, new_wordir(offset) + ); + + return + new_ir2( + opcode, size, + address, value + ); +} + +static struct ir* load(int size, struct ir* address, int offset) +{ + int opcode; + + if (size == 1) + { + opcode = IR_LOADB; + size = EM_wordsize; + } + else if ((size < EM_wordsize) && (size == 2)) + { + opcode = IR_LOADH; + size = EM_wordsize; + } + else + opcode = IR_LOAD; + + if (offset > 0) + address = new_ir2( + IR_ADD, EM_pointersize, + address, new_wordir(offset) + ); + + return + new_ir1( + opcode, size, + address + ); +} + static struct ir* tristate_compare(int size, int opcode) { struct ir* right = pop(size); @@ -197,7 +282,7 @@ static void simple_convert(int opcode) value = pop(srcsize->u.ivalue); push( - convert(value, destsize->u.ivalue, opcode) + convert(value, srcsize->u.ivalue, destsize->u.ivalue, opcode) ); } @@ -212,7 +297,7 @@ static void simple_branch2(int opcode, int size, appendir( new_ir2( irop, 0, - compare(left, right, size, IR_COMPARES1), + compare(left, right, size, IR_COMPARESI), new_ir2( IR_PAIR, 0, new_bbir(truebb), @@ -238,7 +323,7 @@ static void simple_test(int size, int irop) push( new_ir1( irop, EM_wordsize, - tristate_compare0(size, IR_COMPARES1) + tristate_compare0(size, IR_COMPARESI) ) ); } @@ -273,16 +358,16 @@ static void insn_simple(int opcode) break; } - case op_cii: simple_convert(IR_CII1); break; - case op_ciu: simple_convert(IR_CIU1); break; - case op_cui: simple_convert(IR_CUI1); break; - case op_cfi: simple_convert(IR_CFI1); break; - case op_cif: simple_convert(IR_CIF1); break; - case op_cff: simple_convert(IR_CFF1); break; + case op_cii: simple_convert(IR_FROMSI); break; + case op_ciu: simple_convert(IR_FROMSI); break; + case op_cui: simple_convert(IR_FROMUI); break; + case op_cfi: simple_convert(IR_FROMF); break; + case op_cif: simple_convert(IR_FROMSI); break; + case op_cff: simple_convert(IR_FROMF); break; case op_cmp: push( - tristate_compare(EM_pointersize, IR_COMPAREU1) + tristate_compare(EM_pointersize, IR_COMPAREUI) ); break; @@ -468,14 +553,12 @@ static struct ir* extract_block_refs(struct basicblock* bb) static void change_by(struct ir* address, int amount) { appendir( - new_ir2( - IR_STORE, EM_wordsize, - address, + store( + EM_wordsize, address, 0, new_ir2( IR_ADD, EM_wordsize, - new_ir1( - IR_LOAD, EM_wordsize, - address + load( + EM_wordsize, address, 0 ), new_wordir(amount) ) @@ -529,33 +612,33 @@ static void insn_ivalue(int opcode, arith value) case op_ngf: simple_alu1(opcode, value, IR_NEGF); break; case op_cmu: /* fall through */ - case op_cms: push(tristate_compare(value, IR_COMPAREU1)); break; - case op_cmi: push(tristate_compare(value, IR_COMPARES1)); break; - case op_cmf: push(tristate_compare(value, IR_COMPAREF1)); break; + case op_cms: push(tristate_compare(value, IR_COMPAREUI)); break; + case op_cmi: push(tristate_compare(value, IR_COMPARESI)); break; + case op_cmf: push(tristate_compare(value, IR_COMPAREF)); break; case op_lol: push( - new_ir1( - IR_LOAD, EM_wordsize, - new_localir(value) + load( + EM_wordsize, + new_localir(value), 0 ) ); break; case op_ldl: push( - new_ir1( - IR_LOAD, EM_wordsize*2, - new_localir(value) + load( + EM_wordsize*2, + new_localir(value), 0 ) ); break; case op_stl: appendir( - new_ir2( - IR_STORE, EM_wordsize, - new_localir(value), + store( + EM_wordsize, + new_localir(value), 0, pop(EM_wordsize) ) ); @@ -563,9 +646,9 @@ static void insn_ivalue(int opcode, arith value) case op_sdl: appendir( - new_ir2( - IR_STORE, EM_wordsize*2, - new_localir(value), + store( + EM_wordsize*2, + new_localir(value), 0, pop(EM_wordsize*2) ) ); @@ -579,24 +662,24 @@ static void insn_ivalue(int opcode, arith value) case op_lil: push( - new_ir1( - IR_LOAD, EM_wordsize, - new_ir1( - IR_LOAD, EM_pointersize, - new_localir(value) - ) + load( + EM_wordsize, + load( + EM_pointersize, + new_localir(value), 0 + ), 0 ) ); break; case op_sil: appendir( - new_ir2( - IR_STORE, EM_wordsize, - new_ir1( - IR_LOAD, EM_pointersize, - new_localir(value) - ), + store( + EM_wordsize, + load( + EM_pointersize, + new_localir(value), 0 + ), 0, pop(EM_wordsize) ) ); @@ -612,9 +695,9 @@ static void insn_ivalue(int opcode, arith value) case op_zrl: appendir( - new_ir2( - IR_STORE, EM_wordsize, - new_localir(value), + store( + EM_wordsize, + new_localir(value), 0, new_wordir(0) ) ); @@ -630,26 +713,18 @@ static void insn_ivalue(int opcode, arith value) case op_loe: push( - new_ir1( - IR_LOAD, EM_wordsize, - new_ir2( - IR_ADD, EM_pointersize, - new_labelir(".hol0"), - new_wordir(value) - ) + load( + EM_wordsize, + new_labelir(".hol0"), value ) ); break; case op_ste: appendir( - new_ir2( - IR_STORE, EM_wordsize, - new_ir2( - IR_ADD, EM_pointersize, - new_labelir(".hol0"), - new_wordir(value) - ), + store( + EM_wordsize, + new_labelir(".hol0"), value, pop(EM_wordsize) ) ); @@ -657,13 +732,9 @@ static void insn_ivalue(int opcode, arith value) case op_zre: appendir( - new_ir2( - IR_STORE, EM_wordsize, - new_ir2( - IR_ADD, EM_pointersize, - new_labelir(".hol0"), - new_wordir(value) - ), + store( + EM_wordsize, + new_labelir(".hol0"), value, new_wordir(0) ) ); @@ -694,9 +765,9 @@ static void insn_ivalue(int opcode, arith value) s = value; push( - new_ir1( - IR_LOAD, s, - ptradd(ptr, offset) + load( + s, + ptr, offset ) ); @@ -713,13 +784,9 @@ static void insn_ivalue(int opcode, arith value) struct ir* ptr = pop(EM_pointersize); push( - new_ir1( - IR_LOAD, EM_wordsize, - new_ir2( - IR_ADD, EM_pointersize, - ptr, - new_wordir(value) - ) + load( + EM_wordsize, + ptr, value ) ); break; @@ -731,9 +798,10 @@ static void insn_ivalue(int opcode, arith value) struct ir* val = pop(value); appendir( - new_ir2( - IR_STORE, value, - ptr, val + store( + value, + ptr, 0, + val ) ); break; @@ -745,13 +813,9 @@ static void insn_ivalue(int opcode, arith value) struct ir* val = pop(EM_wordsize); appendir( - new_ir2( - IR_STORE, EM_wordsize, - new_ir2( - IR_ADD, EM_pointersize, - ptr, - new_wordir(value) - ), + store( + EM_wordsize, + ptr, value, val ) ); @@ -764,7 +828,7 @@ static void insn_ivalue(int opcode, arith value) struct ir* ptr = pop(EM_pointersize); if (value != EM_pointersize) - off = convert(off, EM_pointersize, IR_CII1); + off = convert(off, value, EM_pointersize, IR_FROMUI); push( new_ir2( @@ -801,7 +865,7 @@ static void insn_ivalue(int opcode, arith value) ); if (value != EM_pointersize) - delta = convert(delta, value, IR_CII1); + delta = convert(delta, EM_pointersize, value, IR_FROMUI); push(delta); break; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 4844da073..691ffcb06 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -6,6 +6,7 @@ #include #include #include "iburg.h" +#include "astring.h" #define YYDEBUG 1 @@ -55,8 +56,9 @@ extern int yylex(void); %type pattern %type pattern_constraints %type pattern_emit -%type aliases; -%type names; +%type nodename +%type aliases +%type names %type qfragments %type terminfo %type rhs @@ -126,10 +128,15 @@ rhs ; terminfo - : ID { $$.name = $1; } - | '(' ID ')' ID { $$.attr = $2; $$.name = $4; } - | ID ':' ID { $$.label = $1; $$.name = $3; } - | ID ':' '(' ID ')' ID { $$.label = $1; $$.attr = $4; $$.name = $6; } + : nodename { $$.name = $1; } + | '(' ID ')' nodename { $$.attr = $2; $$.name = $4; } + | ID ':' nodename { $$.label = $1; $$.name = $3; } + | ID ':' '(' ID ')' nodename { $$.label = $1; $$.attr = $4; $$.name = $6; } + ; + +nodename + : ID { $$ = $1; } + | ID '.' ID { $$ = aprintf("%s.%s", $1, $3); } ; pattern_emit diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 146f920c3..f45043773 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -151,14 +151,20 @@ int main(int argc, char* argv[]) { const static struct terminfo reg = { "reg", NULL, "" }; const static struct terminfo REG = { "REG", NULL, NULL }; - const static struct terminfo NOP = { "NOP", NULL, NULL }; + const static struct terminfo NOPI = { "NOP.I", NULL, NULL }; + const static struct terminfo NOPF = { "NOP.F", NULL, NULL }; + const static struct terminfo NOPL = { "NOP.L", NULL, NULL }; + const static struct terminfo NOPD = { "NOP.D", NULL, NULL }; const static struct terminfo RET = { "RET", NULL, NULL }; nonterm("reg", true); rule(NULL, tree(®, NULL, NULL))->cost = 1; rule(®, tree(®, NULL, NULL))->cost = 1; - rule(®, tree(&NOP, tree(®, NULL, NULL), NULL))->cost = 1; + rule(®, tree(&NOPI, tree(®, NULL, NULL), NULL))->cost = 1; + rule(®, tree(&NOPF, tree(®, NULL, NULL), NULL))->cost = 1; + rule(®, tree(&NOPL, tree(®, NULL, NULL), NULL))->cost = 1; + rule(®, tree(&NOPD, tree(®, NULL, NULL), NULL))->cost = 1; rule(NULL, tree(&RET, NULL, NULL))->cost = 1; } @@ -195,10 +201,10 @@ int main(int argc, char* argv[]) return errcnt > 0; } -static void registerterminal(const struct ir_data* data, int iropcode, int size) +static void registerterminal(const struct ir_data* data, int iropcode, char type) { - const char* s = (size == 0) ? data->name : aprintf("%s%d", data->name, size); - int esn = ir_to_esn(iropcode, size); + const char* s = (type == 0) ? data->name : aprintf("%s.%c", data->name, type); + int esn = ir_to_esn(iropcode, type); term(s, esn); } @@ -209,15 +215,11 @@ static void registerterminals(void) for (i=0; i 2 +S I=I. EXTENDB +S I=I. EXTENDH +S I=I. TRUNCATEB +S I=I. TRUNCATEH # Tristate comparisons -S I=II COMPARES1 -S I=II COMPARES2 -S I=II COMPARES4 -S I=LL COMPARES8 - -S I=II COMPAREU1 -S I=II COMPAREU2 -S I=II COMPAREU4 -S I=LL COMPAREU8 - -S I=FF COMPAREF1 -S I=FF COMPAREF2 -S I=FF COMPAREF4 -S I=DD COMPAREF8 +# (order is important here; the 8-byte version of each must immediate succeed +# the 4-byte version) +S I=II COMPARESI +S I=LL COMPARESL +S I=II COMPAREUI +S I=LL COMPAREUL +S I=FF COMPAREF +S I=DD COMPARED # Tristate to boolean conversion S I=I. IFEQ diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index da0c8b1a1..9b0b876fd 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -3,14 +3,14 @@ /* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit. * - * Sizes are mapped as: 0=1, 1=1, 2=2, 4=3, 8=4. + * Types are mapped to: I=1, F=2, L=3, D=4 */ -#define ir_to_esn(iropcode, size) \ - ((iropcode)*4 + \ - (((size) == 4) ? 2 : \ - ((size) == 8) ? 3 : \ - ((size) == 0) ? 0 : \ - (size-1))) +#define ir_to_esn(iropcode, type) \ + ((iropcode)*5 + \ + (((type) == 'I') ? 1 : \ + ((type) == 'F') ? 2 : \ + ((type) == 'L') ? 3 : \ + ((type) == 'D') ? 4 : 0)) #define STATE_TYPE void* From b22780c075ddd4134410cbad5c76680babcd3104 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 23 Oct 2016 22:24:08 +0200 Subject: [PATCH 141/230] More opcodes, including the difficult and fairly stupid los/sts. --- mach/powerpc/mcg/table | 4 ++ mach/proto/mcg/parse_em.c | 7 +++ mach/proto/mcg/treebuilder.c | 97 +++++++++++++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 2c3565a73..448e1123e 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -194,6 +194,10 @@ PATTERNS emit "add sp, sp, %in" cost 4; + STACKADJUST.I(NEG.I(in:(int)reg)) + emit "subf sp, %in, sp" + cost 4; + out:(int)reg = GETFP.I emit "mr %out, fp" cost 4; diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 9551ecd02..26754b1e1 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -427,6 +427,13 @@ void parse_em(void) { switch (em.em_argtype) { + case 0: + /* This is an instruction which would normally + * take a size, but the size is provided on the + * stack. We hates them. */ + queue_insn_simple(em.em_opcode); + break; + case ilb_ptyp: queue_insn_ilabel(em.em_opcode, em.em_ilb); break; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index b1b235f30..82fae8655 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -371,8 +371,12 @@ static void insn_simple(int opcode) ); break; - case op_teq: simple_test(EM_wordsize, IR_IFEQ); break; + case op_teq: simple_test( EM_wordsize, IR_IFEQ); break; case op_tne: simple_test_neg(EM_wordsize, IR_IFEQ); break; + case op_tlt: simple_test( EM_wordsize, IR_IFLT); break; + case op_tge: simple_test_neg(EM_wordsize, IR_IFLT); break; + case op_tle: simple_test( EM_wordsize, IR_IFLE); break; + case op_tgt: simple_test_neg(EM_wordsize, IR_IFLE); break; case op_cai: { @@ -447,6 +451,20 @@ static void insn_simple(int opcode) break; } + /* FIXME: These instructions are really complex and barely used + * (Modula-2 bitset support, I believe). Leave them until leter. */ + case op_set: + case op_ior: + { + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(".unimplemented") + ) + ); + break; + } + case op_lni: { /* Increment line number --- ignore. */ @@ -1181,6 +1199,83 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_los: + { + /* Copy an arbitrary amount to the stack. */ + struct ir* bytes = pop(EM_wordsize); + struct ir* address = pop(EM_pointersize); + + materialise_stack(); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_ir1( + IR_NEG, EM_wordsize, + bytes + ) + ) + ); + + push( + new_ir0( + IR_GETSP, EM_pointersize + ) + ); + push(address); + push(bytes); + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir("memcpy") + ) + ); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_wordir(EM_pointersize*2 + EM_wordsize) + ) + ); + break; + } + + case op_sts: + { + /* Copy an arbitrary amount from the stack. */ + struct ir* bytes = pop(EM_wordsize); + struct ir* dest = pop(EM_pointersize); + struct ir* src; + + materialise_stack(); + src = appendir( + new_ir0( + IR_GETSP, EM_pointersize + ) + ); + + push(dest); + push(src); + push(bytes); + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir("memcpy") + ) + ); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_ir2( + IR_ADD, EM_wordsize, + new_wordir(EM_pointersize*2 + EM_wordsize), + bytes + ) + ) + ); + break; + } + case op_lin: { /* Set line number --- ignore. */ From a4644dee4dde586c07b7df1abda896bd9b2e85f2 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 24 Oct 2016 12:08:40 +0200 Subject: [PATCH 142/230] More opcodes. --- mach/proto/mcg/treebuilder.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 82fae8655..b64ff83ce 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -810,6 +810,19 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_ldf: + { + struct ir* ptr = pop(EM_pointersize); + + push( + load( + EM_wordsize*2, + ptr, value + ) + ); + break; + } + case op_sti: { struct ir* ptr = pop(EM_pointersize); @@ -840,6 +853,21 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_sdf: + { + struct ir* ptr = pop(EM_pointersize); + struct ir* val = pop(EM_wordsize*2); + + appendir( + store( + EM_wordsize*2, + ptr, value, + val + ) + ); + break; + } + case op_ads: { struct ir* off = pop(value); From 111c13e253ad5e500ac61d54ee2571446857b24b Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 24 Oct 2016 20:15:22 +0200 Subject: [PATCH 143/230] More opcodes. --- mach/powerpc/mcg/table | 30 ++++++++++++++++++++++++++++++ mach/proto/mcg/treebuilder.c | 26 ++++++++++++++++++++------ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 448e1123e..79e2f355c 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -177,6 +177,11 @@ PATTERNS emit "addi sp, sp, 4" cost 8; + out:(long)reg = POP.D + emit "lfd %out, 0(sp)" + emit "addi sp, sp, 8" + cost 8; + SETRET.I(in:(ret)reg) emit "! setret4" cost 1; @@ -231,6 +236,13 @@ PATTERNS emit "addi sp, sp, 8" cost 16; + out:(long)reg = COPYD.L(in:(double)reg) + emit "sfdu %in, -8(sp)" + emit "lwz %out.0, 4(sp)" + emit "lwz %out.1, 0(sp)" + emit "addi sp, sp, 8" + cost 16; + /* Memory operations */ @@ -362,6 +374,11 @@ PATTERNS emit "bl .fromd2i" cost 4; + out:(long)reg = FROMF.L(in:(double)reg) + with corrupted(volatile) + emit "bl .fromf2l" + cost 4; + #if 0 /* byte conversions */ @@ -534,6 +551,19 @@ PATTERNS emit "rlwinm %out, %out, [32-5], 5, 31" /* if 32, return 1, otherwise 0 */ cost 8; + out:(int)reg = IFLT.I(in:(cr)cr) + emit "mfcr %out" /* get cr0 */ + emit "andi. %out, %out, 1" /* leave just LT */ + cost 8; + + out:(int)reg = IFLE.I(in:(cr)cr) + emit "mfcr %out" /* get cr0 */ + emit "andi. %out, %out, 5" /* leave just LT and EQ */ + emit "cntlzw %out, %out" /* returns 0..32 */ + emit "rlwinm %out, %out, [32-5], 5, 31" /* if 32, return 1, otherwise 0 */ + emit "xori %out, %out, 1" /* negate */ + cost 8; + /* Conversions */ diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index b64ff83ce..66a69edef 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -361,6 +361,7 @@ static void insn_simple(int opcode) case op_cii: simple_convert(IR_FROMSI); break; case op_ciu: simple_convert(IR_FROMSI); break; case op_cui: simple_convert(IR_FROMUI); break; + case op_cfu: simple_convert(IR_FROMF); break; /* FIXME: technically wrong */ case op_cfi: simple_convert(IR_FROMF); break; case op_cif: simple_convert(IR_FROMSI); break; case op_cff: simple_convert(IR_FROMF); break; @@ -1058,12 +1059,12 @@ static void insn_ivalue(int opcode, arith value) } materialise_stack(); - push( - appendir( - new_ir1( - IR_CALL, EM_wordsize, - new_labelir(helper) - ) + /* No push here, because the helper function leaves the result on + * the physical stack (which is very dubious). */ + appendir( + new_ir1( + IR_CALL, EM_wordsize, + new_labelir(helper) ) ); break; @@ -1304,6 +1305,19 @@ static void insn_ivalue(int opcode, arith value) break; } + /* FIXME: These instructions are really complex and barely used + * (Modula-2 bitset support, I believe). Leave them until leter. */ + case op_inn: + { + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(".unimplemented") + ) + ); + break; + } + case op_lin: { /* Set line number --- ignore. */ From 45a7f2e9930f288ce3a89fca6eb347ae2384dd60 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 24 Oct 2016 22:14:08 +0200 Subject: [PATCH 144/230] Phi copies are now inserted as part of type inference. More opcodes. --- mach/powerpc/mcg/platform.c | 5 ++ mach/powerpc/mcg/table | 13 +++- mach/proto/mcg/pass_typeinference.c | 98 +++++++++++++++++++++-------- 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 664ed3848..725c9975a 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -184,6 +184,11 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest); break; + case burm_long_ATTR: + hop_add_insel(hop, "stw %0H, 4+%S(fp) ! %H", src, dest, dest); + hop_add_insel(hop, "stw %1H, 0+%S(fp) ! %H", src, dest, dest); + break; + case burm_double_ATTR: hop_add_insel(hop, "stfd %H, %S(fp) ! %H", src, dest, dest); break; diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 79e2f355c..39a5305cc 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -237,7 +237,7 @@ PATTERNS cost 16; out:(long)reg = COPYD.L(in:(double)reg) - emit "sfdu %in, -8(sp)" + emit "stfdu %in, -8(sp)" emit "lwz %out.0, 4(sp)" emit "lwz %out.1, 0(sp)" emit "addi sp, sp, 8" @@ -249,10 +249,14 @@ PATTERNS /* Stores */ + STORE.D(addr:address, value:(double)reg) + emit "sfd %value, %addr" + cost 4; + STORE.L(addr:address, value:(long)reg) emit "stw %value.0, 4+%addr" emit "stw %value.1, 0+%addr" - cost 4; + cost 8; STORE.I(addr:address, value:(int)reg) emit "stw %value, %addr" @@ -379,6 +383,11 @@ PATTERNS emit "bl .fromf2l" cost 4; + out:(long)reg = FROMSI.D(in:(double)reg) + with corrupted(volatile) + emit "bl .fromsi2d" + cost 4; + #if 0 /* byte conversions */ diff --git a/mach/proto/mcg/pass_typeinference.c b/mach/proto/mcg/pass_typeinference.c index 90a0ead1a..c081a4b3d 100644 --- a/mach/proto/mcg/pass_typeinference.c +++ b/mach/proto/mcg/pass_typeinference.c @@ -226,7 +226,37 @@ static struct ir* new_copy(char wanted, char real, struct ir* ir) return copy; } -static void insert_copies(void) +static void insert_copy(struct ir* ir, struct ir** child, char returntype, char childtype) +{ + if (*child) + { + char wanted; + char real; + + if ((returntype == '?') && (childtype == '?')) + { + wanted = ir->type; + real = (*child)->type; + } + else + { + wanted = effective_type(ir, childtype); + real = (*child)->type; + } + + if (wanted) + { + if (wanted != real) + { + struct ir* copy = new_copy(wanted, real, *child); + copy->root = ir->root; + *child = copy; + } + } + } +} + +static void insert_ir_copies(void) { int i; @@ -237,40 +267,54 @@ static void insert_copies(void) struct ir* ir = irs.item[i]; const struct ir_data* ird = &ir_data[ir->opcode]; - if (ir->left) - { - char wanted = effective_type(ir, ird->lefttype); - char real = ir->left->type; - - if (wanted && (wanted != real)) - { - struct ir* copy = new_copy(wanted, real, ir->left); - copy->root = ir->root; - ir->left = copy; - } - } - - if (ir->right) - { - char wanted = effective_type(ir, ird->righttype); - char real = ir->right->type; - - if (wanted && (wanted != real)) - { - struct ir* copy = new_copy(wanted, real, ir->right); - copy->root = ir->root; - ir->right = copy; - } - } + insert_copy(ir, &ir->left, ird->returntype, ird->lefttype); + insert_copy(ir, &ir->right, ird->returntype, ird->righttype); } } +static void insert_phi_copies(void) +{ + int i, j; + + /* If the child of a phi isn't the same type as the phi itself, we need to + * insert the copy at the end of the block that exported the value. */ + + for (i=0; iu.phivalue.count; j++) + { + struct ir* childir = ir->u.phivalue.item[j].right; + int wanted = ir->type; + int real = childir->type; + if (wanted != real) + { + struct basicblock* childbb = ir->u.phivalue.item[j].left; + struct ir* copy = new_copy(wanted, real, childir); + copy->root = copy; + + /* The copy gets inserted as the second last item of the child + * basic block. That way it'll happen before the final jump + * that exits the block. */ + + array_insert(&childbb->irs, copy, childbb->irs.count-1); + + /* And replace the value in the phi with our copy. */ + + ir->u.phivalue.item[j].right = copy; + } + } + } +} + void pass_infer_types(void) { collect_irs(); propagate_types(); assign_fallback_types(); - insert_copies(); + insert_ir_copies(); + insert_phi_copies(); } /* vim: set sw=4 ts=4 expandtab : */ From 9977ce841a3a218ae78fb83d9e2f257e12168973 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 25 Oct 2016 23:04:20 +0200 Subject: [PATCH 145/230] Remove the bytes1, bytes2, bytes4, bytes8 attributes; remove the concept of a register 'type'; now use int/float/long/double throughout to identify registers. Lots of register allocator tweaks and table bugfixes --- we now get through the dreading Mathlib.mod! --- mach/powerpc/mcg/platform.c | 37 ++-- mach/powerpc/mcg/table | 243 ++++++++++----------- mach/proto/mcg/pass_instructionselection.c | 14 +- mach/proto/mcg/pass_phigroups.c | 17 ++ mach/proto/mcg/pass_registerallocator.c | 57 +++-- mach/proto/mcg/reg.c | 8 +- mach/proto/mcg/reg.h | 1 - util/mcgg/gram.y | 3 +- util/mcgg/iburg.c | 12 +- util/mcgg/iburg.h | 3 +- util/mcgg/ircodes.h | 3 + util/mcgg/mcgg.h | 9 - 12 files changed, 207 insertions(+), 200 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 725c9975a..a049de3b6 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -59,9 +59,9 @@ struct hop* platform_prologue(void) for (i=0; itype & burm_int_ATTR) + if (hreg->attrs & burm_int_ATTR) hop_add_insel(hop, "stw %H, %d(fp)", hreg, saved_offset); - else if (hreg->type & burm_float_ATTR) + else if (hreg->attrs & burm_float_ATTR) hop_add_insel(hop, "stfs %H, %d(fp)", hreg, saved_offset); saved_offset += 4; } @@ -78,9 +78,9 @@ struct hop* platform_epilogue(void) for (i=0; itype & burm_int_ATTR) + if (hreg->attrs & burm_int_ATTR) hop_add_insel(hop, "lwz %H, %d(fp)", hreg, saved_offset); - else if (hreg->type & burm_float_ATTR) + else if (hreg->attrs & burm_float_ATTR) hop_add_insel(hop, "lfs %H, %d(fp)", hreg, saved_offset); saved_offset += 4; } @@ -98,15 +98,13 @@ struct hop* platform_epilogue(void) struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest) { struct hop* hop = new_hop(bb, NULL); - const uint32_t type_attrs = - burm_int_ATTR | burm_long_ATTR | burm_float_ATTR | burm_double_ATTR; - if ((src->type & type_attrs) != (dest->type & type_attrs)) + if ((src->attrs & TYPE_ATTRS) != (dest->attrs & TYPE_ATTRS)) { assert(!src->is_stacked); assert(!dest->is_stacked); - switch (src->type & type_attrs) + switch (src->attrs & TYPE_ATTRS) { case burm_int_ATTR: hop_add_insel(hop, "stwu %H, -4(sp)", src); @@ -126,10 +124,10 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* break; default: - assert(false); + goto nomove; } - switch (dest->type & type_attrs) + switch (dest->attrs & TYPE_ATTRS) { case burm_int_ATTR: hop_add_insel(hop, "lwz %H, 0(sp)", dest); @@ -149,10 +147,10 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* break; default: - assert(false); + goto nomove; } - switch (dest->type & type_attrs) + switch (dest->attrs & TYPE_ATTRS) { case burm_int_ATTR: case burm_float_ATTR: @@ -165,12 +163,12 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* break; default: - assert(false); + goto nomove; } } else { - uint32_t type = src->type & type_attrs; + uint32_t type = src->attrs & TYPE_ATTRS; if (!src->is_stacked && dest->is_stacked) { @@ -194,7 +192,7 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* break; default: - assert(false); + goto nomove; } } else if (src->is_stacked && !dest->is_stacked) @@ -214,7 +212,7 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* break; default: - assert(false); + goto nomove; } } else if (!src->is_stacked && !dest->is_stacked) @@ -236,14 +234,17 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* break; default: - assert(false); + goto nomove; } } else - assert(false); + goto nomove; } return hop; + +nomove: + fatal("cannot move %s to %s", src->id, dest->id); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 39a5305cc..0ffbc40f0 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -3,126 +3,129 @@ REGISTERS /* Registers are allocated top down; the order here is odd in order to make * sure that non-volatile registers get allocated from r31 (or f31) down. * - * Attributes ending in an exclamation mark must match exactly when copying - * a register into another register (e.g. for eviction). + * Attributes may have at most one of: int, float, long, double. These + * indicate that the register is used to store a value of that type. If + * your register can store more than one type, create an alias. Registers + * with none of these cannot be copied by the code generator (and so cannot + * be moved from register to register or spilt). */ - r12 bytes4! int! volatile; - r11 bytes4! int! volatile; - r10 bytes4! int! volatile; - r9 bytes4! int! volatile; - r8 bytes4! int! volatile; - r7 bytes4! int! volatile; - r6 bytes4! int! volatile; - r5 bytes4! int! volatile; - r4 bytes4! int! volatile; - r3 bytes4! int! volatile ret; + r12 int volatile; + r11 int volatile; + r10 int volatile; + r9 int volatile; + r8 int volatile; + r7 int volatile; + r6 int volatile; + r5 int volatile; + r4 int volatile; + r3 int volatile ret; - r31 bytes4! int!; - r30 bytes4! int!; - r29 bytes4! int!; - r28 bytes4! int!; - r27 bytes4! int!; - r26 bytes4! int!; - r25 bytes4! int!; - r24 bytes4! int!; - r23 bytes4! int!; - r22 bytes4! int!; - r21 bytes4! int!; - r20 bytes4! int!; - r19 bytes4! int!; - r18 bytes4! int!; - r17 bytes4! int!; - r16 bytes4! int!; - r15 bytes4! int!; - r14 bytes4! int!; - r13 bytes4! int!; + r31 int; + r30 int; + r29 int; + r28 int; + r27 int; + r26 int; + r25 int; + r24 int; + r23 int; + r22 int; + r21 int; + r20 int; + r19 int; + r18 int; + r17 int; + r16 int; + r15 int; + r14 int; + r13 int; - r11r12 named("r11", "r12") aliases(r11, r12) bytes8! long! volatile; - r9r10 named("r9", "r10") aliases(r9, r10) bytes8! long! volatile; - r7r8 named("r7", "r8") aliases(r7, r8) bytes8! long! volatile; - r5r6 named("r5", "r6") aliases(r6, r6) bytes8! long! volatile; - r3r4 named("r3", "r4") aliases(r3, r4) bytes8! long! volatile pret; + r11r12 named("r11", "r12") aliases(r11, r12) long volatile; + r9r10 named("r9", "r10") aliases(r9, r10) long volatile; + r7r8 named("r7", "r8") aliases(r7, r8) long volatile; + r5r6 named("r5", "r6") aliases(r6, r6) long volatile; + r3r4 named("r3", "r4") aliases(r3, r4) long volatile lret; - r29r30 named("r29", "r30") aliases(r29, r30) bytes8! long!; - r27r28 named("r27", "r28") aliases(r27, r28) bytes8! long!; - r25r26 named("r25", "r26") aliases(r25, r26) bytes8! long!; - r23r24 named("r23", "r24") aliases(r23, r24) bytes8! long!; - r21r22 named("r21", "r22") aliases(r21, r22) bytes8! long!; - r19r20 named("r19", "r20") aliases(r19, r20) bytes8! long!; - r17r18 named("r17", "r18") aliases(r17, r18) bytes8! long!; - r15r16 named("r15", "r16") aliases(r15, r16) bytes8! long!; - r13r14 named("r13", "r14") aliases(r13, r14) bytes8! long!; + r29r30 named("r29", "r30") aliases(r29, r30) long; + r27r28 named("r27", "r28") aliases(r27, r28) long; + r25r26 named("r25", "r26") aliases(r25, r26) long; + r23r24 named("r23", "r24") aliases(r23, r24) long; + r21r22 named("r21", "r22") aliases(r21, r22) long; + r19r20 named("r19", "r20") aliases(r19, r20) long; + r17r18 named("r17", "r18") aliases(r17, r18) long; + r15r16 named("r15", "r16") aliases(r15, r16) long; + r13r14 named("r13", "r14") aliases(r13, r14) long; - f14 bytes4! float! volatile; - f13 bytes4! float! volatile; - f12 bytes4! float! volatile; - f11 bytes4! float! volatile; - f10 bytes4! float! volatile; - f9 bytes4! float! volatile; - f8 bytes4! float! volatile; - f7 bytes4! float! volatile; - f6 bytes4! float! volatile; - f5 bytes4! float! volatile; - f4 bytes4! float! volatile; - f3 bytes4! float! volatile fret; - f2 bytes4! float! volatile; - f1 bytes4! float! volatile; - f0 bytes4! float! volatile; + f14 float volatile; + f13 float volatile; + f12 float volatile; + f11 float volatile; + f10 float volatile; + f9 float volatile; + f8 float volatile; + f7 float volatile; + f6 float volatile; + f5 float volatile; + f4 float volatile; + f3 float volatile fret; + f2 float volatile; + f1 float volatile; + f0 float volatile; - f31 bytes4! float!; - f30 bytes4! float!; - f29 bytes4! float!; - f28 bytes4! float!; - f27 bytes4! float!; - f26 bytes4! float!; - f25 bytes4! float!; - f24 bytes4! float!; - f23 bytes4! float!; - f22 bytes4! float!; - f21 bytes4! float!; - f20 bytes4! float!; - f19 bytes4! float!; - f18 bytes4! float!; - f17 bytes4! float!; - f16 bytes4! float!; - f15 bytes4! float!; + f31 float; + f30 float; + f29 float; + f28 float; + f27 float; + f26 float; + f25 float; + f24 float; + f23 float; + f22 float; + f21 float; + f20 float; + f19 float; + f18 float; + f17 float; + f16 float; + f15 float; - d14 named("f14") aliases(f14) bytes8! double! volatile; - d13 named("f13") aliases(f13) bytes8! double! volatile; - d12 named("f12") aliases(f12) bytes8! double! volatile; - d11 named("f11") aliases(f11) bytes8! double! volatile; - d10 named("f10") aliases(f10) bytes8! double! volatile; - d9 named("f9") aliases(f9) bytes8! double! volatile; - d8 named("f8") aliases(f8) bytes8! double! volatile; - d7 named("f7") aliases(f7) bytes8! double! volatile; - d6 named("f6") aliases(f6) bytes8! double! volatile; - d5 named("f5") aliases(f5) bytes8! double! volatile; - d4 named("f4") aliases(f4) bytes8! double! volatile; - d3 named("f3") aliases(f3) bytes8! double! volatile dret; - d2 named("f2") aliases(f2) bytes8! double! volatile; - d1 named("f1") aliases(f1) bytes8! double! volatile; - d0 named("f0") aliases(f0) bytes8! double! volatile; + d14 named("f14") aliases(f14) double volatile; + d13 named("f13") aliases(f13) double volatile; + d12 named("f12") aliases(f12) double volatile; + d11 named("f11") aliases(f11) double volatile; + d10 named("f10") aliases(f10) double volatile; + d9 named("f9") aliases(f9) double volatile; + d8 named("f8") aliases(f8) double volatile; + d7 named("f7") aliases(f7) double volatile; + d6 named("f6") aliases(f6) double volatile; + d5 named("f5") aliases(f5) double volatile; + d4 named("f4") aliases(f4) double volatile; + d3 named("f3") aliases(f3) double volatile dret; + d2 named("f2") aliases(f2) double volatile; + d1 named("f1") aliases(f1) double volatile; + d0 named("f0") aliases(f0) double volatile; - d31 named("f31") aliases(f31) bytes8! double!; - d30 named("f30") aliases(f30) bytes8! double!; - d29 named("f29") aliases(f29) bytes8! double!; - d28 named("f28") aliases(f28) bytes8! double!; - d27 named("f27") aliases(f27) bytes8! double!; - d26 named("f26") aliases(f26) bytes8! double!; - d25 named("f25") aliases(f25) bytes8! double!; - d24 named("f24") aliases(f24) bytes8! double!; - d23 named("f23") aliases(f23) bytes8! double!; - d22 named("f22") aliases(f22) bytes8! double!; - d21 named("f21") aliases(f21) bytes8! double!; - d20 named("f20") aliases(f20) bytes8! double!; - d19 named("f19") aliases(f19) bytes8! double!; - d18 named("f18") aliases(f18) bytes8! double!; - d17 named("f17") aliases(f17) bytes8! double!; - d16 named("f16") aliases(f16) bytes8! double!; - d15 named("f15") aliases(f15) bytes8! double!; + d31 named("f31") aliases(f31) double; + d30 named("f30") aliases(f30) double; + d29 named("f29") aliases(f29) double; + d28 named("f28") aliases(f28) double; + d27 named("f27") aliases(f27) double; + d26 named("f26") aliases(f26) double; + d25 named("f25") aliases(f25) double; + d24 named("f24") aliases(f24) double; + d23 named("f23") aliases(f23) double; + d22 named("f22") aliases(f22) double; + d21 named("f21") aliases(f21) double; + d20 named("f20") aliases(f20) double; + d19 named("f19") aliases(f19) double; + d18 named("f18") aliases(f18) double; + d17 named("f17") aliases(f17) double; + d16 named("f16") aliases(f16) double; + d15 named("f15") aliases(f15) double; - cr0 cr!; + cr0 cr; @@ -177,7 +180,7 @@ PATTERNS emit "addi sp, sp, 4" cost 8; - out:(long)reg = POP.D + out:(double)reg = POP.D emit "lfd %out, 0(sp)" emit "addi sp, sp, 8" cost 8; @@ -186,7 +189,7 @@ PATTERNS emit "! setret4" cost 1; - SETRET.L(in:(pret)reg) + SETRET.L(in:(lret)reg) emit "! setret8" cost 1; @@ -250,7 +253,7 @@ PATTERNS /* Stores */ STORE.D(addr:address, value:(double)reg) - emit "sfd %value, %addr" + emit "stfd %value, %addr" cost 4; STORE.L(addr:address, value:(long)reg) @@ -293,10 +296,6 @@ PATTERNS emit "lwz %out.1, 0+%addr" cost 8; - out:(double)reg = LOAD.D(addr:address) - emit "lfsd %out, %addr" - cost 4; - out:(int)ushort0 = LOADH.I(addr:address) emit "lhz %out, %addr" cost 4; @@ -373,17 +372,17 @@ PATTERNS emit "srawi %out.1, %out.0, 31" cost 8; - out:(int)reg = FROMD.I(in:(double)reg) + out:(ret)reg = FROMD.I(in:(dret)reg) with corrupted(volatile) emit "bl .fromd2i" cost 4; - out:(long)reg = FROMF.L(in:(double)reg) + out:(lret)reg = FROMF.L(in:(fret)reg) with corrupted(volatile) emit "bl .fromf2l" cost 4; - out:(long)reg = FROMSI.D(in:(double)reg) + out:(dret)reg = FROMSI.D(in:(ret)reg) with corrupted(volatile) emit "bl .fromsi2d" cost 4; @@ -491,7 +490,7 @@ PATTERNS emit "bl $dest" cost 4; - out:(pret)reg = CALL.L(dest:LABEL.I) + out:(lret)reg = CALL.L(dest:LABEL.I) with corrupted(volatile) emit "bl $dest" cost 4; @@ -508,7 +507,7 @@ PATTERNS emit "bcctrl 20, 0, 0" cost 8; - out:(pret)reg = CALL.L(dest:(int)reg) + out:(lret)reg = CALL.L(dest:(int)reg) with corrupted(volatile) emit "mtspr ctr, %dest" emit "bcctrl 20, 0, 0" diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index c95906081..525846878 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -94,9 +94,9 @@ static void constrain_input_reg(int child, uint32_t attr) struct vreg* vreg = find_vreg_of_child(child); struct constraint* c; - if (vreg) - array_appendu(¤t_hop->ins, vreg); + assert(vreg); + array_appendu(¤t_hop->ins, vreg); get_constraint(vreg)->attrs = attr; } @@ -112,7 +112,15 @@ static uint32_t find_type_from_constraint(uint32_t attr) while (brd->id) { if (brd->attrs & attr) - return brd->type; + { + const uint32_t type_attrs = + (burm_int_ATTR | burm_float_ATTR | + burm_long_ATTR | burm_double_ATTR); + + if (brd->attrs & type_attrs) + return brd->attrs & type_attrs; + return attr; + } brd++; } diff --git a/mach/proto/mcg/pass_phigroups.c b/mach/proto/mcg/pass_phigroups.c index 41fa6e093..dfff73faa 100644 --- a/mach/proto/mcg/pass_phigroups.c +++ b/mach/proto/mcg/pass_phigroups.c @@ -36,6 +36,7 @@ static void recursively_associate_group(struct phicongruence* c, struct vreg* vr struct constraint* constraint = pmap_findleft(&vreg->defined->constraints, vreg); if (c->type == 0) c->type = vreg->type; + assert(c->type == vreg->type); array_appendu(&c->definitions, vreg->defined); @@ -62,6 +63,21 @@ static void recursively_associate_group(struct phicongruence* c, struct vreg* vr } } +static void update_vreg_types(struct phicongruence* c) +{ + int i; + + for (i=0; ivregs.count; i++) + { + struct vreg* vreg = c->vregs.item[i]; + + if (vreg->type == 0) + vreg->type = c->type; + assert(vreg->type == c->type); + assert(vreg->type != 0); + } +} + static void associate_groups(void) { static int number = 0; @@ -71,6 +87,7 @@ static void associate_groups(void) struct phicongruence* c = calloc(1, sizeof(*c)); c->id = number++; recursively_associate_group(c, phimap.item[0].left); + update_vreg_types(c); } } diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 5d9e702fc..fd10b22a0 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -84,7 +84,7 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs, for (i=0; itype == type)) + if (!register_used(regs, hreg) && (hreg->attrs & type)) { /* This one is unused. Use it. */ return hreg; @@ -95,11 +95,6 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs, assert(false); } -static bool evictable(struct hreg* hreg, struct vreg* vreg) -{ - return type_match(hreg, vreg) && !array_contains(¤t_hop->ins, vreg); -} - static struct hreg* evict(struct vreg* vreg) { int i; @@ -114,7 +109,7 @@ static struct hreg* evict(struct vreg* vreg) struct vreg* candidatein = pmap_findleft(current_ins, hreg); struct vreg* candidateout = pmap_findleft(current_outs, hreg); - if (evictable(hreg, vreg)) + if (hreg->attrs & vreg->type) { if (!candidatein && !candidateout && @@ -141,41 +136,47 @@ static struct hreg* evict(struct vreg* vreg) assert(false); } -static bool type_match(struct hreg* hreg, struct vreg* vreg) +static bool constraints_match(struct hreg* hreg, struct vreg* vreg) { struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); if (c) return (hreg->attrs & c->attrs); - if (vreg->congruence) - return (hreg->type == vreg->congruence->type); - return (hreg->type == vreg->type); + return true; } static bool allocatable_stackable_input(struct hreg* hreg, struct vreg* vreg) { return !register_used(current_ins, hreg) && - type_match(hreg, vreg); + (hreg->attrs & vreg->type); } static bool allocatable_stackable_output(struct hreg* hreg, struct vreg* vreg) { return !register_used(current_outs, hreg) && - type_match(hreg, vreg) && + (hreg->attrs & vreg->type) && !(hreg->attrs & current_hop->insndata->corrupts); } static bool allocatable_input(struct hreg* hreg, struct vreg* vreg) { return allocatable_stackable_input(hreg, vreg) && + constraints_match(hreg, vreg) && !hreg->is_stacked; } static bool allocatable_output(struct hreg* hreg, struct vreg* vreg) { return allocatable_stackable_output(hreg, vreg) && + constraints_match(hreg, vreg) && !hreg->is_stacked; } +static bool allocatable_through(struct hreg* hreg, struct vreg* vreg) +{ + return allocatable_stackable_input(hreg, vreg) && + allocatable_stackable_output(hreg, vreg); +} + static struct hreg* find_input_reg(struct vreg* vreg) { int i; @@ -218,8 +219,7 @@ static struct hreg* find_through_reg(struct vreg* vreg) for (i=0; itype; + uint32_t srctype = vreg->type; struct hreg* hreg; int i; @@ -391,9 +391,8 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s for (i=0; itype == src->type) && - allocatable_stackable_input(hreg, vreg) && - allocatable_stackable_output(hreg, vreg)) + if ((hreg->attrs & srctype) && + allocatable_through(hreg, vreg)) { goto found; } @@ -401,7 +400,7 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s /* No more registers --- allocate a stack slot. */ - hreg = new_stacked_hreg(src->type); + hreg = new_stacked_hreg(srctype); array_append(&hregs, hreg); found: @@ -725,7 +724,7 @@ static int pack_stackframe(int stacksize, int size, uint32_t attr) for (i=0; iis_stacked && (hreg->type & attr)) + if (hreg->is_stacked && (hreg->attrs & attr)) { hreg->offset = stacksize; stacksize += size; @@ -738,10 +737,10 @@ static int pack_stackframe(int stacksize, int size, uint32_t attr) static void layout_stack_frame(void) { int stacksize = 0; - stacksize = pack_stackframe(stacksize, 8, burm_bytes8_ATTR); - stacksize = pack_stackframe(stacksize, 4, burm_bytes4_ATTR); - stacksize = pack_stackframe(stacksize, 2, burm_bytes2_ATTR); - stacksize = pack_stackframe(stacksize, 1, burm_bytes1_ATTR); + stacksize = pack_stackframe(stacksize, EM_wordsize*2, burm_double_ATTR); + stacksize = pack_stackframe(stacksize, EM_wordsize*2, burm_long_ATTR); + stacksize = pack_stackframe(stacksize, EM_wordsize*1, burm_float_ATTR); + stacksize = pack_stackframe(stacksize, EM_wordsize*1, burm_int_ATTR); current_proc->spills_size = stacksize; } diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c index 8af8079e2..d40deb171 100644 --- a/mach/proto/mcg/reg.c +++ b/mach/proto/mcg/reg.c @@ -14,20 +14,18 @@ struct hreg* new_hreg(const struct burm_register_data* brd) struct hreg* hreg = calloc(1, sizeof *hreg); hreg->id = brd->id; hreg->brd = brd; - hreg->type = brd->type; hreg->attrs = brd->attrs; hreg->is_stacked = false; /* The aliases array needs to be initialised later. */ return hreg; } -struct hreg* new_stacked_hreg(uint32_t type) +struct hreg* new_stacked_hreg(uint32_t attrs) { static int hreg_count = 1; struct hreg* hreg = calloc(1, sizeof *hreg); - hreg->id = aprintf("stacked_%d_id_%d", type, hreg_count++); - hreg->type = type; - hreg->attrs = type; + hreg->id = aprintf("stacked_%d_id_%d", attrs, hreg_count++); + hreg->attrs = attrs; hreg->is_stacked = true; hreg->offset = -1; array_append(&hreg->aliases, hreg); diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index f449b7e19..00c8220b5 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -15,7 +15,6 @@ struct hreg { const char* id; const struct burm_register_data* brd; - uint32_t type; uint32_t attrs; bool is_stacked; int offset; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 691ffcb06..99fdeda95 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -80,8 +80,7 @@ register : ID { $$ = makereg($1); } | register NAMED '(' names ')' { $$ = $1; setregnames($$, $4); } | register ALIASES '(' aliases ')' { $$ = $1; addregaliases($$, $4); } - | register ID { $$ = $1; addregattr($1, $2, false); } - | register ID '!' { $$ = $1; addregattr($1, $2, true); } + | register ID { $$ = $1; addregattr($1, $2); } ; names diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index f45043773..55a24e717 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -141,10 +141,6 @@ int main(int argc, char* argv[]) registerterminals(); start = nonterm("stmt", true); - makeregattr("bytes1"); - makeregattr("bytes2"); - makeregattr("bytes4"); - makeregattr("bytes8"); /* Define some standard terms. */ @@ -309,7 +305,7 @@ struct regattr* makeregattr(const char* id) return p; } -void addregattr(struct reg* reg, const char* id, bool exact) +void addregattr(struct reg* reg, const char* id) { struct regattr* p = smap_get(®isterattrs, id); @@ -317,8 +313,6 @@ void addregattr(struct reg* reg, const char* id, bool exact) p = makeregattr(id); reg->attrs |= 1<<(p->number); - if (exact) - reg->type |= 1<<(p->number); } void addregalias(struct reg* r1, struct reg* r2) @@ -663,8 +657,8 @@ static void emitregisters(void) struct reg* r = registers.item[i].right; assert(r->number == i); - print("%1{ \"%s\", 0x%x, 0x%x, %Pregister_names_%d_%s, %Pregister_aliases_%d_%s },\n", - r->name, r->type, r->attrs, i, r->name, i, r->name); + print("%1{ \"%s\", 0x%x, %Pregister_names_%d_%s, %Pregister_aliases_%d_%s },\n", + r->name, r->attrs, i, r->name, i, r->name); } print("%1{ NULL }\n"); print("};\n\n"); diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index e0bbeef57..8ba4f5ab9 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -61,7 +61,6 @@ struct reg const char* name; /* friendly register name */ int number; /* identifying number */ uint32_t attrs; /* bitfield of register attributes */ - uint32_t type; /* register type */ struct stringlist* names; /* register names */ ARRAYOF(struct reg) aliases; /* registers that this one aliases */ }; @@ -74,7 +73,7 @@ struct regattr extern struct reg* makereg(const char* name); extern void setregnames(struct reg* reg, struct stringlist* names); -extern void addregattr(struct reg* reg, const char* regattr, bool exact); +extern void addregattr(struct reg* reg, const char* regattr); extern void addregaliases(struct reg* reg, struct stringlist* aliases); extern struct regattr* getregattr(const char* name); diff --git a/util/mcgg/ircodes.h b/util/mcgg/ircodes.h index 7d91b27fd..d9c05126f 100644 --- a/util/mcgg/ircodes.h +++ b/util/mcgg/ircodes.h @@ -17,6 +17,9 @@ struct ir_data extern const struct ir_data ir_data[]; +#define TYPE_ATTRS \ + (burm_int_ATTR | burm_long_ATTR | burm_float_ATTR | burm_double_ATTR) + #include "ircodes-dyn.h" #endif diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 9b0b876fd..a068fa660 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -64,7 +64,6 @@ extern const struct burm_instruction_data burm_instruction_data[]; struct burm_register_data { const char* id; - uint32_t type; uint32_t attrs; const char** names; const struct burm_register_data** aliases; @@ -73,14 +72,6 @@ struct burm_register_data extern const struct burm_register_data burm_register_data[]; extern const char* burm_register_class_names[]; -enum -{ - REGATTR_BYTES1 = 0, - REGATTR_BYTES2, - REGATTR_BYTES4, - REGATTR_BYTES8 -}; - enum { NONTERM_STMT = 1 From 51bd3ee4dd0aa7d83494f03fc7d836699dbee54a Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 27 Oct 2016 21:40:25 +0200 Subject: [PATCH 146/230] Fix bug where some phis weren't being inserted when a given variable definition needed more than one phi (due to the dominance frontier containing more than one basic block). --- mach/proto/mcg/pass_ssa.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 260ad9294..e0f835f17 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -185,12 +185,16 @@ static void ssa_convert(void) for (i=0; ioffset, bb->name); + for (j=0; joffset, dominates->name); + if (dominancefrontiers.item[j].left == bb) + { + struct basicblock* dominates = dominancefrontiers.item[j].right; + array_appendu(&needsphis, dominates); + array_appendu(&defining, dominates); + tracef('S', "S: local %d needs phi in block %s\n", current_local->offset, dominates->name); + } } } From be3dece5af1ec2bb063298226aeffef1add88a02 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 27 Oct 2016 21:48:46 +0200 Subject: [PATCH 147/230] Allow emission of strings containing ". --- mach/proto/mcg/data.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index 38525b724..6b6fc084f 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -74,6 +74,11 @@ void data_float(const char* data, size_t size, bool is_ro) fprintf(outputfile, "\n"); } +static bool istext(c) +{ + return isprint(c) && (c != '"'); +} + void data_block(const uint8_t* data, size_t size, bool is_ro) { const uint8_t* start = data; @@ -85,7 +90,7 @@ void data_block(const uint8_t* data, size_t size, bool is_ro) start = p = data; while (p < end) { - while ((p < end) && isprint(*p)) + while ((p < end) && istext(*p)) p++; if (start < p) @@ -99,7 +104,7 @@ void data_block(const uint8_t* data, size_t size, bool is_ro) fprintf(outputfile, "\"\n"); } - while ((p < end) && !isprint(*p)) + while ((p < end) && !istext(*p)) p++; if (start < p) From 81525c0f2c13e9ec5c71b32ebcbf0da61ff9a2de Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 27 Oct 2016 21:50:58 +0200 Subject: [PATCH 148/230] Swaps work (at least for registers). More opcodes. Rearrange the stack layout so we can always trivially find fp, which lets CHAINFP work. --- mach/powerpc/mcg/platform.c | 59 +++++++++++++++++++++---- mach/powerpc/mcg/table | 10 +++-- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_registerallocator.c | 19 ++------ 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index a049de3b6..7d8499e0b 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -4,15 +4,19 @@ * * | ...params... * | --------------- <- ab - * | saved regs + * | spills * | --------------- - * | spills + * | saved regs + * | LR + * | FP * | --------------- <- st, fp (a.k.a. lb) * | locals * | --------------- <- sp * V ...user area... * * st indexes up; lb indexes down. + * + * We ensure that dereferencing fp always produces the caller's fp. */ static ARRAYOF(struct hreg) saved_regs; @@ -51,11 +55,12 @@ struct hop* platform_prologue(void) hop_add_insel(hop, "addi sp, sp, %d", -(current_proc->fp_to_ab + current_proc->locals_size)); hop_add_insel(hop, "mfspr r0, lr"); - hop_add_insel(hop, "stw r0, %d(sp)", current_proc->locals_size + current_proc->spills_size); - hop_add_insel(hop, "stw fp, %d(sp)", current_proc->locals_size + current_proc->spills_size + 4); + hop_add_insel(hop, "stw fp, %d(sp)", current_proc->locals_size + 0); + hop_add_insel(hop, "stw r0, %d(sp)", current_proc->locals_size + 4); hop_add_insel(hop, "addi fp, sp, %d", current_proc->locals_size); - saved_offset = current_proc->spills_size + 8; + /* Saved reg offsets are negative. */ + saved_offset = current_proc->saved_size + 8; for (i=0; ispills_size + 8; + /* Saved reg offsets are negative. */ + saved_offset = current_proc->saved_size + 8; for (i=0; ispills_size); + hop_add_insel(hop, "lwz r0, 4(fp)"); hop_add_insel(hop, "mtspr lr, r0"); - hop_add_insel(hop, "lwz r0, %d(fp)", current_proc->spills_size + 4); + hop_add_insel(hop, "lwz r0, 0(fp)"); /* load old fp */ hop_add_insel(hop, "addi sp, fp, %d", current_proc->fp_to_ab); hop_add_insel(hop, "mr fp, r0"); hop_add_insel(hop, "bclr 20, 0, 0"); @@ -247,5 +253,42 @@ nomove: fatal("cannot move %s to %s", src->id, dest->id); } +struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + assert(!src->is_stacked); + assert(!dest->is_stacked); + assert((src->attrs & TYPE_ATTRS) == (dest->attrs & TYPE_ATTRS)); + + switch (src->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + hop_add_insel(hop, "mr r0, %H", src); + hop_add_insel(hop, "mr %H, %H", src, dest); + hop_add_insel(hop, "mr %H, r0", dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "mr r0, %0H", src); + hop_add_insel(hop, "mr %0H, %0H", src, dest); + hop_add_insel(hop, "mr %0H, r0", dest); + + hop_add_insel(hop, "mr r0, %1H", src); + hop_add_insel(hop, "mr %1H, %1H", src, dest); + hop_add_insel(hop, "mr %1H, r0", dest); + break; + + case burm_float_ATTR: + case burm_double_ATTR: + hop_add_insel(hop, "fmr f0, %H", src); + hop_add_insel(hop, "fmr %H, %H", src, dest); + hop_add_insel(hop, "fmr %H, f0", dest); + break; + } + + return hop; +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 0ffbc40f0..5b97ae4d9 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -210,6 +210,10 @@ PATTERNS emit "mr %out, fp" cost 4; + out:(int)reg = CHAINFP.I(in:(int)reg) + emit "lwz %out, 0(%in)" + cost 4; + out:(int)reg = FPTOARGS.I(GETFP.I) emit "addi %out, fp, 8" cost 4; @@ -641,8 +645,10 @@ PATTERNS ALUR(DIVU.I, "divwu") ALUR(ASL.I, "slw") + ALUR(ASR.I, "sraw") ALUR(LSL.I, "slw") + ALUR(LSR.I, "srw") out:(int)reg = NEG.I(left:(int)reg) emit "neg %out, %left" @@ -694,10 +700,6 @@ PATTERNS out:(double)reg = LOAD.D(addr:address) emit "lfd %out, %addr" cost 4; - - out:(float)reg = value:CONST.F - emit "lfs %out, address-containing-$value" - cost 8; FPU4R(ADDF.F, "fadds") FPU8R(ADDF.D, "fadd") diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index c60dee9ce..13a3d236e 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -123,6 +123,7 @@ extern void platform_calculate_offsets(void); extern struct hop* platform_prologue(void); extern struct hop* platform_epilogue(void); extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest); +extern struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest); extern FILE* outputfile; extern FILE* dominance_dot_file; diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index fd10b22a0..0a6eba638 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -578,19 +578,6 @@ static void assign_hregs_to_vregs(void) } } -static struct hop* create_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) -{ - struct hop* hop = new_hop(bb, NULL); - - hop_add_string_insel(hop, "! swap "); - hop_add_hreg_insel(hop, src, 0); - hop_add_string_insel(hop, " <-> "); - hop_add_hreg_insel(hop, dest, 0); - hop_add_eoi_insel(hop); - - return hop; -} - /* returns the number of instructions inserted */ static int insert_moves(struct basicblock* bb, int index, register_assignment_t* srcregs, register_assignment_t* destregs) @@ -640,12 +627,12 @@ static int insert_moves(struct basicblock* bb, int index, } else { - /* Swap. */ + /* There's nowhere to copy to --- the copies that are left form a cycle. + * So we need to swap instead. */ - assert(false); src = copies.item[0].left; dest = pmap_findleft(&copies, src); - hop = create_swap(bb, src, dest); + hop = platform_swap(bb, src, dest); pmap_remove(&copies, src, dest); pmap_remove(&copies, dest, src); } From 658db4ba719582f4b9dfbdd6c79f32e431f9b5ca Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 27 Oct 2016 23:17:16 +0200 Subject: [PATCH 149/230] Mangle label names (turns out that the ACK assembler can't really cope with labels that are the same name as instructions...). --- mach/powerpc/mcg/platform.c | 12 ++++++++++++ mach/proto/mcg/basicblock.c | 2 +- mach/proto/mcg/data.c | 2 +- mach/proto/mcg/hop.c | 4 ++-- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_instructionselection.c | 6 ++++-- mach/proto/mcg/procedure.c | 14 +++++++------- 7 files changed, 28 insertions(+), 13 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 7d8499e0b..4a77118ca 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -290,5 +290,17 @@ struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* return hop; } +const char* platform_label(const char* label) +{ + /* Labels starting with . are internal, not exported, and don't need mangling. */ + + if (label[0] == '.') + return label; + + /* Otherwise, mangle. */ + + return aprintf("_%s", label); +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/basicblock.c b/mach/proto/mcg/basicblock.c index 5a30d9a90..aa0a729e0 100644 --- a/mach/proto/mcg/basicblock.c +++ b/mach/proto/mcg/basicblock.c @@ -20,7 +20,7 @@ struct basicblock* bb_get(const char* name) struct idf* p; if (!name) - name = aprintf("___anon_bb_%d", next_id++); + name = aprintf(".anon_bb_%d", next_id++); p = str2idf((char*) name, 0); if (!p->block) { diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index 6b6fc084f..2e6fde9b2 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -44,7 +44,7 @@ static void emit_header(int desired_section) fatal("label '%s' can't change sections", pending->name); fprintf(outputfile, "\n.sect %s\n", section_to_str(pending->section)); - fprintf(outputfile, "%s:\n", pending->name); + fprintf(outputfile, "%s:\n", platform_label(pending->name)); pending = NULL; } } diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 02f6b2930..1afa04c50 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -265,11 +265,11 @@ char* hop_render(struct hop* hop) switch (ir->opcode) { case IR_BLOCK: - appendf("%s", ir->u.bvalue->name); + appendf("%s", platform_label(ir->u.bvalue->name)); break; case IR_LABEL: - appendf("%s", ir->u.lvalue); + appendf("%s", platform_label(ir->u.lvalue)); break; case IR_LOCAL: diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 13a3d236e..08f6828bf 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -124,6 +124,7 @@ extern struct hop* platform_prologue(void); extern struct hop* platform_epilogue(void); extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest); extern struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest); +extern const char* platform_label(const char* label); extern FILE* outputfile; extern FILE* dominance_dot_file; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 525846878..2bf5e5b59 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -220,6 +220,7 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) { case ir_to_esn(IR_REG, 0): current_hop->output = node->ir->result; + assert(current_hop->output != NULL); break; case ir_to_esn(IR_NOP, 'I'): @@ -227,6 +228,7 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) case ir_to_esn(IR_NOP, 'L'): case ir_to_esn(IR_NOP, 'D'): current_hop->output = node->left->ir->result; + assert(current_hop->output != NULL); break; } } @@ -314,9 +316,9 @@ void pass_instruction_selector(void) { int i; - for (i=0; iname); + fprintf(outputfile, "%s:\n", platform_label(bb->name)); for (j=0; jhops.count; j++) { struct hop* hop = bb->hops.item[j]; @@ -128,12 +128,12 @@ static void write_cfg_graph(const char* name) { int i; - fprintf(cfg_dot_file, "subgraph %s {\n", name); - fprintf(cfg_dot_file, "\t%s [color=red];\n", cfg.entry->name); + fprintf(cfg_dot_file, "subgraph \"%s\" {\n", name); + fprintf(cfg_dot_file, "\t\"%s\" [color=red];\n", cfg.entry->name); for (i=0; i %s;\n", + fprintf(cfg_dot_file, "\t\"%s\" -> \"%s\";\n", cfg.graph.item[i].left->name, cfg.graph.item[i].right->name); } @@ -145,12 +145,12 @@ static void write_dominance_graph(const char* name) { int i; - fprintf(dominance_dot_file, "subgraph %s {\n", name); - fprintf(dominance_dot_file, "\t%s [color=green];\n", cfg.entry->name); + fprintf(dominance_dot_file, "subgraph \"%s\" {\n", name); + fprintf(dominance_dot_file, "\t\"%s\" [color=green];\n", cfg.entry->name); for (i=0; i %s;\n", + fprintf(dominance_dot_file, "\t\"%s\" -> \"%s\";\n", dominance.graph.item[i].right->name, dominance.graph.item[i].left->name); } From bfa65168e27005b685e6085ee1f3a0a10a7cd01e Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 29 Oct 2016 10:55:48 +0200 Subject: [PATCH 150/230] Don't generate phis if unnecessary (because this breaks the critical-edge-splitting guarantee and causes insertion of phi copies to fail). --- mach/proto/mcg/pass_convertstackops.c | 30 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index 59290d376..49da42226 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -95,15 +95,31 @@ static void convert_block(struct basicblock* bb) { struct basicblock* outbb = pops.item[i].left; struct ir* ir = pops.item[i].right; - struct ir* phi = new_ir0(IR_PHI, ir->size); - for (j=0; ju.phivalue, - pushes.item[j].left, - pushes.item[j].right); - phi->root = phi; + assert(pushes.count > 0); + if (pushes.count == 1) + { + /* The push happened in exactly one place; that means we don't need a phi and can + * just import the value directly. */ - *ir = *phi; + struct ir* src = pushes.item[0].right; + ir->opcode = IR_NOP; + ir->left = src; + } + else + { + /* The push could have happened in one of several places; we need a phi. */ + + struct ir* phi = new_ir0(IR_PHI, ir->size); + for (j=0; ju.phivalue, + pushes.item[j].left, + pushes.item[j].right); + } + phi->root = phi; + *ir = *phi; + } } } } From 2cc2c0ae98e0b7be4ea803ff8a3ec5ea20e1de97 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 29 Oct 2016 11:57:56 +0200 Subject: [PATCH 151/230] Lots more opcodes. Rearrange the stack layout so that fp->ab is a fixed value (needed for CHAINFP and FPTOAB). Wire up lfrs to calls via a phi when necessary, to allow call-bra-lfr chains. --- mach/powerpc/mcg/platform.c | 30 +++-- mach/powerpc/mcg/table | 155 +++++++-------------- mach/proto/mcg/hop.c | 6 + mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_livevreganalysis.c | 2 + mach/proto/mcg/pass_registerallocator.c | 12 +- mach/proto/mcg/pass_returnvalues.c | 123 +++++++++++++++++ mach/proto/mcg/pass_typeinference.c | 4 +- mach/proto/mcg/procedure.c | 1 + mach/proto/mcg/treebuilder.c | 172 ++++++++++++++---------- util/mcgg/ir.dat | 12 +- 11 files changed, 318 insertions(+), 200 deletions(-) create mode 100644 mach/proto/mcg/pass_returnvalues.c diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 4a77118ca..a8fd1af7c 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -4,19 +4,20 @@ * * | ...params... * | --------------- <- ab + * | old FR + * | old FP + * | --------------- <- st, fp (a.k.a. lb) * | spills * | --------------- * | saved regs - * | LR - * | FP - * | --------------- <- st, fp (a.k.a. lb) + * | --------------- * | locals * | --------------- <- sp * V ...user area... * * st indexes up; lb indexes down. * - * We ensure that dereferencing fp always produces the caller's fp. + * Note that [fp] == old_fp and ab == fp + 8. */ static ARRAYOF(struct hreg) saved_regs; @@ -39,28 +40,29 @@ void platform_calculate_offsets(void) } current_proc->fp_to_st = 0; - current_proc->fp_to_ab = current_proc->spills_size + current_proc->saved_size + 8; - current_proc->fp_to_lb = 0; + current_proc->fp_to_ab = 8; + current_proc->fp_to_lb = -(current_proc->spills_size + current_proc->saved_size); } struct hop* platform_prologue(void) { int i; int saved_offset; + int spoffset = current_proc->saved_size + current_proc->spills_size + + current_proc->locals_size; struct hop* hop = new_hop(current_proc->entry, NULL); - hop_add_insel(hop, "! saved_size = %d+8 bytes", current_proc->saved_size); + hop_add_insel(hop, "! saved_size = %d bytes", current_proc->saved_size); hop_add_insel(hop, "! spills_size = %d bytes", current_proc->spills_size); hop_add_insel(hop, "! locals_size = %d bytes", current_proc->locals_size); - hop_add_insel(hop, "addi sp, sp, %d", -(current_proc->fp_to_ab + current_proc->locals_size)); + hop_add_insel(hop, "addi sp, sp, %d", -(spoffset + 8)); hop_add_insel(hop, "mfspr r0, lr"); - - hop_add_insel(hop, "stw fp, %d(sp)", current_proc->locals_size + 0); - hop_add_insel(hop, "stw r0, %d(sp)", current_proc->locals_size + 4); - hop_add_insel(hop, "addi fp, sp, %d", current_proc->locals_size); + hop_add_insel(hop, "stw fp, %d(sp)", spoffset + 0); + hop_add_insel(hop, "stw r0, %d(sp)", spoffset + 4); + hop_add_insel(hop, "addi fp, sp, %d", spoffset); /* Saved reg offsets are negative. */ - saved_offset = current_proc->saved_size + 8; + saved_offset = -current_proc->spills_size; for (i=0; isaved_size + 8; + saved_offset = -current_proc->spills_size; for (i=0; i ubyte0" - cost 1; - - out:(int)ubyte0 = CIU41(in:(int)ubyte0) - with %out == %in - emit "! CIU41(ubyte0) -> ubyte0" - cost 1; - - out:(int)ubyteX = CIU41(in:(int)ubyteX) - with %out == %in - emit "! CIU41(ubyteX) -> ubyteX" - cost 1; - - out:(int)reg = CII14(in:(int)ubyteX) - emit "extsb %out, %in ! CII14(ubyteX) -> reg" + out:(fret)reg = FROMUI.F(in:(ret)reg) + with corrupted(volatile) + emit "bl .fromui2f" cost 4; - /* short conversions */ + out:(dret)reg = FROMUI.D(in:(ret)reg) + with corrupted(volatile) + emit "bl .fromui2d" + cost 4; - out:(int)ushort0 = CIU24(in:(int)ushort0) - with %out == %in - emit "! CIU24(ushort0) -> ushort0" - cost 1; - - out:(int)ushort0 = CIU42(in:(int)ushort0) - with %out == %in - emit "! CIU42(ushort0) -> ushort0" - cost 1; - - out:(int)ushortX = CIU42(in:(int)ushortX) - with %out == %in - emit "! CIU42(ushortX) -> ushortX" - cost 1; - - out:(int)reg = CII24(in:(int)ushort0) - with %out == %in - emit "! CII24(ushort0) -> reg" - cost 4; - - out:(int)reg = CII24(in:(int)ushortX) - emit "extsh %out, %in" - cost 4; -#endif /* Locals */ @@ -452,6 +430,7 @@ PATTERNS + /* Memory addressing modes */ address = ADD.I(addr:(int)reg, offset:CONST.I) @@ -484,38 +463,26 @@ PATTERNS emit "b $false" cost 8; - CALL(dest:LABEL.I) - with corrupted(volatile) - emit "bl $dest" - cost 4; + #define CALLLABEL(insn) \ + insn (dest:LABEL.I) \ + with corrupted(volatile) \ + emit "bl $dest" \ + cost 4; - out:(ret)reg = CALL.I(dest:LABEL.I) - with corrupted(volatile) - emit "bl $dest" - cost 4; + CALLLABEL(CALL) + out:(int)reg = CALLLABEL(CALL.I) + out:(long)reg = CALLLABEL(CALL.L) - out:(lret)reg = CALL.L(dest:LABEL.I) - with corrupted(volatile) - emit "bl $dest" - cost 4; + #define CALLINDIRECT(insn) \ + insn (dest:(int)reg) \ + with corrupted(volatile) \ + emit "mtspr ctr, %dest" \ + emit "bcctrl 20, 0, 0" \ + cost 8; - CALL(dest:(int)reg) - with corrupted(volatile) - emit "mtspr ctr, %dest" - emit "bcctrl 20, 0, 0" - cost 8; - - out:(ret)reg = CALL.I(dest:(int)reg) - with corrupted(volatile) - emit "mtspr ctr, %dest" - emit "bcctrl 20, 0, 0" - cost 8; - - out:(lret)reg = CALL.L(dest:(int)reg) - with corrupted(volatile) - emit "mtspr ctr, %dest" - emit "bcctrl 20, 0, 0" - cost 8; + CALLINDIRECT(CALL) + out:(int)reg = CALLINDIRECT(CALL.I) + out:(long)reg = CALLINDIRECT(CALL.L) JUMP(dest:LABEL.I) emit "b $dest" @@ -701,6 +668,12 @@ PATTERNS emit "lfd %out, %addr" cost 4; + out:(float)reg = in:CONST.F + when specific_constant(%in, 0) + emit "la r0, .fd_00000000" + emit "lfs %out, 0(r0)" + cost 12; + FPU4R(ADDF.F, "fadds") FPU8R(ADDF.D, "fadd") @@ -729,35 +702,5 @@ PATTERNS emit "fcmpu %cr, %left, %right" cost 4; - #if 0 - out:(ret)reg = CFI44(val:(fret)reg) - with corrupted(volatile) - emit "bl .cfi44" - cost 4; - - out:(fret)reg = CIF44(val:(ret)reg) - with corrupted(volatile) - emit "bl .cif44" - cost 4; - - out:(ret)reg = CFI84(val:(dret)reg) - with corrupted(volatile) - emit "bl .cfi84" - cost 4; - - out:(dret)reg = CIF48(val:(ret)reg) - with corrupted(volatile) - emit "bl .cif48" - cost 4; - - out:(float)reg = CFF84(val:(double)reg) - emit "frsp %out, %val" - cost 4; - - out:(double)reg = CFF48(val:(float)reg) - emit "fmr %out, %val" - cost 1; - #endif - /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 1afa04c50..27ea8be03 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -282,9 +282,15 @@ char* hop_render(struct hop* hop) case IR_CONST: appendf("%d", ir->u.ivalue); break; + + default: + assert(false); } break; } + + default: + assert(false); } } diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 08f6828bf..540f5799c 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -118,6 +118,7 @@ extern void pass_register_allocator(void); extern void pass_remove_dead_blocks(void); extern void pass_remove_dead_phis(void); extern void pass_split_critical_edges(void); +extern void pass_wire_up_return_values(void); extern void platform_calculate_offsets(void); extern struct hop* platform_prologue(void); diff --git a/mach/proto/mcg/pass_livevreganalysis.c b/mach/proto/mcg/pass_livevreganalysis.c index 889fe35b5..5481c6598 100644 --- a/mach/proto/mcg/pass_livevreganalysis.c +++ b/mach/proto/mcg/pass_livevreganalysis.c @@ -67,6 +67,8 @@ void pass_live_vreg_analysis(void) propagate_liveness(dominance.postorder.item[i]); } while (!finished); + + //assert(cfg.entry->liveins.count == 0); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 0a6eba638..7c348f0a3 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -120,7 +120,7 @@ static struct hreg* evict(struct vreg* vreg) * Shouldn't really happen in real life. */ return hreg; } - if (candidatein == candidateout) + if (candidatein && candidateout && (candidatein == candidateout)) { /* This is a through register. */ tracef('R', "R: evicting %%%d from %s\n", candidatein->id, hreg->id); @@ -513,8 +513,9 @@ static void assign_hregs_to_vregs(void) phi->prev->regsout, phi->ir->result); if (hreg && !pmap_findleft(old, hreg)) { - tracef('R', "R: import hreg %s for phi input %%%d from %s\n", - hreg->id, vreg->id, phi->prev->name); + tracef('R', "R: import hreg %s for %%%d, imported from %s %%%d\n", + hreg->id, vreg->id, + phi->prev->name, phi->ir->id); pmap_put(old, hreg, vreg); } } @@ -534,8 +535,9 @@ static void assign_hregs_to_vregs(void) struct phicongruence* c = vreg->congruence; struct hreg* hreg = allocate_phi_hreg(old, vreg, c->type); - tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n", - hreg->id, vreg->id, phi->prev->name); + tracef('R', "R: import fallback hreg %s for %%%d, imported from %s %%%d\n", + hreg->id, vreg->id, + phi->prev->name, phi->ir->id); pmap_add(old, hreg, vreg); } } diff --git a/mach/proto/mcg/pass_returnvalues.c b/mach/proto/mcg/pass_returnvalues.c new file mode 100644 index 000000000..3be801411 --- /dev/null +++ b/mach/proto/mcg/pass_returnvalues.c @@ -0,0 +1,123 @@ +#include "mcg.h" + +/* The ACK returns values from functions not on the stack but in a special + * 'register' which are read with lfr. This register is defined to survive + * asp, bra and gto. The way it's intended to work is that value just gets put + * in a particular hreg and stays there until lfr brings it to the attention of + * the code generator. + * + * Trouble is, while that worked on ncg, it doesn't work here because the + * register allocator may decide to insert moves arbitrarily. So we need to + * somehow turn this special register into a real register so that it can be + * kept alive. + * + * The easiest thing to do is to just push the result of call onto the stack... + * but that doesn't work either, because if someone does a call without an lfr, + * we don't want to be left with an unpopped value. + * + * So what we do is we find lfrs, and then we search for the call which + * generated the value, and then we hook up the IRs so there's a connection + * between the two. But beware! The lfr value survives bra! Which means a + * single lfr may actually read the value produced by *several* call + * instructions. You know what that means? Phis. + * + * (Luckily a single call instruction can't be read by multiple lfrs, because + * conditional branches trash the lfr value.) + */ + +static void find_call(struct basicblock* bb, int index, struct ir* lfr, + struct basicblock** callbb, struct ir** callir) +{ + if (index == -1) + index = bb->irs.count - 1; + + while (index >= 0) + { + struct ir* ir = bb->irs.item[index]; + switch (ir->opcode) + { + case IR_CALL: + ir->size = lfr->size; + *callbb = bb; + *callir = ir; + return; + + case IR_STACKADJUST: + case IR_GETRET: + case IR_JUMP: + /* lfr value preserved */ + break; + + default: + /* lfr value has been corrupted. */ + fatal("lfr reading corrupted value in %s", bb->name); + } + + index--; + } + + /* Our search hit the top of the block; we need to import the + * lfr value from a previous block. */ + + if (bb->prevs.count == 1) + { + /* Only a single predecessor, so no phi is necessary. */ + + find_call(bb->prevs.item[0], -1, lfr, callbb, callir); + } + else + { + /* We have multiple predecessors. This means that the lfr value may + * come from any of these blocks. We need a phi. */ + + int i; + struct ir* phi = new_ir0(IR_PHI, lfr->size); + + phi->root = phi; + array_insert(&bb->irs, phi, 0); + + for (i=0; iprevs.count; i++) + { + struct basicblock* prev = bb->prevs.item[i]; + struct basicblock* parentbb; + struct ir* parentir; + + find_call(prev, -1, phi, &parentbb, &parentir); + + pmap_add(&phi->u.phivalue, parentbb, parentir); + } + + *callbb = bb; + *callir = phi; + } +} + +static void wire_up_ir(struct basicblock* bb, int index) +{ + struct ir* lfr = bb->irs.item[index]; + struct basicblock* callbb; + struct ir* callir; + + find_call(bb, index, lfr, &callbb, &callir); + + lfr->left = callir; + lfr->opcode = IR_NOP; +} + +void pass_wire_up_return_values(void) +{ + int i, j; + + for (i=0; iirs.count; j++) + { + struct ir* ir = bb->irs.item[j]; + if (ir->opcode == IR_GETRET) + wire_up_ir(bb, j); + } + } +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_typeinference.c b/mach/proto/mcg/pass_typeinference.c index c081a4b3d..f3b123e25 100644 --- a/mach/proto/mcg/pass_typeinference.c +++ b/mach/proto/mcg/pass_typeinference.c @@ -218,8 +218,8 @@ static struct ir* new_copy(char wanted, char real, struct ir* ir) else if ((wanted == 'L') && (real == 'D')) opcode = IR_COPYD; else - fatal("type mismatch: parent IR wanted %c, child IR provided %c", - wanted, real); + fatal("type mismatch: parent IR $%d wanted %c, child IR provided %c", + ir->id, wanted, real); copy = new_ir1(opcode, ir->size, ir); copy->type = wanted; diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index d09d30c05..7db7aff3a 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -179,6 +179,7 @@ void procedure_compile(struct procedure* proc) * and nexts (and then calling update_graph_data()). */ print_blocks('3'); + pass_wire_up_return_values(); pass_convert_stack_ops(); print_blocks('4'); pass_convert_locals_to_ssa(); diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 66a69edef..73e454d2c 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -4,7 +4,6 @@ static struct basicblock* current_bb; static int stackptr; static struct ir* stack[64]; -static struct ir* lastcall; static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode); static struct ir* appendir(struct ir* ir); @@ -340,6 +339,20 @@ static void simple_test_neg(int size, int irop) ); } +static void helper_function(const char* name) +{ + /* Delegates to a helper function; these leave their result on the stack + * rather than returning values through lfr. */ + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir(name) + ) + ); +} + static void insn_simple(int opcode) { switch (opcode) @@ -364,6 +377,7 @@ static void insn_simple(int opcode) case op_cfu: simple_convert(IR_FROMF); break; /* FIXME: technically wrong */ case op_cfi: simple_convert(IR_FROMF); break; case op_cif: simple_convert(IR_FROMSI); break; + case op_cuf: simple_convert(IR_FROMUI); break; case op_cff: simple_convert(IR_FROMF); break; case op_cmp: @@ -384,7 +398,7 @@ static void insn_simple(int opcode) struct ir* dest = pop(EM_pointersize); materialise_stack(); - lastcall = appendir( + appendir( new_ir1( IR_CALL, 0, dest @@ -421,7 +435,7 @@ static void insn_simple(int opcode) { push( new_ir1( - IR_LOAD, 2, + (EM_wordsize == 2) ? IR_LOAD : IR_LOADH, EM_wordsize, new_labelir(".ignmask") ) ); @@ -432,7 +446,7 @@ static void insn_simple(int opcode) { appendir( new_ir2( - IR_STORE, 2, + (EM_wordsize == 2) ? IR_STORE : IR_STOREH, EM_wordsize, new_labelir(".ignmask"), pop(EM_wordsize) ) @@ -440,31 +454,32 @@ static void insn_simple(int opcode) break; } - case op_trp: - { - materialise_stack(); - appendir( - new_ir1( - IR_CALL, 0, - new_labelir(".trp") - ) - ); - break; - } + case op_trp: helper_function(".trp"); break; + case op_sig: helper_function(".sig"); break; + case op_rtt: helper_function(".rtt"); break; /* FIXME: These instructions are really complex and barely used - * (Modula-2 bitset support, I believe). Leave them until leter. */ - case op_set: - case op_ior: - { - appendir( + * (Modula-2 bitset support, I believe). Leave them until later. */ + case op_set: helper_function(".unimplemented_set"); break; + case op_ior: helper_function(".unimplemented_ior"); break; + + case op_dch: + push( new_ir1( - IR_CALL, 0, - new_labelir(".unimplemented") + IR_CHAINFP, EM_pointersize, + pop(EM_pointersize) + ) + ); + break; + + case op_lpb: + push( + new_ir1( + IR_FPTOAB, EM_pointersize, + pop(EM_pointersize) ) ); break; - } case op_lni: { @@ -598,6 +613,28 @@ static struct ir* ptradd(struct ir* address, int offset) ); } +static void blockmove(struct ir* dest, struct ir* src, struct ir* size) +{ + /* memmove stack: ( size src dest -- ) */ + push(size); + push(src); + push(dest); + + materialise_stack(); + appendir( + new_ir1( + IR_CALL, 0, + new_labelir("memmove") + ) + ); + appendir( + new_ir1( + IR_STACKADJUST, EM_pointersize, + new_wordir(EM_pointersize*2 + EM_wordsize) + ) + ); +} + static void insn_ivalue(int opcode, arith value) { switch (opcode) @@ -725,7 +762,7 @@ static void insn_ivalue(int opcode, arith value) case op_zrf: { struct ir* ir = new_constir(value, 0); - ir->opcode = IR_CONSTF; + ir->opcode = IR_CONST; push(ir); break; } @@ -1012,9 +1049,13 @@ static void insn_ivalue(int opcode, arith value) case op_lfr: { - assert(lastcall != NULL); - lastcall->size = value; - push(lastcall); + push( + appendir( + new_ir0( + IR_GETRET, value + ) + ) + ); break; } @@ -1063,7 +1104,7 @@ static void insn_ivalue(int opcode, arith value) * the physical stack (which is very dubious). */ appendir( new_ir1( - IR_CALL, EM_wordsize, + IR_CALL, 0, new_labelir(helper) ) ); @@ -1094,26 +1135,11 @@ static void insn_ivalue(int opcode, arith value) case op_lxa: { - struct ir* ir; - - /* Walk the static chain. */ - - ir = new_ir0( - IR_GETFP, EM_pointersize - ); - - while (value--) - { - ir = new_ir1( - IR_CHAINFP, EM_pointersize, - ir - ); - } - - push( + /* What does this actually *do*? The spec doesn't say. */ + appendir( new_ir1( - IR_FPTOARGS, EM_pointersize, - ir + IR_CALL, 0, + new_labelir(".unimplemented_lxa") ) ); break; @@ -1166,6 +1192,17 @@ static void insn_ivalue(int opcode, arith value) { switch (value) { + case 0: + appendir( + new_ir1( + IR_FPTOLB, EM_pointersize, + new_ir0( + IR_GETFP, EM_pointersize + ) + ) + ); + break; + case 1: appendir( new_ir0( @@ -1185,6 +1222,15 @@ static void insn_ivalue(int opcode, arith value) { switch (value) { + case 0: + appendir( + new_ir1( + IR_SETFP, EM_pointersize, + pop(EM_pointersize) + ) + ); + break; + case 1: appendir( new_ir1( @@ -1204,27 +1250,19 @@ static void insn_ivalue(int opcode, arith value) case op_blm: { /* Input stack: ( src dest -- ) */ - /* Memmove stack: ( size src dest -- ) */ struct ir* dest = pop(EM_pointersize); struct ir* src = pop(EM_pointersize); + blockmove(dest, src, new_wordir(value)); + break; + } - push(new_wordir(value)); - push(src); - push(dest); - - materialise_stack(); - appendir( - new_ir1( - IR_CALL, 0, - new_labelir("memmove") - ) - ); - appendir( - new_ir1( - IR_STACKADJUST, EM_pointersize, - new_wordir(EM_pointersize*2 + EM_wordsize) - ) - ); + case op_bls: + { + /* Input stack: ( src dest size -- ) */ + struct ir* dest = pop(EM_pointersize); + struct ir* src = pop(EM_pointersize); + struct ir* size = pop(EM_wordsize); + blockmove(dest, src, size); break; } @@ -1426,7 +1464,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset) case op_cal: assert(offset == 0); materialise_stack(); - lastcall = appendir( + appendir( new_ir1( IR_CALL, 0, new_labelir(label) @@ -1513,8 +1551,6 @@ void tb_procedure(void) for (i=0; iblocks.count; i++) generate_tree(current_proc->blocks.item[i]); - } /* vim: set sw=4 ts=4 expandtab : */ - diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 1be1810fd..92fb5df0d 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -6,8 +6,7 @@ # ?: pull/push types from other ? parameters # Simple terminals -S ?=.. CONST # must be followed by float form -S ?=.. CONSTF +S ?=.. CONST V ?=.. REG S ?=?. NOP S I=.. LABEL @@ -95,7 +94,9 @@ S I=I. IFLT S I=I. IFLE # Procedures -S i=.. CALL +S i=I. CALL +S i=?. GETRET +S ?=i. SETRET # Flow control --- these never return V .=i. JUMP @@ -106,10 +107,11 @@ V .=.. RET # Special S ?=i. STACKADJUST -S ?=i. SETRET S i=.. GETFP +S ?=i. SETFP S i=.. GETSP S ?=i. SETSP S i=i. CHAINFP -S i=i. FPTOARGS +S i=i. FPTOAB +S i=i. FPTOLB From 68419da235342b0efcc172a16308ee2676a84da6 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 29 Oct 2016 12:00:33 +0200 Subject: [PATCH 152/230] Actually, the locals need to go above the spills and saved regs, so fp == lb. --- mach/powerpc/mcg/platform.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index a8fd1af7c..b8bd44744 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -7,11 +7,11 @@ * | old FR * | old FP * | --------------- <- st, fp (a.k.a. lb) + * | locals + * | --------------- * | spills * | --------------- * | saved regs - * | --------------- - * | locals * | --------------- <- sp * V ...user area... * @@ -39,9 +39,9 @@ void platform_calculate_offsets(void) } } - current_proc->fp_to_st = 0; + current_proc->fp_to_st = -current_proc->locals_size; current_proc->fp_to_ab = 8; - current_proc->fp_to_lb = -(current_proc->spills_size + current_proc->saved_size); + current_proc->fp_to_lb = 0; } struct hop* platform_prologue(void) @@ -62,7 +62,7 @@ struct hop* platform_prologue(void) hop_add_insel(hop, "addi fp, sp, %d", spoffset); /* Saved reg offsets are negative. */ - saved_offset = -current_proc->spills_size; + saved_offset = -(current_proc->locals_size + current_proc->spills_size); for (i=0; ispills_size; + saved_offset = -(current_proc->locals_size + current_proc->spills_size); for (i=0; i Date: Sat, 29 Oct 2016 12:48:05 +0200 Subject: [PATCH 153/230] More opcodes. sti can now cope with non-standard sizes (really need a better fix for this). Hack in crude support for mismatched stack pushes and pops (ints vs longs). --- mach/powerpc/mcg/table | 20 +++++++- mach/proto/mcg/data.c | 3 +- mach/proto/mcg/treebuilder.c | 92 ++++++++++++++++++++++++++++++++---- util/mcgg/ir.dat | 3 ++ 4 files changed, 107 insertions(+), 11 deletions(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 3cfb1447d..366b16d14 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -229,7 +229,7 @@ PATTERNS out:(int)reg = FPTOLB.I(in:(int)reg) with %out == %in cost 1; - + out:(int)reg = GETSP.I emit "mr %out, sp" cost 4; @@ -417,6 +417,19 @@ PATTERNS emit "bl .fromui2d" cost 4; + out:(lret)reg = FROMIPAIR.L(in1:(int)reg, in2:(int)reg) + emit "mr %out.0, %in1" + emit "mr %out.1, %in2" + cost 8; + + out:(int)reg = FROML0.I(in:(long)reg) + emit "mr %out, %in.0" + cost 4; + + out:(int)reg = FROML1.I(in:(long)reg) + emit "mr %out, %in.1" + cost 4; + /* Locals */ @@ -448,6 +461,11 @@ PATTERNS emit "b $addr" cost 4; + JUMP(dest:(int)reg) + emit "mtspr ctr, %dest" + emit "bcctrl 20, 0, 0" + cost 8; + CJUMPEQ(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I)) emit "bc 12, 2, $true" /* IFTRUE EQ */ emit "b $false" diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index 2e6fde9b2..5eeca8fc2 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -64,7 +64,8 @@ void data_float(const char* data, size_t size, bool is_ro) emit_header(is_ro ? SECTION_ROM : SECTION_DATA); assert((size == 4) || (size == 8)); - if (float_cst(data, size, (char*) buffer)) + i = float_cst(data, size, (char*) buffer); + if ((i != 0) && (i != 2)) /* 2 == overflow */ fatal("cannot parse floating point constant %s sz %d", data, size); fprintf(outputfile, "\t!float %s sz %d\n", data, size); diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 73e454d2c..1d0c408cf 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -59,7 +59,37 @@ static struct ir* pop(int size) #endif if (ir->size != size) - fatal("expected an item on stack of size %d, but got %d\n", size, ir->size); + { + if ((size == (EM_wordsize*2)) && (ir->size == EM_wordsize)) + { + /* Tried to read a long, but we got an int. Assemble the long + * out of two ints. Note that EM doesn't specify an order. */ + return + new_ir2( + IR_FROMIPAIR, size, + ir, + pop(EM_wordsize) + ); + } + else if ((size == EM_wordsize) && (ir->size == (EM_wordsize*2))) + { + /* Tried to read an int, but we got a long. */ + push( + new_ir1( + IR_FROML1, EM_wordsize, + ir + ) + ); + + return + new_ir1( + IR_FROML0, EM_wordsize, + ir + ); + } + else + fatal("expected an item on stack of size %d, but got %d\n", size, ir->size); + } return ir; } } @@ -864,15 +894,34 @@ static void insn_ivalue(int opcode, arith value) case op_sti: { struct ir* ptr = pop(EM_pointersize); - struct ir* val = pop(value); + int offset = 0; - appendir( - store( - value, - ptr, 0, - val - ) - ); + /* FIXME: this is awful; need a better way of dealing with + * non-standard EM sizes. */ + if (value > (EM_wordsize*2)) + appendir(ptr); + + while (value > 0) + { + int s; + if (value > (EM_wordsize*2)) + s = EM_wordsize*2; + else + s = value; + + appendir( + store( + s, + ptr, offset, + pop(s) + ) + ); + + value -= s; + offset += s; + } + + assert(value == 0); break; } @@ -1483,6 +1532,31 @@ static void insn_lvalue(int opcode, const char* label, arith offset) ); break; + case op_gto: + { + struct ir* descriptor = pop(EM_pointersize); + + appendir( + new_ir1( + IR_SETSP, EM_pointersize, + load(EM_pointersize, descriptor, EM_pointersize*2) + ) + ); + appendir( + new_ir1( + IR_SETFP, EM_pointersize, + load(EM_pointersize, descriptor, EM_pointersize*1) + ) + ); + appendir( + new_ir1( + IR_JUMP, 0, + load(EM_pointersize, descriptor, EM_pointersize*0) + ) + ); + break; + } + case op_fil: { /* Set filename --- ignore. */ diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 92fb5df0d..1db593efc 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -71,6 +71,9 @@ S ?=I. FROMSI S ?=L. FROMSL S ?=F. FROMF S ?=D. FROMD +S L=II FROMIPAIR +S I=L. FROML0 +S I=L. FROML1 # The H versions are only used if wordsize > 2 S I=I. EXTENDB From acaae765afea2657ec36144efab91b28c481ec81 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 29 Oct 2016 12:55:21 +0200 Subject: [PATCH 154/230] Emit negative constants correctly. --- mach/proto/mcg/data.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index 5eeca8fc2..2e27e37ca 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -49,13 +49,24 @@ static void emit_header(int desired_section) } } +static void writehex(arith data, int size) +{ + if (data < 0) + fprintf(outputfile, "-0x%0*lx", size*2, -data); + else + fprintf(outputfile, "0x%0*lx", size*2, data); +} + void data_int(arith data, size_t size, bool is_ro) { emit_header(is_ro ? SECTION_ROM : SECTION_DATA); assert((size == 1) || (size == 2) || (size == 4) || (size == 8)); - fprintf(outputfile, "\t.data%d 0x%0*lld\n", size, size*2, data); + fprintf(outputfile, "\t.data%d ", size); + writehex(data, size); + fprintf(outputfile, "\n"); } + void data_float(const char* data, size_t size, bool is_ro) { unsigned char buffer[8]; @@ -69,9 +80,13 @@ void data_float(const char* data, size_t size, bool is_ro) fatal("cannot parse floating point constant %s sz %d", data, size); fprintf(outputfile, "\t!float %s sz %d\n", data, size); - fprintf(outputfile, "\t.data1 0x%02x", buffer[0]); + fprintf(outputfile, "\t.data1 "); + writehex(buffer[0], 1); for (i=1; i Date: Sat, 29 Oct 2016 12:55:34 +0200 Subject: [PATCH 155/230] More opcodes. --- mach/powerpc/mcg/table | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 366b16d14..3be30c306 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -387,6 +387,11 @@ PATTERNS emit "srawi %out.1, %out.0, 31" cost 8; + out:(long)reg = FROMUI.L(in:(int)reg) + emit "mr %out.0, %in" + emit "li %out.1, 0" + cost 8; + out:(ret)reg = FROMF.I(in:(dret)reg) with corrupted(volatile) emit "bl .fromf2i" From e3ebf986e9e8663aea623f675395794012d58ffb Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 29 Oct 2016 13:32:09 +0200 Subject: [PATCH 156/230] More opcodes. --- mach/proto/mcg/parse_em.c | 1 + mach/proto/mcg/treebuilder.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 26754b1e1..4644d3a09 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -249,6 +249,7 @@ static void parse_pseu(void) break; case sof_ptyp: + case pro_ptyp: data_offset(strdup(em.em_dnam), em.em_off, ro); break; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 1d0c408cf..b0ef5ba87 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -806,6 +806,16 @@ static void insn_ivalue(int opcode, arith value) ); break; + case op_lae: + push( + new_ir2( + IR_ADD, EM_pointersize, + new_labelir(".hol0"), + new_wordir(value) + ) + ); + break; + case op_ste: appendir( store( @@ -1013,6 +1023,15 @@ static void insn_ivalue(int opcode, arith value) break; } + case op_exg: + { + struct ir* v1 = pop(value); + struct ir* v2 = pop(value); + push(v1); + push(v2); + break; + } + case op_asp: { switch (value) @@ -1260,6 +1279,10 @@ static void insn_ivalue(int opcode, arith value) ); break; + case 2: + helper_function(".unimplemented_lor_2"); + break; + default: fatal("'lor %d' not supported", value); } @@ -1289,6 +1312,10 @@ static void insn_ivalue(int opcode, arith value) ); break; + case 2: + helper_function(".unimplemented_str_2"); + break; + default: fatal("'str %d' not supported", value); } From a311e6136023fab7d2065a25387a2f483dc78bf3 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 29 Oct 2016 20:22:44 +0200 Subject: [PATCH 157/230] Add support for preserved registers. --- mach/powerpc/mcg/table | 2 ++ mach/proto/mcg/hop.h | 1 + mach/proto/mcg/pass_instructionselection.c | 11 +++++++++++ util/mcgg/gram.y | 3 +++ util/mcgg/iburg.c | 23 ++++++++++++++++++++++ util/mcgg/iburg.h | 1 + util/mcgg/mcgg.h | 1 + util/mcgg/scan.l | 1 + 8 files changed, 43 insertions(+) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 3be30c306..7023c08b6 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -617,12 +617,14 @@ PATTERNS cost 4; out:(int)reg = MOD.I(left:(int)reg, right:(int)reg) + with preserved(%left), preserved(%right) emit "divw %out, %left, %right" emit "mullw %out, %out, %right" emit "subf %out, %out, %left" cost 12; out:(int)reg = MODU.I(left:(int)reg, right:(int)reg) + with preserved(%left), preserved(%right) emit "divwu %out, %left, %right" emit "mullw %out, %out, %right" emit "subf %out, %out, %left" diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 0cc5dc0b1..21c7e9293 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -31,6 +31,7 @@ struct insel struct constraint { uint32_t attrs; + bool preserved; struct vreg* equals_to; }; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 2bf5e5b59..860dad02f 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -100,6 +100,16 @@ static void constrain_input_reg(int child, uint32_t attr) get_constraint(vreg)->attrs = attr; } +static void constrain_input_reg_preserved(int child) +{ + struct vreg* vreg = find_vreg_of_child(child); + struct constraint* c; + + assert(vreg); + array_appendu(¤t_hop->throughs, vreg); + get_constraint(vreg)->preserved = true; +} + static uint32_t find_type_from_constraint(uint32_t attr) { /* Looks through the registers and finds a concrete register implementing @@ -158,6 +168,7 @@ static const struct burm_emitter_data emitter_data = &emit_value, &emit_eoi, &constrain_input_reg, + &constrain_input_reg_preserved, &constrain_output_reg, &constrain_output_reg_equal_to, }; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 99fdeda95..891030a10 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -38,6 +38,7 @@ extern int yylex(void); %term NOTEQUALS %term PATTERNS %term PREFERS +%term PRESERVED %term REGISTERS %term WHEN %term WITH @@ -170,6 +171,8 @@ constraint $$->type = CONSTRAINT_EQUALS; $$->left = $2; $$->right = $5; } | CORRUPTED '(' ID ')' { $$ = calloc(1, sizeof(*$$)); $$->type = CONSTRAINT_CORRUPTED_ATTR; $$->left = $3; } + | PRESERVED '(' '%' ID ')' { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_PRESERVED; $$->left = $4; } ; qfragments diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 55a24e717..23705c7d8 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -1199,6 +1199,28 @@ static void emit_output_constraints(Rule r) } } +static void emit_input_constraints(Rule r) +{ + int i; + for (i=0; iconstraints.count; i++) + { + int index; + struct constraint* c = r->constraints.item[i]; + + if (c->type == CONSTRAINT_PRESERVED) + { + if (strcmp(c->left, r->label) == 0) + yyerror("cannot preserve an output register!"); + + index = 0; + if (!find_child_index(r->pattern, c->left, &index, NULL)) + label_not_found(r, c->left); + + print("%1data->constrain_input_reg_preserved(%d);\n", index); + } + } +} + /* emitinsndata - emit the code generation data */ static void emitinsndata(Rule rules) { @@ -1234,6 +1256,7 @@ static void emitinsndata(Rule rules) } emit_output_constraints(r); + emit_input_constraints(r); while (f) { diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 8ba4f5ab9..739641d4d 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -21,6 +21,7 @@ enum { CONSTRAINT_EQUALS, CONSTRAINT_CORRUPTED_ATTR, + CONSTRAINT_PRESERVED, }; struct constraint diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index a068fa660..c0c930a27 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -45,6 +45,7 @@ struct burm_emitter_data void (*emit_value)(int child); void (*emit_eoi)(void); void (*constrain_input_reg)(int child, uint32_t attr); + void (*constrain_input_reg_preserved)(int child); void (*constrain_output_reg)(uint32_t attr); void (*constrain_output_reg_equal_to)(int child); }; diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 272dd2bf1..447a7d395 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -46,6 +46,7 @@ static int braces = 0; "fragment" return FRAGMENT; "named" return NAMED; "prefers" return PREFERS; +"preserved" return PRESERVED; "when" return WHEN; "with" return WITH; "==" return EQUALS; From 8c3670483fc1f896aba79bb4573077f153862e16 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 29 Oct 2016 23:37:11 +0200 Subject: [PATCH 158/230] Get top working with the PowerPC; use it to eliminate useless branches and moves. --- mach/powerpc/libem/build.lua | 8 +++++++- mach/powerpc/top/table | 11 ++++++++++- mach/proto/mcg/parse_em.c | 4 ++-- plat/linuxppc/build-tools.lua | 6 ++++++ plat/linuxppc/descr | 19 +++++++++---------- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/mach/powerpc/libem/build.lua b/mach/powerpc/libem/build.lua index 56278aa55..dd9ec7542 100644 --- a/mach/powerpc/libem/build.lua +++ b/mach/powerpc/libem/build.lua @@ -1,4 +1,9 @@ for _, plat in ipairs(vars.plats) do + acklibrary { + name = "headers_"..plat, + hdrs = { "./*.h" } + } + acklibrary { name = "lib_"..plat, srcs = { @@ -6,7 +11,8 @@ for _, plat in ipairs(vars.plats) do }, vars = { plat = plat }, deps = { - "h+emheaders" + "h+emheaders", + "+headers_"..plat, } } end diff --git a/mach/powerpc/top/table b/mach/powerpc/top/table index e735afee6..acbe543a7 100644 --- a/mach/powerpc/top/table +++ b/mach/powerpc/top/table @@ -1,7 +1,8 @@ -/* 68020 desciptor table for ACK target optimizer */ +/* PowerPC desciptor table for ACK target optimizer */ MAXOP 3; +LABEL_STARTER '.'; %%; @@ -15,6 +16,14 @@ X, Y, Z { TRUE }; addi X, X, 0 -> ; addis X, X, 0 -> ; +mr X, X -> ; +fmr X, X -> ; + or X, Y, Z : or. X, X, X -> or. X, Y, Z ; +b X : labdef X -> labdef X ; + +/* IFFALSE=4, IFTRUE=12, ALWAYS=20 */ +/* LT=0, GT=1, EQ=2, OV=3 */ + %%; diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 4644d3a09..b66b177c4 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -51,12 +51,12 @@ static void unknown_type(const char* s) static const char* ilabel_to_str(label l) { assert(current_proc != NULL); - return aprintf("__%s_I%d", current_proc->name, l); + return aprintf(".%s_I%d", current_proc->name, l); } static const char* dlabel_to_str(label l) { - return aprintf("__D%d", l); + return aprintf(".D%d", l); } static void terminate_block(void) diff --git a/plat/linuxppc/build-tools.lua b/plat/linuxppc/build-tools.lua index 0157e31a4..ce1a163d8 100644 --- a/plat/linuxppc/build-tools.lua +++ b/plat/linuxppc/build-tools.lua @@ -15,12 +15,18 @@ build_ncg { arch = "powerpc", } +build_top { + name = "top", + arch = "powerpc", +} + return installable { name = "tools", map = { ["$(PLATDEP)/linuxppc/as"] = "+as", ["$(PLATDEP)/linuxppc/ncg"] = "+ncg", ["$(PLATDEP)/linuxppc/mcg"] = "+mcg", + ["$(PLATDEP)/linuxppc/top"] = "+top", ["$(PLATIND)/descr/linuxppc"] = "./descr", "util/opt+pkg", } diff --git a/plat/linuxppc/descr b/plat/linuxppc/descr index 72958b212..79188640a 100644 --- a/plat/linuxppc/descr +++ b/plat/linuxppc/descr @@ -40,16 +40,15 @@ name be stdout need .e end -# FIXME(dtrg): not working yet -#name asopt -# from .s -# to .so -# program {EM}/lib/ack/{PLATFORM}/top -# args -# optimizer -# stdin -# stdout -#end +name asopt + from .s + to .so + program {EM}/lib/ack/{PLATFORM}/top + args + optimizer + stdin + stdout +end name as from .s.so to .o From ca5b6e07bbecb585e64ec3a8008f66cabc1d7b3c Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 29 Oct 2016 23:52:17 +0200 Subject: [PATCH 159/230] Properly export symbols. --- mach/proto/mcg/symbol.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mach/proto/mcg/symbol.c b/mach/proto/mcg/symbol.c index 26e01e020..ac5e78ce4 100644 --- a/mach/proto/mcg/symbol.c +++ b/mach/proto/mcg/symbol.c @@ -37,6 +37,9 @@ void symbol_declare(const char* name, bool is_exported, bool is_proc) else if (s->section != SECTION_TEXT) fatal("section mismatch for '%s'", name); } + + if (is_exported) + fprintf(outputfile, ".extern %s\n", platform_label(name)); } struct symbol* symbol_walk(symbol_walker_t* cb, void* user) From e19850b11446d1b5d4d8acb10a6820f22812f866 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 30 Oct 2016 16:51:06 +0100 Subject: [PATCH 160/230] Fix a few c11isms. --- mach/proto/mcg/procedure.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 7db7aff3a..f819c56e3 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -7,7 +7,7 @@ static void print_blocks(char k) int i; tracef(k, "%c: procedure %s\n", k, current_proc->name); - for (int i=0; iblocks.count; i++) + for (i=0; iblocks.count; i++) { struct basicblock* bb = current_proc->blocks.item[i]; int j; @@ -43,7 +43,7 @@ static void print_hops(char k) int i; tracef(k, "%c: procedure %s\n", k, current_proc->name); - for (int i=0; i Date: Mon, 31 Oct 2016 19:52:17 +0100 Subject: [PATCH 161/230] Use fmadd for multiply-and-add instructions. --- mach/powerpc/mcg/table | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 61729d308..159d0332b 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -711,6 +711,14 @@ PATTERNS FPU4R(DIVF.F, "fdivs") FPU8R(DIVF.D, "fdiv") + out:(double)reg = ADDF.D(MULF.D(m1:(double)reg, m2:(double)reg), m3:(double)reg) + emit "fmadd %out, %m1, %m2, %m3" + cost 4; + + out:(double)reg = ADDF.D(m3:(double)reg, MULF.D(m1:(double)reg, m2:(double)reg)) + emit "fmadd %out, %m1, %m2, %m3" + cost 4; + out:(float)reg = NEGF.F(left:(float)reg) emit "fneg %out, %left" cost 4; From 44f0cea6ca8914f52c834d53ae5f0c59fd9e2436 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 31 Oct 2016 19:55:16 +0100 Subject: [PATCH 162/230] Also use fmadd for single-precision floats. --- mach/powerpc/mcg/table | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 159d0332b..6a581e3df 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -719,6 +719,14 @@ PATTERNS emit "fmadd %out, %m1, %m2, %m3" cost 4; + out:(float)reg = ADDF.F(MULF.D(m1:(float)reg, m2:(float)reg), m3:(float)reg) + emit "fmadds %out, %m1, %m2, %m3" + cost 4; + + out:(float)reg = ADDF.F(m3:(float)reg, MULF.D(m1:(float)reg, m2:(float)reg)) + emit "fmadds %out, %m1, %m2, %m3" + cost 4; + out:(float)reg = NEGF.F(left:(float)reg) emit "fneg %out, %left" cost 4; From 941072e0d79be9ea6f7ffd656bdda075fde336ef Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 31 Oct 2016 22:36:54 +0100 Subject: [PATCH 163/230] Add, I hope, patterns for fmsub, fnmadd, and fnmsub (also float versions). --- mach/powerpc/mcg/table | 44 ++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 6a581e3df..cb3b01edd 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -711,21 +711,41 @@ PATTERNS FPU4R(DIVF.F, "fdivs") FPU8R(DIVF.D, "fdiv") - out:(double)reg = ADDF.D(MULF.D(m1:(double)reg, m2:(double)reg), m3:(double)reg) - emit "fmadd %out, %m1, %m2, %m3" - cost 4; + #define FMALEFT(type, insn, add, mul) \ + out:(type)reg = add(mul(m1:(double)reg, m2:(double)reg), m3:(double)reg) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ + + #define FMARIGHT(type, insn, add, mul) \ + out:(type)reg = add(m3:(double)reg, mul(m1:(double)reg, m2:(double)reg)) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ - out:(double)reg = ADDF.D(m3:(double)reg, MULF.D(m1:(double)reg, m2:(double)reg)) - emit "fmadd %out, %m1, %m2, %m3" - cost 4; + FMALEFT( double, "fmadd", ADDF.D, MULF.D) + FMARIGHT(double, "fmadd", ADDF.D, MULF.D) + FMALEFT( float, "fmadds", ADDF.F, MULF.F) + FMARIGHT(float, "fmadds", ADDF.F, MULF.F) - out:(float)reg = ADDF.F(MULF.D(m1:(float)reg, m2:(float)reg), m3:(float)reg) - emit "fmadds %out, %m1, %m2, %m3" - cost 4; + FMALEFT( double, "fmsub", SUBF.D, MULF.D) + FMALEFT( float, "fmsubs", SUBF.F, MULF.F) - out:(float)reg = ADDF.F(m3:(float)reg, MULF.D(m1:(float)reg, m2:(float)reg)) - emit "fmadds %out, %m1, %m2, %m3" - cost 4; + FMARIGHT(double, "fnmadd", SUBF.D, MULF.D) + FMARIGHT(float, "fnmadds", SUBF.D, MULF.D) + + #define FMANEGLEFT(type, insn, neg, add, mul) \ + out:(type)reg = neg(add(mul(m1:(double)reg, m2:(double)reg), m3:(double)reg)) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ + + #define FMANEGRIGHT(type, insn, neg, add, mul) \ + out:(type)reg = neg(add(m3:(double)reg, mul(m1:(double)reg, m2:(double)reg))) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ + + FMANEGLEFT( double, "fnmsub", NEGF.D, ADDF.D, MULF.D) + FMANEGRIGHT(double, "fnmsub", NEGF.D, ADDF.D, MULF.D) + FMANEGLEFT( float, "fnmsub", NEGF.F, ADDF.F, MULF.F) + FMANEGRIGHT(float, "fnmsub", NEGF.F, ADDF.F, MULF.F) out:(float)reg = NEGF.F(left:(float)reg) emit "fneg %out, %left" From 9261cd978d19ba93dba60206b08ccaa8666f771a Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 31 Oct 2016 23:16:02 +0100 Subject: [PATCH 164/230] Typo fix. --- mach/powerpc/mcg/table | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index cb3b01edd..486d983ed 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -712,14 +712,14 @@ PATTERNS FPU8R(DIVF.D, "fdiv") #define FMALEFT(type, insn, add, mul) \ - out:(type)reg = add(mul(m1:(double)reg, m2:(double)reg), m3:(double)reg) \ - emit insn " %out, %m1, %m2, %m3" \ - cost 4; \ + out:(type)reg = add(mul(m1:(type)reg, m2:(type)reg), m3:(type)reg) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ #define FMARIGHT(type, insn, add, mul) \ - out:(type)reg = add(m3:(double)reg, mul(m1:(double)reg, m2:(double)reg)) \ - emit insn " %out, %m1, %m2, %m3" \ - cost 4; \ + out:(type)reg = add(m3:(type)reg, mul(m1:(type)reg, m2:(type)reg)) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ FMALEFT( double, "fmadd", ADDF.D, MULF.D) FMARIGHT(double, "fmadd", ADDF.D, MULF.D) @@ -730,17 +730,17 @@ PATTERNS FMALEFT( float, "fmsubs", SUBF.F, MULF.F) FMARIGHT(double, "fnmadd", SUBF.D, MULF.D) - FMARIGHT(float, "fnmadds", SUBF.D, MULF.D) + FMARIGHT(float, "fnmadds", SUBF.F, MULF.F) #define FMANEGLEFT(type, insn, neg, add, mul) \ - out:(type)reg = neg(add(mul(m1:(double)reg, m2:(double)reg), m3:(double)reg)) \ - emit insn " %out, %m1, %m2, %m3" \ - cost 4; \ + out:(type)reg = neg(add(mul(m1:(type)reg, m2:(type)reg), m3:(type)reg)) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ #define FMANEGRIGHT(type, insn, neg, add, mul) \ - out:(type)reg = neg(add(m3:(double)reg, mul(m1:(double)reg, m2:(double)reg))) \ - emit insn " %out, %m1, %m2, %m3" \ - cost 4; \ + out:(type)reg = neg(add(m3:(type)reg, mul(m1:(type)reg, m2:(type)reg))) \ + emit insn " %out, %m1, %m2, %m3" \ + cost 4; \ FMANEGLEFT( double, "fnmsub", NEGF.D, ADDF.D, MULF.D) FMANEGRIGHT(double, "fnmsub", NEGF.D, ADDF.D, MULF.D) From 4fa2c94a4a2c6b61570b1294e714ca74be7974c6 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 31 Oct 2016 23:21:33 +0100 Subject: [PATCH 165/230] Correctly mangle labels used in initialisers. --- mach/proto/mcg/data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index 2e27e37ca..cbaa4c3eb 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -144,7 +144,8 @@ void data_block(const uint8_t* data, size_t size, bool is_ro) void data_offset(const char* label, arith offset, bool is_ro) { emit_header(is_ro ? SECTION_ROM : SECTION_DATA); - fprintf(outputfile, "\t.data%d %s+%lld\n", EM_pointersize, label, offset); + fprintf(outputfile, "\t.data%d %s+%lld\n", + EM_pointersize, platform_label(label), offset); } void data_bss(arith size, int init) From 4ba409eb743302d1d0ed79497b81ecd6bf85e9d3 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 5 Nov 2016 11:52:54 +0100 Subject: [PATCH 166/230] Ensure the modules properly depend on their headers. --- modules/src/data/build.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/src/data/build.lua b/modules/src/data/build.lua index f9af7c519..9f5941808 100644 --- a/modules/src/data/build.lua +++ b/modules/src/data/build.lua @@ -2,7 +2,6 @@ clibrary { name = "lib", srcs = { "./*.c" }, hdrs = { "./*.h" }, - deps = { - }, + deps = { "./*.h" }, } From 57cb99ade1ada6dd5cf77162b335f8f750d075ff Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 9 Nov 2016 21:52:04 +0100 Subject: [PATCH 167/230] Remove sys_time in favour of directly calling time(). --- lang/cem/cemcom.ansi/init.c | 5 +++-- lang/cem/cpp.ansi/init.c | 5 +++-- modules/src/system/system.3 | 4 +--- modules/src/system/system.h | 1 - modules/src/system/time.c | 15 --------------- 5 files changed, 7 insertions(+), 23 deletions(-) delete mode 100644 modules/src/system/time.c diff --git a/lang/cem/cemcom.ansi/init.c b/lang/cem/cemcom.ansi/init.c index bb1fd5559..3b3403aa4 100644 --- a/lang/cem/cemcom.ansi/init.c +++ b/lang/cem/cemcom.ansi/init.c @@ -7,6 +7,7 @@ #include #include +#include #include "parameters.h" #ifndef NOPP @@ -44,7 +45,7 @@ init_pp() "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - long clock, sys_time(); + time_t clock; static char dbuf[30]; static char tbuf[30]; struct tm *tp; @@ -70,7 +71,7 @@ init_pp() /* Initialize __LINE__, __FILE__, __DATE__, __TIME__, and __STDC__ macro definitions. */ - clock = sys_time(); + clock = time(NULL); tp = localtime(&clock); /* __DATE__ */ diff --git a/lang/cem/cpp.ansi/init.c b/lang/cem/cpp.ansi/init.c index a9cba4dba..3953609b5 100644 --- a/lang/cem/cpp.ansi/init.c +++ b/lang/cem/cpp.ansi/init.c @@ -7,6 +7,7 @@ #include #include +#include #include "system.h" #include "alloc.h" #include "time.h" @@ -42,7 +43,7 @@ init_pp() "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - long clock, sys_time(); + time_t clock; static char dbuf[30]; static char tbuf[30]; struct tm *tp; @@ -68,7 +69,7 @@ init_pp() /* Initialize __LINE__, __FILE__, __DATE__, __TIME__, and __STDC__ macro definitions. */ - clock = sys_time(); + clock = time(NULL); tp = localtime(&clock); /* __DATE__ */ diff --git a/modules/src/system/system.3 b/modules/src/system/system.3 index 58557489c..c58c168bb 100644 --- a/modules/src/system/system.3 +++ b/modules/src/system/system.3 @@ -4,7 +4,7 @@ sys_open, sys_close, sys_read, sys_write, sys_reset, sys_access, sys_modtime, sys_remove, sys_rename, sys_filesize, sys_chmode, sys_lock, sys_unlock, -sys_break, sys_stop, sys_time \- system call interface +sys_break, sys_stop \- system call interface .SH SYNOPSIS .nf .B #include @@ -67,8 +67,6 @@ sys_break, sys_stop, sys_time \- system call interface .B void sys_stop(how) .B int how; .PP -.B long sys_time(); -.PP .B long sys_modtime(path) .B char *path; .fi diff --git a/modules/src/system/system.h b/modules/src/system/system.h index 8f8bce45c..8a5825173 100644 --- a/modules/src/system/system.h +++ b/modules/src/system/system.h @@ -50,7 +50,6 @@ _PROTOTYPE(int sys_unlock, (char *)); #endif _PROTOTYPE(char *sys_break, (int)); _PROTOTYPE(void sys_stop, (int)); -_PROTOTYPE(long sys_time, (void)); _PROTOTYPE(long sys_modtime, (char *)); /* standard file decsriptors */ diff --git a/modules/src/system/time.c b/modules/src/system/time.c deleted file mode 100644 index e06a9fa00..000000000 --- a/modules/src/system/time.c +++ /dev/null @@ -1,15 +0,0 @@ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* $Id$ */ - -#include "system.h" - -long time(); - -long -sys_time() -{ - return time((long *) 0); -} From fd9185100523b01b9561be6cbd072a6f6e617ac8 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 10 Nov 2016 22:04:18 +0100 Subject: [PATCH 168/230] Add enough return types to the K&R C that the ACK builds (on Linux) using clang now. --- lang/basic/src/eval.c | 3 +++ lang/basic/src/symbols.c | 1 + lang/basic/src/util.c | 1 + lang/cem/cemcom.ansi/LLlex.c | 3 +++ lang/cem/cemcom.ansi/arith.c | 3 +++ lang/cem/cemcom.ansi/ch3.c | 4 ++++ lang/cem/cemcom.ansi/ch3bin.c | 4 ++++ lang/cem/cemcom.ansi/code.c | 5 +++++ lang/cem/cemcom.ansi/domacro.c | 6 ++++++ lang/cem/cemcom.ansi/error.c | 4 ++-- lang/cem/cemcom.ansi/eval.c | 6 ++++++ lang/cem/cemcom.ansi/expr.c | 1 + lang/cem/cemcom.ansi/idf.c | 6 ++++++ lang/cem/cemcom.ansi/ival.g | 8 ++++++++ lang/cem/cemcom.ansi/main.c | 3 +++ lang/cem/cemcom.ansi/proto.c | 4 ++++ lang/cem/cemcom.ansi/replace.c | 7 +++++++ lang/cem/cemcom.ansi/stab.c | 2 +- lang/cem/cemcom.ansi/stack.c | 1 + lang/cem/cemcom.ansi/switch.c | 2 ++ lang/cem/cemcom.ansi/util.c | 1 + lang/cem/cpp.ansi/LLlex.c | 3 +++ lang/cem/cpp.ansi/domacro.c | 6 ++++++ lang/cem/cpp.ansi/main.c | 3 +++ lang/cem/cpp.ansi/preprocess.c | 1 + lang/cem/cpp.ansi/replace.c | 7 +++++++ lang/m2/comp/LLlex.c | 1 + lang/m2/comp/casestat.C | 5 +++++ lang/m2/comp/chk_expr.c | 1 + lang/m2/comp/code.c | 8 ++++++++ lang/m2/comp/cstoper.c | 6 ++++++ lang/m2/comp/desig.c | 1 + lang/m2/comp/enter.c | 2 ++ lang/m2/comp/error.c | 3 +++ lang/m2/comp/node.c | 1 + lang/m2/comp/stab.c | 2 +- lang/m2/comp/type.c | 3 +++ lang/m2/comp/walk.c | 9 ++++++--- lang/pc/comp/LLlex.c | 3 ++- lang/pc/comp/body.c | 6 ++++++ lang/pc/comp/casestat.C | 2 ++ lang/pc/comp/code.c | 9 +++++++++ lang/pc/comp/cstoper.c | 2 ++ lang/pc/comp/def.c | 1 + lang/pc/comp/desig.c | 4 ++++ lang/pc/comp/error.c | 3 +++ lang/pc/comp/label.c | 4 ++++ lang/pc/comp/node.c | 1 + lang/pc/comp/progs.c | 4 ++++ lang/pc/comp/readwrite.c | 13 +++++++++++++ lang/pc/comp/stab.c | 3 ++- lang/pc/comp/type.c | 4 ++++ mach/i386/as/mach5.c | 2 ++ mach/i386/ncg/mach.c | 2 ++ mach/i80/ncg/mach.c | 2 ++ mach/i86/ncg/mach.c | 2 ++ mach/m68020/as/mach5.c | 15 +++++++++++++++ mach/m68020/ncg/mach.c | 2 ++ mach/powerpc/ncg/mach.c | 2 ++ mach/proto/as/comm4.c | 5 +++++ mach/proto/as/comm5.c | 3 +++ mach/proto/as/comm6.c | 9 +++++++++ mach/proto/ncg/compute.c | 1 + mach/proto/ncg/equiv.c | 3 +++ mach/proto/ncg/fillem.c | 15 +++++++++++++++ mach/proto/ncg/gencode.c | 1 + mach/proto/ncg/label.c | 1 + mach/proto/ncg/regvar.c | 1 + mach/proto/ncg/salloc.c | 4 ++++ mach/proto/ncg/state.c | 3 +++ mach/proto/ncg/subr.c | 2 ++ mach/proto/top/top.c | 5 +++++ mach/vc4/ncg/mach.c | 2 +- util/LLgen/src/check.c | 8 ++++---- util/LLgen/src/compute.c | 24 ++++++++++++------------ util/LLgen/src/gencode.c | 24 ++++++++++++------------ util/LLgen/src/main.c | 4 +++- util/LLgen/src/reach.c | 4 ++-- util/LLgen/src/savegram.c | 8 ++++---- util/LLgen/src/tokens.c | 8 ++++---- util/LLgen/src/tokens.g | 7 ++++--- util/ack/files.c | 1 + util/ack/grows.c | 1 + util/ack/grows.h | 2 +- util/ack/main.c | 3 +++ util/ack/mktables.c | 3 +++ util/ack/rmach.c | 2 ++ util/ack/scan.c | 3 +++ util/ack/trans.c | 8 ++++++++ util/ack/util.c | 3 +++ util/amisc/anm.c | 3 +++ util/arch/archiver.c | 7 +++++++ util/ego/bo/bo.c | 4 +++- util/ego/ca/ca.c | 4 ++-- util/ego/cf/cf_loop.c | 2 +- util/ego/cj/cj.c | 5 +++-- util/ego/cs/cs.c | 2 +- util/ego/cs/cs_avail.c | 2 +- util/ego/cs/cs_debug.c | 2 +- util/ego/cs/cs_kill.c | 2 +- util/ego/cs/cs_stack.c | 1 + util/ego/ic/ic_lib.c | 2 +- util/ego/il/il1_aux.c | 1 + util/ego/il/il1_aux.h | 2 +- util/ego/il/il1_cal.c | 2 +- util/ego/il/il1_formal.c | 1 + util/ego/il/il1_formal.h | 2 +- util/ego/il/il3_change.c | 3 ++- util/ego/il/il3_change.h | 2 +- util/ego/il/il_aux.c | 1 + util/ego/lv/lv.c | 1 + util/ego/ra/ra.c | 1 + util/ego/ra/ra_items.c | 2 +- util/ego/ra/ra_xform.c | 2 ++ util/ego/share/locals.c | 8 ++++---- util/ego/share/locals.h | 4 ++-- util/ego/share/put.c | 1 + util/ego/share/put.h | 2 +- util/ego/sp/sp.c | 1 + util/ego/sr/sr.c | 1 + util/ego/sr/sr_cand.c | 2 +- util/ego/sr/sr_iv.c | 2 +- util/ego/sr/sr_reduce.c | 6 +++--- util/ego/sr/sr_xform.c | 1 + util/ego/sr/sr_xform.h | 2 +- util/ego/ud/ud.c | 1 + util/ego/ud/ud_const.c | 2 +- util/ego/ud/ud_copy.c | 4 ++-- util/ego/ud/ud_defs.c | 2 +- util/led/extract.c | 4 ++++ util/led/main.c | 11 +++++++---- util/led/memory.c | 1 + util/led/output.c | 4 ++-- util/led/save.c | 3 +++ util/ncgg/coerc.c | 4 ++++ util/ncgg/output.c | 1 + util/ncgg/set.c | 2 +- util/ncgg/subr.c | 2 ++ util/opt/cleanup.c | 1 + util/opt/flow.c | 3 +++ util/opt/getline.c | 1 + util/opt/reg.c | 2 ++ util/opt/tes.c | 1 + 143 files changed, 432 insertions(+), 94 deletions(-) diff --git a/lang/basic/src/eval.c b/lang/basic/src/eval.c index ed5b6f499..f1f762b05 100644 --- a/lang/basic/src/eval.c +++ b/lang/basic/src/eval.c @@ -31,6 +31,7 @@ int ltype,rtype; +void conversion(oldtype,newtype) int oldtype,newtype; { @@ -71,6 +72,7 @@ int oldtype,newtype; +void extraconvert(oldtype,newtype,topstack) int oldtype,newtype,topstack; { @@ -509,6 +511,7 @@ endarrayload() +void loadarray(type) int type; { diff --git a/lang/basic/src/symbols.c b/lang/basic/src/symbols.c index 30c3b5e8b..96d148ae3 100644 --- a/lang/basic/src/symbols.c +++ b/lang/basic/src/symbols.c @@ -68,6 +68,7 @@ char *str; +void dcltype(s) Symbol *s; { diff --git a/lang/basic/src/util.c b/lang/basic/src/util.c index 8255b39a1..ff98cf82b 100644 --- a/lang/basic/src/util.c +++ b/lang/basic/src/util.c @@ -16,6 +16,7 @@ int errorcnt; +void warning(str) char *str; { diff --git a/lang/cem/cemcom.ansi/LLlex.c b/lang/cem/cemcom.ansi/LLlex.c index 07a79ad8e..d0632536d 100644 --- a/lang/cem/cemcom.ansi/LLlex.c +++ b/lang/cem/cemcom.ansi/LLlex.c @@ -52,6 +52,8 @@ extern int lint_skip_comment; static struct token LexStack[MAX_LL_DEPTH]; static LexSP = 0; +void skipcomment(); + /* In PushLex() the actions are taken in order to initialise or re-initialise the lexical scanner. E.g. at the invocation of a sub-parser that uses LLlex(), the @@ -442,6 +444,7 @@ garbage: } #ifndef NOPP +void skipcomment() { /* The last character read has been the '*' of '/_*'. The diff --git a/lang/cem/cemcom.ansi/arith.c b/lang/cem/cemcom.ansi/arith.c index d5f3af3e7..317107a43 100644 --- a/lang/cem/cemcom.ansi/arith.c +++ b/lang/cem/cemcom.ansi/arith.c @@ -30,6 +30,7 @@ extern char options[]; extern arith flt_flt2arith(); extern label code_string(); +void arithbalance(e1p, oper, e2p) /* 3.1.2.5 */ register struct expr **e1p, **e2p; int oper; @@ -523,6 +524,7 @@ opnd2logical(expp, oper) } } +void opnd2test(expp, oper) register struct expr **expp; { @@ -548,6 +550,7 @@ opnd2test(expp, oper) ch3bin(expp, NOTEQUAL, intexpr((arith)0, INT)); } +void any2opnd(expp, oper) register struct expr **expp; { diff --git a/lang/cem/cemcom.ansi/ch3.c b/lang/cem/cemcom.ansi/ch3.c index bebe77efa..eef806776 100644 --- a/lang/cem/cemcom.ansi/ch3.c +++ b/lang/cem/cemcom.ansi/ch3.c @@ -23,11 +23,14 @@ extern char options[]; extern char *symbol2str(); extern struct type *qualifier_type(); +void ch3cast(); + /* Most expression-handling routines have a pointer to a (struct type *) as first parameter. The object under the pointer gets updated in the process. */ +void ch3sel(expp, oper, idf) struct expr **expp; struct idf *idf; @@ -169,6 +172,7 @@ ch3incr(expp, oper) ch3asgn(expp, oper, intexpr((arith)1, INT)); } +void ch3cast(expp, oper, tp) register struct expr **expp; register struct type *tp; diff --git a/lang/cem/cemcom.ansi/ch3bin.c b/lang/cem/cemcom.ansi/ch3bin.c index 8145b933d..ba75c112c 100644 --- a/lang/cem/cemcom.ansi/ch3bin.c +++ b/lang/cem/cemcom.ansi/ch3bin.c @@ -19,6 +19,8 @@ extern char options[]; extern char *symbol2str(); +void pntminuspnt(); + /* This chapter asks for the repeated application of code to handle an operation that may be executed at compile time or at run time, depending on the constancy of the operands. @@ -32,6 +34,7 @@ extern char *symbol2str(); #define commutative_binop(expp, oper, expr) mk_binop(expp, oper, expr, 1) #define non_commutative_relop(expp, oper, expr) mk_binop(expp, oper, expr, 1) +void ch3bin(expp, oper, expr) register struct expr **expp; struct expr *expr; @@ -292,6 +295,7 @@ ch3bin(expp, oper, expr) } } +void pntminuspnt(expp, oper, expr) register struct expr **expp, *expr; { diff --git a/lang/cem/cemcom.ansi/code.c b/lang/cem/cemcom.ansi/code.c index 1beeb12c4..abfd2b2b2 100644 --- a/lang/cem/cemcom.ansi/code.c +++ b/lang/cem/cemcom.ansi/code.c @@ -64,6 +64,8 @@ extern char options[]; extern char *symbol2str(); extern char *source; +void loc_init(); + #ifndef LINT init_code(dst_file) char *dst_file; @@ -415,6 +417,7 @@ do_return_expr(expr) return_expr_occurred = 1; } +void code_declaration(idf, expr, lvl, sc) register struct idf *idf; /* idf to be declared */ struct expr *expr; /* initialisation; NULL if absent */ @@ -527,6 +530,7 @@ code_declaration(idf, expr, lvl, sc) } } +void loc_init(expr, id) struct expr *expr; struct idf *id; @@ -721,6 +725,7 @@ code_break() it generates a branch instruction to the continue label of the innermost statement in which continue has a meaning. */ +void code_continue() { register struct stmt_block *stmt_block = stmt_stack; diff --git a/lang/cem/cemcom.ansi/domacro.c b/lang/cem/cemcom.ansi/domacro.c index 4173a11b2..d0fe7a96d 100644 --- a/lang/cem/cemcom.ansi/domacro.c +++ b/lang/cem/cemcom.ansi/domacro.c @@ -34,6 +34,9 @@ char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */ int nestlevel = -1; +void macro_def(); +void do_define(); + struct idf * GetIdentifier(skiponerr) int skiponerr; /* skip the rest of the line on error */ @@ -145,6 +148,7 @@ domacro() int lint_skip_comment; #endif +void skip_block(to_endif) int to_endif; { @@ -347,6 +351,7 @@ do_include() } } +void do_define() { /* do_define() interprets a #define control line. @@ -574,6 +579,7 @@ getparams(buf, parbuf) /*NOTREACHED*/ } +void macro_def(id, text, nformals, length, flags) register struct idf *id; char *text; diff --git a/lang/cem/cemcom.ansi/error.c b/lang/cem/cemcom.ansi/error.c index 10b237db4..6f2283b74 100644 --- a/lang/cem/cemcom.ansi/error.c +++ b/lang/cem/cemcom.ansi/error.c @@ -57,7 +57,7 @@ extern char loptions[]; expression, whereas other errors use the information in the token. */ -static _error(); +static void _error(); #if __STDC__ /*VARARGS*/ @@ -521,7 +521,7 @@ fatal(va_alist) /* fmt, args */ } #endif -static +static void _error(class, fn, ln, fmt, ap) int class; char *fn; diff --git a/lang/cem/cemcom.ansi/eval.c b/lang/cem/cemcom.ansi/eval.c index 16f19c0ad..f678682c2 100644 --- a/lang/cem/cemcom.ansi/eval.c +++ b/lang/cem/cemcom.ansi/eval.c @@ -37,6 +37,9 @@ arith NewLocal(); /* util.c */ #define LocalPtrVar() NewLocal(pointer_size, pointer_align, reg_pointer, REGISTER) extern int err_occurred; /* error.c */ +void store_val(); +void load_val(); + /* EVAL() is the main expression-tree evaluator, which turns any legal expression tree into EM code. parameters.h: @@ -63,6 +66,7 @@ extern int err_occurred; /* error.c */ labels, in case they are specified (i.e. are non-zero) */ +void EVAL(expr, val, code, true_label, false_label) register struct expr *expr; int val, code; @@ -836,6 +840,7 @@ ptr_add(size) - into a local static variable - absolute addressing */ +void store_val(vl, tp) register struct value *vl; register struct type *tp; @@ -907,6 +912,7 @@ store_val(vl, tp) - static variable - local variable */ +void load_val(expr, rlval) register struct expr *expr; /* expression containing the value */ int rlval; /* generate either LVAL or RVAL */ diff --git a/lang/cem/cemcom.ansi/expr.c b/lang/cem/cemcom.ansi/expr.c index 6d8c1e23d..3a7e3c494 100644 --- a/lang/cem/cemcom.ansi/expr.c +++ b/lang/cem/cemcom.ansi/expr.c @@ -369,6 +369,7 @@ new_oper(tp, e1, oper, e2) return expr; } +void chk_cst_expr(expp) struct expr **expp; { diff --git a/lang/cem/cemcom.ansi/idf.c b/lang/cem/cemcom.ansi/idf.c index eb43e34bb..4edc88456 100644 --- a/lang/cem/cemcom.ansi/idf.c +++ b/lang/cem/cemcom.ansi/idf.c @@ -37,6 +37,8 @@ extern char *symbol2str(); #include +void global_redecl(); + struct idf * gen_idf() { @@ -248,6 +250,7 @@ declare_idf(ds, dc, lvl) } } +int actual_declaration(sc, tp) int sc; struct type *tp; @@ -269,6 +272,7 @@ actual_declaration(sc, tp) return 1; } +void global_redecl(idf, new_sc, tp) register struct idf *idf; struct type *tp; @@ -393,6 +397,7 @@ declare_params(dc) } } +void idf_initialized(idf) register struct idf *idf; { @@ -429,6 +434,7 @@ declare_enum(tp, idf, l) idf->id_def->df_address = l; } +void check_formals(idf, dc) struct idf *idf; struct declarator *dc; diff --git a/lang/cem/cemcom.ansi/ival.g b/lang/cem/cemcom.ansi/ival.g index b085ebc73..757bb721b 100644 --- a/lang/cem/cemcom.ansi/ival.g +++ b/lang/cem/cemcom.ansi/ival.g @@ -46,6 +46,11 @@ static int pack_level; struct type **gen_tphead(), **gen_tpmiddle(); struct sdef *gen_align_to_next(); struct e_stack *p_stack; + +void pad(); +void gen_simple_exp(); +void gen_tpcheck(); + } /* initial_value recursively guides the initialisation expression. @@ -122,6 +127,7 @@ initial_value_list(register struct type **tpp; struct expr **expp;) ; { +void gen_tpcheck(tpp) struct type **tpp; { @@ -147,6 +153,7 @@ gen_tpcheck(tpp) } } +void gen_simple_exp(tpp, expp) struct type **tpp; struct expr **expp; @@ -465,6 +472,7 @@ check_and_pad(expp, tpp) /* pad() fills an element of type tp with zeroes. If the element is an aggregate, pad() is called recursively. */ +void pad(tpx) struct type *tpx; { diff --git a/lang/cem/cemcom.ansi/main.c b/lang/cem/cemcom.ansi/main.c index 556e23495..1bb72ae85 100644 --- a/lang/cem/cemcom.ansi/main.c +++ b/lang/cem/cemcom.ansi/main.c @@ -46,6 +46,8 @@ struct sp_id special_ids[] = { {0, 0} }; +void dependency(); + #ifndef NOCROSS arith short_size = SZ_SHORT, @@ -181,6 +183,7 @@ char *s; } } +void dependency(s, source) char *s, *source; { diff --git a/lang/cem/cemcom.ansi/proto.c b/lang/cem/cemcom.ansi/proto.c index 1f7f6bf6d..b237f3433 100644 --- a/lang/cem/cemcom.ansi/proto.c +++ b/lang/cem/cemcom.ansi/proto.c @@ -26,6 +26,7 @@ extern char options[]; +void check_for_void(pl) register struct proto *pl; { @@ -261,6 +262,7 @@ declare_protos(dc) } +void update_proto(tp, otp) register struct type *tp, *otp; { @@ -312,6 +314,7 @@ update_proto(tp, otp) /* struct/union and enum tags can be declared inside prototypes * remove them from the symbol-table */ +void remove_proto_tag(tp) struct type *tp; { @@ -380,6 +383,7 @@ remove_proto_idfs(pl) } } +void call_proto(expp) register struct expr **expp; { diff --git a/lang/cem/cemcom.ansi/replace.c b/lang/cem/cemcom.ansi/replace.c index cde3aaf43..50978be3c 100644 --- a/lang/cem/cemcom.ansi/replace.c +++ b/lang/cem/cemcom.ansi/replace.c @@ -26,6 +26,10 @@ extern int InputLevel; struct repl *ReplaceList; /* list of currently active macros */ extern char *strcat(), *strcpy(); +void macro2buffer(); +void getactuals(); +void expand_defined(); + int replace(idf) register struct idf *idf; @@ -172,6 +176,7 @@ expand_macro(repl, idf) return 1; } +void expand_defined(repl) register struct repl *repl; { @@ -211,6 +216,7 @@ newarg(args) args->a_rawptr = args->a_rawbuf = Malloc(args->a_rawsize = ARGBUF); } +void getactuals(repl, idf) struct repl *repl; register struct idf *idf; @@ -529,6 +535,7 @@ macro_func(idef) } } +void macro2buffer(repl, idf, args) register struct repl *repl; register struct idf *idf; diff --git a/lang/cem/cemcom.ansi/stab.c b/lang/cem/cemcom.ansi/stab.c index 8c00838e3..f80b360b4 100644 --- a/lang/cem/cemcom.ansi/stab.c +++ b/lang/cem/cemcom.ansi/stab.c @@ -72,7 +72,7 @@ adds_db_str(s) while (*s) addc_db_str(*s++); } -static +static void stb_type(tp) register struct type *tp; { diff --git a/lang/cem/cemcom.ansi/stack.c b/lang/cem/cemcom.ansi/stack.c index 49dfbfab4..c8616b86e 100644 --- a/lang/cem/cemcom.ansi/stack.c +++ b/lang/cem/cemcom.ansi/stack.c @@ -57,6 +57,7 @@ stack_level() { #endif /* LINT */ } +void stack_idf(idf, stl) struct idf *idf; register struct stack_level *stl; diff --git a/lang/cem/cemcom.ansi/switch.c b/lang/cem/cemcom.ansi/switch.c index 856e1b115..3cce2c622 100644 --- a/lang/cem/cemcom.ansi/switch.c +++ b/lang/cem/cemcom.ansi/switch.c @@ -159,6 +159,7 @@ code_endswitch() unstack_stmt(); } +void code_case(expr) struct expr *expr; { @@ -227,6 +228,7 @@ code_case(expr) } } +void code_default() { register struct switch_hdr *sh = switch_stack; diff --git a/lang/cem/cemcom.ansi/util.c b/lang/cem/cemcom.ansi/util.c index 7326f04ec..273fa8d78 100644 --- a/lang/cem/cemcom.ansi/util.c +++ b/lang/cem/cemcom.ansi/util.c @@ -163,6 +163,7 @@ LocalFinish() #endif } +void RegisterAccount(offset, size, regtype, sc) arith offset, size; { diff --git a/lang/cem/cpp.ansi/LLlex.c b/lang/cem/cpp.ansi/LLlex.c index 3cd162898..dbf8d9ea1 100644 --- a/lang/cem/cpp.ansi/LLlex.c +++ b/lang/cem/cpp.ansi/LLlex.c @@ -35,6 +35,8 @@ extern arith char_constant(); #define FLG_ESEEN 0x01 /* possibly a floating point number */ #define FLG_DOTSEEN 0x02 /* certainly a floating point number */ +void skipcomment(); + int LLlex() { @@ -325,6 +327,7 @@ garbage: /*NOTREACHED*/ } +void skipcomment() { /* The last character read has been the '*' of '/_*'. The diff --git a/lang/cem/cpp.ansi/domacro.c b/lang/cem/cpp.ansi/domacro.c index a5cc9407d..306ed32cc 100644 --- a/lang/cem/cpp.ansi/domacro.c +++ b/lang/cem/cpp.ansi/domacro.c @@ -32,6 +32,9 @@ int svnestlevel[30] = {-1}; int nestcount; extern int do_preprocess; +void macro_def(); +void do_define(); + char * GetIdentifier(skiponerr) int skiponerr; /* skip the rest of the line on error */ @@ -148,6 +151,7 @@ domacro() } } +void skip_block(to_endif) int to_endif; { @@ -327,6 +331,7 @@ do_include() } } +void do_define() { /* do_define() interprets a #define control line. @@ -566,6 +571,7 @@ getparams(buf, parbuf) /*NOTREACHED*/ } +void macro_def(id, text, nformals, length, flags) register struct idf *id; char *text; diff --git a/lang/cem/cpp.ansi/main.c b/lang/cem/cpp.ansi/main.c index db444ae80..225562be0 100644 --- a/lang/cem/cpp.ansi/main.c +++ b/lang/cem/cpp.ansi/main.c @@ -32,6 +32,8 @@ char *prog_name; extern char **inctable; extern int inc_max, inc_total; +void dependency(); + main(argc, argv) char *argv[]; { @@ -140,6 +142,7 @@ add_dependency(s) } } +void dependency(s, source) char *s, *source; { diff --git a/lang/cem/cpp.ansi/preprocess.c b/lang/cem/cpp.ansi/preprocess.c index 7c3840d80..3d26b18e0 100644 --- a/lang/cem/cpp.ansi/preprocess.c +++ b/lang/cem/cpp.ansi/preprocess.c @@ -102,6 +102,7 @@ do_pragma() char Xbuf[256]; +void preprocess(fn) char *fn; { diff --git a/lang/cem/cpp.ansi/replace.c b/lang/cem/cpp.ansi/replace.c index 255902f68..cd7d60696 100644 --- a/lang/cem/cpp.ansi/replace.c +++ b/lang/cem/cpp.ansi/replace.c @@ -26,6 +26,10 @@ extern char *strcat(); extern int InputLevel; struct repl *ReplaceList; /* list of currently active macros */ +void expand_defined(); +void getactuals(); +void macro2buffer(); + int replace(idf) register struct idf *idf; @@ -165,6 +169,7 @@ expand_macro(repl, idf) return 1; } +void expand_defined(repl) register struct repl *repl; { @@ -208,6 +213,7 @@ newarg(args) args->a_rawptr = args->a_rawbuf = Malloc((unsigned)(args->a_rawsize = ARGBUF)); } +void getactuals(repl, idf) struct repl *repl; register struct idf *idf; @@ -522,6 +528,7 @@ macro_func(idef) } } +void macro2buffer(repl, idf, args) register struct repl *repl; register struct idf *idf; diff --git a/lang/m2/comp/LLlex.c b/lang/m2/comp/LLlex.c index 1eacae76f..083947161 100644 --- a/lang/m2/comp/LLlex.c +++ b/lang/m2/comp/LLlex.c @@ -180,6 +180,7 @@ getch() return ch; } +void CheckForLineDirective() { register int ch = getch(); diff --git a/lang/m2/comp/casestat.C b/lang/m2/comp/casestat.C index d227e3117..a4c2285d2 100644 --- a/lang/m2/comp/casestat.C +++ b/lang/m2/comp/casestat.C @@ -54,6 +54,9 @@ struct case_entry { arith ce_low, ce_up; /* lower and upper bound of range */ }; +void AddCases(); +void AddOneCase(); + /* STATICALLOCDEF "case_entry" 20 */ /* The constant DENSITY determines when CSA and when CSB instructions @@ -237,6 +240,7 @@ FreeSh(sh) free_switch_hdr(sh); } +void AddCases(sh, node, lbl) struct switch_hdr *sh; register t_node *node; @@ -264,6 +268,7 @@ AddCases(sh, node, lbl) AddOneCase(sh, node, node, lbl); } +void AddOneCase(sh, lnode, rnode, lbl) register struct switch_hdr *sh; t_node *lnode, *rnode; diff --git a/lang/m2/comp/chk_expr.c b/lang/m2/comp/chk_expr.c index 7dbe5abc6..e87725688 100644 --- a/lang/m2/comp/chk_expr.c +++ b/lang/m2/comp/chk_expr.c @@ -53,6 +53,7 @@ df_error(nd, mess, edf) else node_error(nd, mess); } +void MkCoercion(pnd, tp) t_node **pnd; register t_type *tp; diff --git a/lang/m2/comp/code.c b/lang/m2/comp/code.c index f74231cb0..a6d283af6 100644 --- a/lang/m2/comp/code.c +++ b/lang/m2/comp/code.c @@ -37,6 +37,10 @@ extern char options[]; extern t_desig null_desig; int fp_used; +void RangeCheck(); +void CodeParameters(); +void CodeCall(); + CodeConst(cst, size) arith cst; int size; @@ -55,6 +59,7 @@ CodeConst(cst, size) } } +void CodeString(nd) register t_node *nd; { @@ -288,6 +293,7 @@ CodeCoercion(t1, t2) } } +void CodeCall(nd) register t_node *nd; { @@ -355,6 +361,7 @@ CodeCall(nd) DoLineno(nd); } +void CodeParameters(param, arg) t_param *param; register t_node *arg; @@ -672,6 +679,7 @@ needs_rangecheck(tpl, tpr) return 0; } +void RangeCheck(tpl, tpr) register t_type *tpl, *tpr; { diff --git a/lang/m2/comp/cstoper.c b/lang/m2/comp/cstoper.c index c55d4389f..b7b13f9a4 100644 --- a/lang/m2/comp/cstoper.c +++ b/lang/m2/comp/cstoper.c @@ -45,6 +45,8 @@ arith min_int[] = { 0L, -128L, -32768L, 0L, -2147483647L-1 }; extern char options[]; +void CutSize(); + overflow(expp) t_node *expp; { @@ -160,6 +162,7 @@ divide(pdiv, prem) #endif } +void cstibin(expp) t_node **expp; { @@ -351,6 +354,7 @@ cstfbin(expp) CutSize(exp); } +void cstubin(expp) t_node **expp; { @@ -457,6 +461,7 @@ cstubin(expp) CutSize(exp); } +void cstset(expp) t_node **expp; { @@ -648,6 +653,7 @@ cstcall(expp, call) } } +void CutSize(expr) register t_node *expr; { diff --git a/lang/m2/comp/desig.c b/lang/m2/comp/desig.c index f2ea83a81..2a6ae34be 100644 --- a/lang/m2/comp/desig.c +++ b/lang/m2/comp/desig.c @@ -533,6 +533,7 @@ CodeFieldDesig(df, ds) } } +void CodeVarDesig(df, ds) register t_def *df; register t_desig *ds; diff --git a/lang/m2/comp/enter.c b/lang/m2/comp/enter.c index 12f3e4e9d..ecd004fde 100644 --- a/lang/m2/comp/enter.c +++ b/lang/m2/comp/enter.c @@ -247,6 +247,7 @@ EnterParamList(ppr, Idlist, type, VARp, off) STATIC t_def *DoImport(); +void ImportEffects(idef, scope, flag) register t_def *idef; t_scope *scope; @@ -481,6 +482,7 @@ CheckForImports(df) } } +void EnterFromImportList(idlist, FromDef, FromId) register t_node *idlist; register t_def *FromDef; diff --git a/lang/m2/comp/error.c b/lang/m2/comp/error.c index 410f7d15f..26b5512b4 100644 --- a/lang/m2/comp/error.c +++ b/lang/m2/comp/error.c @@ -61,6 +61,8 @@ extern char *symbol2str(); node, whereas other errors use the information in the token. */ +void _error(); + #if __STDC__ #ifdef DEBUG /*VARARGS*/ @@ -318,6 +320,7 @@ crash(va_alist) } #endif +void _error(class, node, fmt, ap, warn_class) int class; t_node *node; diff --git a/lang/m2/comp/node.c b/lang/m2/comp/node.c index 910769e0d..43db6a239 100644 --- a/lang/m2/comp/node.c +++ b/lang/m2/comp/node.c @@ -81,6 +81,7 @@ dot2leaf(class) return nd; } +void FreeNode(nd) register t_node *nd; { diff --git a/lang/m2/comp/stab.c b/lang/m2/comp/stab.c index 5aae2a1e5..4f4e2e3ac 100644 --- a/lang/m2/comp/stab.c +++ b/lang/m2/comp/stab.c @@ -71,7 +71,7 @@ adds_db_str(s) while (*s) addc_db_str(*s++); } -static +static void stb_type(tp, assign_num) register t_type *tp; { diff --git a/lang/m2/comp/type.c b/lang/m2/comp/type.c index 247e5e280..b70f2b4b1 100644 --- a/lang/m2/comp/type.c +++ b/lang/m2/comp/type.c @@ -74,6 +74,8 @@ t_type *std_type, *error_type; +void ArraySizes(); + t_type * construct_type(fund, tp) int fund; @@ -576,6 +578,7 @@ ArrayElSize(tp) } } +void ArraySizes(tp) register t_type *tp; { diff --git a/lang/m2/comp/walk.c b/lang/m2/comp/walk.c index de9a63552..93cc3308b 100644 --- a/lang/m2/comp/walk.c +++ b/lang/m2/comp/walk.c @@ -64,7 +64,7 @@ static int WalkDef(); static int stabdef(); #endif static int MkCalls(); -static int UseWarnings(); +static void UseWarnings(); #define NO_EXIT_LABEL ((label) 0) #define RETURN_LABEL ((label) 1) @@ -72,6 +72,8 @@ static int UseWarnings(); #define REACH_FLAG 1 #define EXIT_FLAG 2 +void DoAssign(); + int LblWalkNode(lbl, nd, exit, reach) label lbl, exit; @@ -995,6 +997,7 @@ node_warning(nd, W_OLDFASHIONED, "compatibility required in FOR statement"); return 1; } +void DoAssign(nd) register t_node *nd; { @@ -1057,7 +1060,7 @@ RegisterMessage(df) } } -static +static void df_warning(nd, df, warning) t_node *nd; t_def *df; @@ -1080,7 +1083,7 @@ df_warning(nd, df, warning) } } -static +static void UseWarnings(df) register t_def *df; { diff --git a/lang/pc/comp/LLlex.c b/lang/pc/comp/LLlex.c index 6074870f7..7bd857a2b 100644 --- a/lang/pc/comp/LLlex.c +++ b/lang/pc/comp/LLlex.c @@ -120,7 +120,7 @@ CommentOptions() } -STATIC +STATIC void SkipComment() { /* Skip ISO-Pascal comments (* ... *) or { ... }. @@ -216,6 +216,7 @@ register int delim; static char *s_error = "illegal line directive"; +void CheckForLineDirective() { register int ch; diff --git a/lang/pc/comp/body.c b/lang/pc/comp/body.c index f2f7a1a04..091ab6927 100644 --- a/lang/pc/comp/body.c +++ b/lang/pc/comp/body.c @@ -47,6 +47,7 @@ MarkDef(nd, flags, on) } } +void AssertStat(expp, line) register struct node *expp; unsigned short line; @@ -69,6 +70,7 @@ AssertStat(expp, line) } } +void AssignStat(left, right) register struct node *left, *right; { @@ -131,6 +133,7 @@ AssignStat(left, right) FreeNode(right); } +void ProcStat(nd) register struct node *nd; { @@ -142,6 +145,7 @@ ProcStat(nd) } } +void ChkForStat(nd) register struct node *nd; { @@ -202,6 +206,7 @@ ChkForStat(nd) return; } +void EndForStat(nd) register struct node *nd; { @@ -283,6 +288,7 @@ CodeEndFor(nd, stepsize, l1, l2, tmp2) C_asp(int_size); } +void WithStat(nd) struct node *nd; { diff --git a/lang/pc/comp/casestat.C b/lang/pc/comp/casestat.C index 61eba13f7..554a6216d 100644 --- a/lang/pc/comp/casestat.C +++ b/lang/pc/comp/casestat.C @@ -40,6 +40,7 @@ struct case_entry { */ #define compact(nr, low, up) (nr != 0 && (up - low) / nr <= DENSITY) +void CaseExpr(nd) struct node *nd; { @@ -62,6 +63,7 @@ CaseExpr(nd) } } +void CaseEnd(nd, exit_label) struct node *nd; label exit_label; diff --git a/lang/pc/comp/code.c b/lang/pc/comp/code.c index 17f0f7c32..1c916c3dc 100644 --- a/lang/pc/comp/code.c +++ b/lang/pc/comp/code.c @@ -24,6 +24,11 @@ int fp_used; +void Long2Int(); +void Int2Long(); +void genrck(); +void CodeCall(); + CodeFil() { if ( !options['L'] ) @@ -791,6 +796,7 @@ CodePString(nd, tp) C_loi(tp->tp_size); } +void CodeCall(nd) register struct node *nd; { @@ -1095,6 +1101,7 @@ CodeStd(nd) } } +void Long2Int() { /* convert a long to integer */ @@ -1106,6 +1113,7 @@ Long2Int() C_cii(); } +void Int2Long() { /* convert integer to long */ @@ -1160,6 +1168,7 @@ RangeCheck(tpl, tpr) } } +void genrck(tp) register struct type *tp; { diff --git a/lang/pc/comp/cstoper.c b/lang/pc/comp/cstoper.c index be9dbc387..c4196e522 100644 --- a/lang/pc/comp/cstoper.c +++ b/lang/pc/comp/cstoper.c @@ -66,6 +66,7 @@ cstunary(expp) expp->nd_right = NULLNODE; } +void cstbin(expp) register struct node *expp; { @@ -195,6 +196,7 @@ cstbin(expp) expp->nd_left = expp->nd_right = NULLNODE; } +void cstset(expp) register struct node *expp; { diff --git a/lang/pc/comp/def.c b/lang/pc/comp/def.c index dfc33f459..745bb48e0 100644 --- a/lang/pc/comp/def.c +++ b/lang/pc/comp/def.c @@ -116,6 +116,7 @@ define(id, scope, kind) return MkDef(id, scope, kind); } +void DoDirective(directive, nd, tp, scl, function) struct idf *directive; struct node *nd; diff --git a/lang/pc/comp/desig.c b/lang/pc/comp/desig.c index 68c5512a9..566bb36a4 100644 --- a/lang/pc/comp/desig.c +++ b/lang/pc/comp/desig.c @@ -26,6 +26,7 @@ struct desig InitDesig = {DSG_INIT, 0, 0, NULLDEF, 0}; struct withdesig *WithDesigs; +void CodeValue(); STATIC int properly(ds, size, al) @@ -71,6 +72,7 @@ CodeCopy(lhs, rhs, sz, psize) C_sti(sz); } +void CodeMove(rhs, left, rtp) register struct desig *rhs; register struct node *left; @@ -150,6 +152,7 @@ CodeMove(rhs, left, rtp) } } +void CodeValue(ds, tp) register struct desig *ds; register struct type *tp; @@ -366,6 +369,7 @@ CodeFieldDesig(df, ds) ds->dsg_packed = df->fld_flags & F_PACKED; } +void CodeVarDesig(df, ds) register struct def *df; register struct desig *ds; diff --git a/lang/pc/comp/error.c b/lang/pc/comp/error.c index 8a381c6fe..dd75c79e6 100644 --- a/lang/pc/comp/error.c +++ b/lang/pc/comp/error.c @@ -39,6 +39,8 @@ int err_occurred; extern char *symbol2str(); +void _error(); + /* There are three general error-message functions: lexerror() lexical and pre-processor error messages error() syntactic and pre-processor messagese @@ -304,6 +306,7 @@ crash(va_alist) } #endif +void _error(class, node, fmt, ap) int class; struct node *node; diff --git a/lang/pc/comp/label.c b/lang/pc/comp/label.c index 73745ba21..b303b7dc5 100644 --- a/lang/pc/comp/label.c +++ b/lang/pc/comp/label.c @@ -12,6 +12,8 @@ #include "scope.h" #include "type.h" +void CodeLabel(); + DeclLabel(nd) struct node *nd; @@ -103,6 +105,7 @@ TstLabel(nd, Slevel) CodeLabel(df, 1); } +void DefLabel(nd, Slevel) register struct node *nd; { @@ -139,6 +142,7 @@ DefLabel(nd, Slevel) } } +void CodeLabel(df, local) register struct def *df; { diff --git a/lang/pc/comp/node.c b/lang/pc/comp/node.c index 889e855f8..1d8a491f0 100644 --- a/lang/pc/comp/node.c +++ b/lang/pc/comp/node.c @@ -42,6 +42,7 @@ MkLeaf(class, token) return nd; } +void FreeNode(nd) register struct node *nd; { diff --git a/lang/pc/comp/progs.c b/lang/pc/comp/progs.c index 173767526..6ed227eb9 100644 --- a/lang/pc/comp/progs.c +++ b/lang/pc/comp/progs.c @@ -15,6 +15,8 @@ static int inpflag = 0; /* input mentioned in heading ? */ static int outpflag = 0; /* output mentioned in heading ? */ static label extfl_label; /* label of array of file pointers */ +void make_extfl_args(); + set_inp() { inpflag = 1; @@ -25,6 +27,7 @@ set_outp() outpflag = 1; } +void make_extfl() { if( err_occurred ) return; @@ -54,6 +57,7 @@ make_extfl() make_extfl_args( GlobalScope->sc_def ); } +void make_extfl_args(df) register struct def *df; { diff --git a/lang/pc/comp/readwrite.c b/lang/pc/comp/readwrite.c index 7b62aaede..35ed8860d 100644 --- a/lang/pc/comp/readwrite.c +++ b/lang/pc/comp/readwrite.c @@ -19,6 +19,12 @@ extern char *sprint(); +void CodeRead(); +void CodeReadln(); +void CodeWrite(); +void CodeWriteln(); + +void ChkRead(arg) register struct node *arg; { @@ -86,6 +92,7 @@ ChkRead(arg) } } +void ChkReadln(arg) register struct node *arg; { @@ -142,6 +149,7 @@ ChkReadln(arg) CodeReadln(file); } +void ChkWrite(arg) register struct node *arg; { @@ -183,6 +191,7 @@ ChkWrite(arg) } } +void ChkWriteln(arg) register struct node *arg; { @@ -318,6 +327,7 @@ ChkStdInOut(name, st_out) return nd; } +void CodeRead(file, arg) register struct node *file, *arg; { @@ -376,6 +386,7 @@ CodeRead(file, arg) } } +void CodeReadln(file) struct node *file; { @@ -386,6 +397,7 @@ CodeReadln(file) C_asp(pointer_size); } +void CodeWrite(file, arg) register struct node *file, *arg; { @@ -472,6 +484,7 @@ CodeWrite(file, arg) } } +void CodeWriteln(file) register struct node *file; { diff --git a/lang/pc/comp/stab.c b/lang/pc/comp/stab.c index d5e4ee3fb..0b8c52f23 100644 --- a/lang/pc/comp/stab.c +++ b/lang/pc/comp/stab.c @@ -71,7 +71,7 @@ adds_db_str(s) while (*s) addc_db_str(*s++); } -static +static void stb_type(tp, assign_num) register struct type *tp; { @@ -247,6 +247,7 @@ stb_addtp(s, tp) (arith) 0); } +void stb_string(df, kind) register struct def *df; long kind; diff --git a/lang/pc/comp/type.c b/lang/pc/comp/type.c index b5662c658..faca8fee5 100644 --- a/lang/pc/comp/type.c +++ b/lang/pc/comp/type.c @@ -51,6 +51,8 @@ struct type *void_type, *error_type; +void ArraySizes(); + CheckTypeSizes() { /* first, do some checking @@ -442,6 +444,7 @@ ArrayElSize(tp, packed) return algn; } +void ArraySizes(tp) register struct type *tp; { @@ -489,6 +492,7 @@ ArraySizes(tp) C_rom_cst(tp->arr_elsize); } +void FreeForward(for_type) register struct forwtype *for_type; { diff --git a/mach/i386/as/mach5.c b/mach/i386/as/mach5.c index 9853c6c0c..8d638c922 100644 --- a/mach/i386/as/mach5.c +++ b/mach/i386/as/mach5.c @@ -38,6 +38,7 @@ ea_1_16(param) } } +void ea_1(param) { if (! address_long) { ea_1_16(param); @@ -134,6 +135,7 @@ regsize(sz) } } +void indexed() { if (address_long) { mod_2 = 0; diff --git a/mach/i386/ncg/mach.c b/mach/i386/ncg/mach.c index e3b74053a..7514d6775 100644 --- a/mach/i386/ncg/mach.c +++ b/mach/i386/ncg/mach.c @@ -61,6 +61,7 @@ string holstr(n) word n; { full lbytes; #endif +void prolog(nlocals) full nlocals; { fputs("push ebp\nmov ebp,esp\n", codefile); @@ -179,6 +180,7 @@ mach_option(s) } #endif /* MACH_OPTIONS */ +void mes(type) word type ; { int argt, a1, a2 ; diff --git a/mach/i80/ncg/mach.c b/mach/i80/ncg/mach.c index 7cf0b92a5..9f952f0d9 100644 --- a/mach/i80/ncg/mach.c +++ b/mach/i80/ncg/mach.c @@ -54,6 +54,7 @@ con_float() { } +void prolog(nlocals) full nlocals; { fprintf(codefile,"\tpush\tb\n\tlxi\th,0\n\tdad\tsp\n\tmov\tb,h\n\tmov\tc,l\n"); @@ -67,6 +68,7 @@ prolog(nlocals) full nlocals; { } } +void mes(type) word type ; { int argt ; diff --git a/mach/i86/ncg/mach.c b/mach/i86/ncg/mach.c index e222522ad..a305d6d9a 100644 --- a/mach/i86/ncg/mach.c +++ b/mach/i86/ncg/mach.c @@ -61,6 +61,7 @@ string holstr(n) word n; { full lbytes; #endif +void prolog(nlocals) full nlocals; { fputs("\tpush\tbp\n\tmov\tbp,sp\n", codefile); @@ -157,6 +158,7 @@ regreturn() } #endif /* REGVARS */ +void mes(type) word type ; { int argt ; diff --git a/mach/m68020/as/mach5.c b/mach/m68020/as/mach5.c index 12ccf087a..e623bd01f 100644 --- a/mach/m68020/as/mach5.c +++ b/mach/m68020/as/mach5.c @@ -21,6 +21,8 @@ * then emitted in one go, by emit_instr(). */ +void move_special(); + emit_instr() { register instr_t *ip; @@ -70,6 +72,7 @@ long words; T_EMIT2((short)(words), 0, 0, 0); } +void ea_1(sz, bits) { /* Because displacements come in three sizes (null displacement, @@ -242,6 +245,7 @@ badoperand() serror("bad operand(s)"); } +void shift_op(opc, sz) { if (mrg_1 < 010 && mrg_2 < 010) { @@ -263,6 +267,7 @@ shift_op(opc, sz) ea_2(SIZE_W, MEM|ALT); } +void bitop(opc) { register bits; @@ -291,6 +296,7 @@ bitfield(opc, extension) ea_2(SIZE_L, (mrg_2 < 010) ? 0 : (CTR | ALT)); } +void add(opc, sz) { if ((mrg_2 & 070) == 010) @@ -326,6 +332,7 @@ add(opc, sz) badoperand(); } +void and(opc, sz) { if (mrg_1 == 074 && mrg_2 >= 076) { /* ccr or sr */ @@ -370,6 +377,7 @@ from_dreg(opc, sz, bits) return(1); } +void cmp(sz) { register opc; @@ -416,6 +424,7 @@ link_instr(sz, areg) ea_2(sz, 0); } +void move(sz) { register opc; @@ -448,6 +457,7 @@ move(sz) ea_2(sz, ALT); } +void move_special(sz) { if (mrg_2 >= 076) { @@ -514,6 +524,7 @@ reverse(regs, max) return regs; } +void movep(sz) { checksize(sz, 2|4); @@ -530,6 +541,7 @@ movep(sz) badoperand(); } +void branch(opc, exp) expr_t exp; { @@ -566,6 +578,7 @@ expr_t exp; T_EMIT4(exp.val, exp.typ, RELPC|RELO4, relonami); } +void cpbcc(opc, exp) expr_t exp; { @@ -593,6 +606,7 @@ expr_t exp; T_EMIT4(exp.val, exp.typ, RELPC|RELO4, relonami); } +void ea7071(sz) { mrg_2 = 071; @@ -671,6 +685,7 @@ ea7071(sz) mrg_2 = 070; } +void fbranch(opc, exp) expr_t exp; { diff --git a/mach/m68020/ncg/mach.c b/mach/m68020/ncg/mach.c index 6759772f7..915b4f6e2 100644 --- a/mach/m68020/ncg/mach.c +++ b/mach/m68020/ncg/mach.c @@ -187,6 +187,7 @@ regsave(s,off,size) fprintf(codefile, "!Local %ld into %s\n",off,s); } +void prolog(n) full n; { nlocals = n; @@ -207,6 +208,7 @@ mach_option(s) } #endif /* MACH_OPTIONS */ +void mes(type) word type ; { int argt, a1, a2 ; diff --git a/mach/powerpc/ncg/mach.c b/mach/powerpc/ncg/mach.c index 39c6362e6..e4ab3c078 100644 --- a/mach/powerpc/ncg/mach.c +++ b/mach/powerpc/ncg/mach.c @@ -56,6 +56,7 @@ con_mult(word sz) #define FL_MSB_AT_LOW_ADDRESS 1 #include +void prolog(full nlocals) { int ss = nlocals + 8; @@ -68,6 +69,7 @@ prolog(full nlocals) framesize = nlocals; } +void mes(word type) { int argt ; diff --git a/mach/proto/as/comm4.c b/mach/proto/as/comm4.c index 9adff1ebf..473cb12e2 100644 --- a/mach/proto/as/comm4.c +++ b/mach/proto/as/comm4.c @@ -18,6 +18,9 @@ extern YYSTYPE yylval; +void setupoutput(); +void commfinish(); + /* ========== Machine independent C routines ========== */ void stop() { @@ -458,6 +461,7 @@ char *s; #endif } +void setupoutput() { register sect_t *sp; @@ -493,6 +497,7 @@ setupoutput() outhead.oh_nchar = off; /* see newsymb() */ } +void commfinish() { #ifndef ASLD diff --git a/mach/proto/as/comm5.c b/mach/proto/as/comm5.c index 276cc2f0c..7dee7c1a9 100644 --- a/mach/proto/as/comm5.c +++ b/mach/proto/as/comm5.c @@ -11,6 +11,8 @@ extern YYSTYPE yylval; +void putval(); + yylex() { register c; @@ -68,6 +70,7 @@ yylex() return(c); } +void putval(c) { register valu_t v; diff --git a/mach/proto/as/comm6.c b/mach/proto/as/comm6.c index f5bd87f39..9cb943cba 100644 --- a/mach/proto/as/comm6.c +++ b/mach/proto/as/comm6.c @@ -12,6 +12,10 @@ #include "comm1.h" #include "y.tab.h" +void switchsect(); +void newsymb(); +void newident(); + newequate(ip, typ) register item_t *ip; register int typ; @@ -34,6 +38,7 @@ register int typ; newident(ip, typ); } +void newident(ip, typ) register item_t *ip; { @@ -74,6 +79,7 @@ register item_t *ip; ); } +void newlabel(ip) register item_t *ip; { @@ -183,6 +189,7 @@ valu_t val; } } +void switchsect(newtyp) int newtyp; { @@ -242,6 +249,7 @@ valu_t bytes; } #ifdef RELOCATION +void newrelo(s, n) { int iscomm; @@ -326,6 +334,7 @@ new_string(s) return r; } +void newsymb(name, type, desc, valu) register char *name; valu_t valu; diff --git a/mach/proto/ncg/compute.c b/mach/proto/ncg/compute.c index f407aa8ae..d32417e68 100644 --- a/mach/proto/ncg/compute.c +++ b/mach/proto/ncg/compute.c @@ -120,6 +120,7 @@ string tostring(n) register word n; { return(mystrcpy(buf)); } +void compute(node, presult) register node_p node; register result_t *presult; { result_t leaf1,leaf2; register token_p tp; diff --git a/mach/proto/ncg/equiv.c b/mach/proto/ncg/equiv.c index a78123180..ace068882 100644 --- a/mach/proto/ncg/equiv.c +++ b/mach/proto/ncg/equiv.c @@ -29,6 +29,8 @@ int maxindex; int regclass[NREGS]; struct perm *perms; +void permute(); + struct perm * tuples(regls,nregneeded) rl_p *regls; { int class=0; @@ -64,6 +66,7 @@ tuples(regls,nregneeded) rl_p *regls; { return(perms); } +void permute(index) { register struct perm *pp; register rl_p rlp; diff --git a/mach/proto/ncg/fillem.c b/mach/proto/ncg/fillem.c index 516239b3d..447faeb41 100644 --- a/mach/proto/ncg/fillem.c +++ b/mach/proto/ncg/fillem.c @@ -83,6 +83,13 @@ extern short em_ptyp[]; extern double atof(); void prolog(full nlocals); +void mes(); +void bss(); +void savelab(); +void dumplab(); +void part_flush(); +void xdumplab(); +void switchseg(); /* Own version of atol that continues computing on overflow. We don't know that about the ANSI C one. @@ -136,6 +143,7 @@ in_start() { in_finish() { } +void fillemlines() { register int t,i; register struct emline *lp; @@ -226,6 +234,7 @@ fillemlines() { } } +void dopseudo() { register b,t; register full n; @@ -605,6 +614,7 @@ char *strarg(t) { return(mystrcpy(argstr)); } +void bss(n,t,b) full n; { register long s = 0; @@ -677,6 +687,7 @@ swtxt() { switchseg(SEGTXT); } +void switchseg(s) { if (s == curseg) @@ -686,6 +697,7 @@ switchseg(s) { fprintf(codefile,"%s\n",segname[s]); } +void savelab() { register char *p,*q; @@ -700,6 +712,7 @@ savelab() { ; } +void dumplab() { if (labstr[0] == 0) @@ -709,6 +722,7 @@ dumplab() { labstr[0] = 0; } +void xdumplab() { if (labstr[0] == 0) @@ -717,6 +731,7 @@ xdumplab() { newdlb(labstr); } +void part_flush() { /* diff --git a/mach/proto/ncg/gencode.c b/mach/proto/ncg/gencode.c index b9b89022c..415d59f51 100644 --- a/mach/proto/ncg/gencode.c +++ b/mach/proto/ncg/gencode.c @@ -108,6 +108,7 @@ gennl() { putc('\n',codefile); } +void prtoken(tp,leadingchar) token_p tp; { register c; register char *code; diff --git a/mach/proto/ncg/label.c b/mach/proto/ncg/label.c index 88e36ee2e..0c192589c 100644 --- a/mach/proto/ncg/label.c +++ b/mach/proto/ncg/label.c @@ -7,6 +7,7 @@ static label_p label_list = (label_p)0; extern char *myalloc(); +void add_label(num, height, flth) { register label_p lbl = (label_p)0; diff --git a/mach/proto/ncg/regvar.c b/mach/proto/ncg/regvar.c index dd791d60a..4c11da2b1 100644 --- a/mach/proto/ncg/regvar.c +++ b/mach/proto/ncg/regvar.c @@ -42,6 +42,7 @@ linkreg(of,sz,tp,sc) long of; { return(rvlp); } +void tryreg(rvlp,typ) register struct regvar *rvlp; { int score; register i; diff --git a/mach/proto/ncg/salloc.c b/mach/proto/ncg/salloc.c index 1826f1793..e110d75ad 100644 --- a/mach/proto/ncg/salloc.c +++ b/mach/proto/ncg/salloc.c @@ -32,6 +32,8 @@ static char rcsid[] = "$Id$"; char *stab[MAXSTAB]; int nstab=0; +void chkstr(); + string myalloc(size) { register string p; @@ -72,6 +74,7 @@ compar(p1,p2) char **p1,**p2; { return(1); } +void garbage_collect() { register i; struct emline *emlp; @@ -116,6 +119,7 @@ garbage_collect() { nstab = fillp-stab; } +void chkstr(str,used) string str; char used[]; { register low,middle,high; diff --git a/mach/proto/ncg/state.c b/mach/proto/ncg/state.c index 23d074bc7..4656ba872 100644 --- a/mach/proto/ncg/state.c +++ b/mach/proto/ncg/state.c @@ -23,6 +23,8 @@ static char rcsid[] = "$Id$"; extern int nstab; /* salloc.c */ +void bmove(); + savestatus(sp) register state_p sp; { sp->st_sh = stackheight; @@ -57,6 +59,7 @@ restorestatus(sp) register state_p sp; { popstr(sp->st_ns); } +void bmove(from,to,nbytes) register short *from,*to; register nbytes; { if (nbytes<=0) diff --git a/mach/proto/ncg/subr.c b/mach/proto/ncg/subr.c index 7d99ebcee..0f1b8edc4 100644 --- a/mach/proto/ncg/subr.c +++ b/mach/proto/ncg/subr.c @@ -49,6 +49,7 @@ match(tp,tep,optexp) register token_p tp; register set_p tep; { return(result.e_v.e_con); } +void instance(instno,token) register token_p token; { register inst_p inp; int i; @@ -145,6 +146,7 @@ instance(instno,token) register token_p token; { } } +void cinstance(instno,token,tp,regno) register token_p token,tp; { register inst_p inp; int i; diff --git a/mach/proto/top/top.c b/mach/proto/top/top.c index 5a9f842f8..178dd450e 100644 --- a/mach/proto/top/top.c +++ b/mach/proto/top/top.c @@ -23,6 +23,9 @@ struct variable ANY; /* ANY symbol matching any instruction */ char *REST; /* Opcode of first instruction not matched by current pattern */ +void labeldef(); +void set_opcode(); + #include "gen.c" @@ -170,6 +173,7 @@ write_first(w) /* Try to recognize the opcode part of an instruction */ +void set_opcode(ip) register instr_p ip; { @@ -318,6 +322,7 @@ bool split_operands(ip) +void labeldef(ip) register instr_p ip; { diff --git a/mach/vc4/ncg/mach.c b/mach/vc4/ncg/mach.c index 124e8a965..8832f744f 100644 --- a/mach/vc4/ncg/mach.c +++ b/mach/vc4/ncg/mach.c @@ -54,7 +54,7 @@ void prolog(full nlocals) framesize = nlocals; } -mes(word type) +void mes(word type) { int argt ; diff --git a/util/LLgen/src/check.c b/util/LLgen/src/check.c index 21d8a9f93..6efe80c02 100644 --- a/util/LLgen/src/check.c +++ b/util/LLgen/src/check.c @@ -40,9 +40,9 @@ STATIC prline(); STATIC printset(); STATIC int check(); STATIC moreverbose(); -STATIC prrule(); +STATIC void prrule(p_gram p); STATIC cfcheck(); -STATIC resolve(); +STATIC void resolve(p_gram p); STATIC propagate(); STATIC spaces(); @@ -283,7 +283,7 @@ moreverbose(t) register p_set t; { } STATIC -prrule(p) register p_gram p; { +void prrule(p_gram p) { /* * Create a verbose printout of grammar rule p */ @@ -420,7 +420,7 @@ cfcheck(s1,s2,flag) p_set s1,s2; { } STATIC -resolve(p) register p_gram p; { +void resolve(p_gram p) { /* * resolve conflicts, as specified by the user */ diff --git a/util/LLgen/src/compute.c b/util/LLgen/src/compute.c index c17d99d73..c16c6725c 100644 --- a/util/LLgen/src/compute.c +++ b/util/LLgen/src/compute.c @@ -41,7 +41,7 @@ typedef struct lngth { /* Defined in this file : */ extern do_compute(); STATIC createsets(); -STATIC walk(); +STATIC void walk(); STATIC co_trans(); STATIC int nempty(); extern empty(); @@ -49,15 +49,15 @@ STATIC int nfirst(); STATIC first(); STATIC int nfollow(); STATIC follow(); -STATIC co_dirsymb(); +STATIC void co_dirsymb(); STATIC co_others(); STATIC do_lengthcomp(); -STATIC complength(); -STATIC add(); +STATIC void complength(); +STATIC void add(); STATIC int compare(); -STATIC setdefaults(); +STATIC void setdefaults(); STATIC do_contains(); -STATIC contains(); +STATIC void contains(); STATIC int nsafes(); STATIC int do_safes(); #ifdef NON_CORRECTING @@ -208,7 +208,7 @@ createsets() { } } -STATIC +STATIC void walk(u, p) p_set u; register p_gram p; { /* * Walk through the grammar rule p, allocating sets @@ -658,7 +658,7 @@ nc_follow(setp,p) p_set setp; register p_gram p; { #endif -STATIC +STATIC void co_dirsymb(setp,p) p_set setp; register p_gram p; { /* * Walk the rule p, doing the work for alternations @@ -777,7 +777,7 @@ do_lengthcomp() { free ((p_mem) length); } -STATIC +STATIC void complength(p,le) register p_gram p; p_length le; { /* * Walk grammar rule p, computing minimum lengths @@ -862,7 +862,7 @@ complength(p,le) register p_gram p; p_length le; { } } -STATIC +STATIC void add(a, c, v) register p_length a; { if (a->cnt == INFINITY || c == INFINITY) { @@ -879,7 +879,7 @@ compare(a, b) register p_length a, b; { return a->val - b->val; } -STATIC +STATIC void setdefaults(p) register p_gram p; { for (;;) { switch(g_gettype(p)) { @@ -949,7 +949,7 @@ do_contains(n) register p_nont n; { } } -STATIC +STATIC void contains(p,set) register p_gram p; register p_set set; { /* * Does the real computation of the contains-sets diff --git a/util/LLgen/src/gencode.c b/util/LLgen/src/gencode.c index 94dd312ca..484319511 100644 --- a/util/LLgen/src/gencode.c +++ b/util/LLgen/src/gencode.c @@ -57,24 +57,24 @@ STATIC genncrecovery(); #endif STATIC string genname(); STATIC generate(); -STATIC prset(); -STATIC macro(); +STATIC void prset(); +STATIC void macro(); STATIC controlline(); STATIC getparams(); STATIC getansiparams(); STATIC genprototypes(); STATIC gettok(); -STATIC rulecode(); +STATIC void rulecode(); STATIC int * dopush(); STATIC int * mk_tokenlist(); -STATIC getaction(); -STATIC alternation(); +STATIC void getaction(); +STATIC void alternation(); STATIC codeforterm(); STATIC genswhead(); STATIC gencases(); STATIC genpush(); STATIC genpop(); -STATIC genincrdecr(); +STATIC void genincrdecr(); STATIC add_cases(); STATIC int analyze_switch(); STATIC out_list(); @@ -414,7 +414,7 @@ generate(f) p_file f; { } } -STATIC +STATIC void prset(p) p_set p; { register int k; register unsigned i; @@ -435,7 +435,7 @@ prset(p) p_set p; { /* NOTREACHED */ } -STATIC +STATIC void macro(s,n) string s; p_nont n; { int i; @@ -625,7 +625,7 @@ gettok() { } } -STATIC +STATIC void rulecode(p,safety,mustscan,mustpop) register p_gram p; { /* * Code for a production rule. @@ -735,7 +735,7 @@ rulecode(p,safety,mustscan,mustpop) register p_gram p; { } } -STATIC +STATIC void alternation(pp, safety, mustscan, mustpop, lb) p_gram pp; { @@ -956,7 +956,7 @@ dopush(p,safety,toplevel,pp) register p_gram p; int **pp; { # define max(a,b) ((a) < (b) ? (b) : (a)) -STATIC +STATIC void getaction(flag) { /* Read an action from the action file. * flag = 1 if it is an action, @@ -1252,7 +1252,7 @@ genpush(d) { genincrdecr("incr", d); } -STATIC +STATIC void genincrdecr(s, d) string s; { if (d == NOPOP) return; if (d >= 0) { diff --git a/util/LLgen/src/main.c b/util/LLgen/src/main.c index 733c0d81a..ca4b05f22 100644 --- a/util/LLgen/src/main.c +++ b/util/LLgen/src/main.c @@ -36,7 +36,7 @@ extern error(); extern fatal(); extern comfatal(); extern copyfile(); -extern install(); +extern void install(); extern char *mktemp(); extern char *sbrk(); @@ -279,6 +279,7 @@ error(lineno,s,t,u) string s,t,u; { } /* VARARGS1 */ +void warning(lineno,s,t,u) string s,t,u; { /* * Just a warning @@ -327,6 +328,7 @@ copyfile(file) string file; { fclose(f); } +void install(target, source) string target, source; { /* * Copy the temporary file generated from source to target diff --git a/util/LLgen/src/reach.c b/util/LLgen/src/reach.c index a950539d2..a8ca81a47 100644 --- a/util/LLgen/src/reach.c +++ b/util/LLgen/src/reach.c @@ -29,7 +29,7 @@ static string rcsid8 = "$Id$"; /* In this file the following routines are defined: */ extern co_reach(); STATIC reachable(); -STATIC reachwalk(); +STATIC void reachwalk(); co_reach() { /* @@ -94,7 +94,7 @@ reachable(p) register p_nont p; { } } -STATIC +STATIC void reachwalk(p) register p_gram p; { /* * Walk through rule p, looking for nonterminals. diff --git a/util/LLgen/src/savegram.c b/util/LLgen/src/savegram.c index 625dc1bab..a32935ecc 100644 --- a/util/LLgen/src/savegram.c +++ b/util/LLgen/src/savegram.c @@ -41,8 +41,8 @@ extern p_set start_firsts; extern p_set setalloc(); extern p_gram search(); -STATIC save_rule(); -STATIC save_set(); +STATIC void save_rule(); +STATIC void save_set(); /* t_list will contain terms to be `flattened' */ static struct t_list { @@ -267,7 +267,7 @@ save_grammar(f) FILE *f; { fprintf(fgram, "#define LLNNONTERMINALS %d\n", nt_highest - assval + 1); } -STATIC +STATIC void save_rule(p, tail) register p_gram p; int tail; { /* Walk through rule p, saving it. The non-terminal tail is @@ -363,7 +363,7 @@ save_rule(p, tail) register p_gram p; int tail; { } } -STATIC +STATIC void save_set(p) p_set p; { register int k; register unsigned i; diff --git a/util/LLgen/src/tokens.c b/util/LLgen/src/tokens.c index 8fa2b3613..6526ec1a3 100644 --- a/util/LLgen/src/tokens.c +++ b/util/LLgen/src/tokens.c @@ -92,13 +92,13 @@ extern int scanner(); extern LLmessage(); extern int input(); extern unput(); -extern skipcomment(); +extern void skipcomment(); # ifdef LINE_DIRECTIVE STATIC linedirective(); # endif STATIC string cpy(); STATIC string vallookup(); -STATIC copyact(); +STATIC void copyact(); static int nparams; # line 75 "tokens.g" @@ -144,7 +144,7 @@ static t_token savedtok; /* to save lextoken in case of an insertion */ static int nostartline; /* = 0 if at the start of a line */ # endif -STATIC +STATIC void copyact(ch1,ch2,flag,level) char ch1,ch2; { /* * Copy an action to file f. Opening bracket is ch1, closing bracket @@ -419,7 +419,7 @@ unput(c) { backupc = c; } -skipcomment(flag) { +void skipcomment(flag) { /* * Skip comment. If flag != 0, the comment is inside a fragment * of C-code, so keep it. diff --git a/util/LLgen/src/tokens.g b/util/LLgen/src/tokens.g index fbdd83d2d..51b83fcb3 100644 --- a/util/LLgen/src/tokens.g +++ b/util/LLgen/src/tokens.g @@ -33,13 +33,13 @@ extern int scanner(); extern LLmessage(); extern int input(); extern unput(); -extern skipcomment(); +extern void skipcomment(); # ifdef LINE_DIRECTIVE STATIC linedirective(); # endif STATIC string cpy(); STATIC string vallookup(); -STATIC copyact(); +STATIC void copyact(); static int nparams; } @@ -114,7 +114,7 @@ static t_token savedtok; /* to save lextoken in case of an insertion */ static int nostartline; /* = 0 if at the start of a line */ # endif -STATIC +STATIC void copyact(ch1,ch2,flag,level) char ch1,ch2; { /* * Copy an action to file f. Opening bracket is ch1, closing bracket @@ -389,6 +389,7 @@ unput(c) { backupc = c; } +void skipcomment(flag) { /* * Skip comment. If flag != 0, the comment is inside a fragment diff --git a/util/ack/files.c b/util/ack/files.c index b47376b24..f2dbc8ed2 100644 --- a/util/ack/files.c +++ b/util/ack/files.c @@ -143,6 +143,7 @@ rmfile(file) path *file ; { } } +void rmtemps() { /* Called in case of disaster, always remove the current output file! */ diff --git a/util/ack/grows.c b/util/ack/grows.c index ca089d48c..81c3c002d 100644 --- a/util/ack/grows.c +++ b/util/ack/grows.c @@ -50,6 +50,7 @@ gr_cat(id,string) growstring *id ; char *string ; { } } +void gr_throw(id) register growstring *id ; { /* Throw the string away */ if ( id->gr_max==0 ) return ; diff --git a/util/ack/grows.h b/util/ack/grows.h index 558387488..9b9511049 100644 --- a/util/ack/grows.h +++ b/util/ack/grows.h @@ -20,7 +20,7 @@ typedef struct { /* Routines used */ -extern int gr_throw() ; /* To free the core */ +extern void gr_throw() ; /* To free the core */ extern int gr_add() ; /* To add one character */ extern int gr_cat() ; /* concatenate the contents and the string */ extern int gr_init() ; /* Initialize the bookkeeping */ diff --git a/util/ack/main.c b/util/ack/main.c index 82c18888e..99e27dceb 100644 --- a/util/ack/main.c +++ b/util/ack/main.c @@ -24,6 +24,8 @@ static int arg_count; extern char *getenv(); +void vieuwargs(); + main(argc,argv) char **argv ; { register list_elem *elem ; register char *frontend ; @@ -136,6 +138,7 @@ varinit() { /************************* flag processing ***********************/ +void vieuwargs(argc,argv) char **argv ; { register char *argp; register int nextarg ; diff --git a/util/ack/mktables.c b/util/ack/mktables.c index 1946d09ee..214b93606 100644 --- a/util/ack/mktables.c +++ b/util/ack/mktables.c @@ -22,6 +22,8 @@ FILE *dmach ; int offset ; +void readm(); + main(argc,argv) char **argv ; { register i ; @@ -70,6 +72,7 @@ FILE *do_open(file) char *file ; { return fopen(dname,"r"); } +void readm() { register int i ; register int token ; diff --git a/util/ack/rmach.c b/util/ack/rmach.c index 38b2a54b3..1e33e8713 100644 --- a/util/ack/rmach.c +++ b/util/ack/rmach.c @@ -55,6 +55,7 @@ int getinchar() ; static char *ty_name ; static char *bol ; +void open_in(); static char *inname ; @@ -263,6 +264,7 @@ static FILE *infile ; static char *inptr ; char *em_dir = EM_DIR; +void open_in(name) register char *name ; { register dmach *cmac ; diff --git a/util/ack/scan.c b/util/ack/scan.c index c4388b152..d020e6a5b 100644 --- a/util/ack/scan.c +++ b/util/ack/scan.c @@ -15,6 +15,8 @@ static char rcs_id[] = "$Id$" ; #endif +void try(); + enum f_path getpath(first) register trf **first ; { /* Try to find a transformation path */ @@ -61,6 +63,7 @@ start_scan() { last_ocount= 0 ; } +void try(f_scan,suffix) list_elem *f_scan; char *suffix; { register list_elem *scan ; register trf *trafo ; diff --git a/util/ack/trans.c b/util/ack/trans.c index 135b4c151..3cb2d7ea8 100644 --- a/util/ack/trans.c +++ b/util/ack/trans.c @@ -28,6 +28,10 @@ static int touch_tail= NO ; char *headvar(),*tailvar() ; +void condit(); +void doassign(); +void set_Rflag(); + int transform(phase) register trf *phase ; { int ok ; @@ -153,6 +157,7 @@ transini() { setpvar(keeps(TAIL),tailvar) ; } +void set_Rflag(argp) register char *argp ; { register char *eos ; register list_elem *prog ; @@ -413,6 +418,7 @@ growstring scanexpr(line) char *line ; { return result ; } +void condit(line,fsuff,lsuff,tailval) growstring *line ; list_head *fsuff, *lsuff; char *tailval ; @@ -504,6 +510,7 @@ int mapexpand(mapentry,cflag) return 1 ; } +void doassign(line,star,length) char *line, *star ; { growstring varval, name, temp ; register char *ptr ; @@ -598,6 +605,7 @@ char *c_rep(string,place,rep) char *string, *place, *rep ; { static list_head *curargs ; static list_head *comb_args ; +void addargs(string) char *string ; { register char *temp, *repc ; register list_elem *elem ; diff --git a/util/ack/util.c b/util/ack/util.c index a3d2d0511..419f087e3 100644 --- a/util/ack/util.c +++ b/util/ack/util.c @@ -32,6 +32,9 @@ extern int n_error; # define STDOUT stderr #endif +void fuerror(const char* fmt, ...); +void werror(const char* fmt, ...); + char *basename(string) char *string ; { static char retval[256] ; char *last_dot, *last_start ; diff --git a/util/amisc/anm.c b/util/amisc/anm.c index 161f6587f..f2469f772 100644 --- a/util/amisc/anm.c +++ b/util/amisc/anm.c @@ -35,6 +35,8 @@ long s_base[S_MAX]; /* for specially encoded bases */ char *filename; int narg; +void do_file(); + main(argc, argv) char **argv; { @@ -134,6 +136,7 @@ process(fd) } } +void do_file(fd) int fd; { diff --git a/util/arch/archiver.c b/util/arch/archiver.c index 38958ea5e..bae09a168 100644 --- a/util/arch/archiver.c +++ b/util/arch/archiver.c @@ -109,6 +109,10 @@ char *temp_arch = &temp_buf[0]; extern char *mktemp(); extern char *ctime(); +void do_object(); +void write_symdef(); +void add(); + usage() { error(TRUE, "usage: %s [qdprtxl][vlc] archive [file] ...\n", @@ -437,6 +441,7 @@ register char *argv[]; close(ar_fd); } +void add(name, fd, mess) char *name; int fd; @@ -630,6 +635,7 @@ char *s, *name; * then 4 bytes giving the size of the string table, followed by the string * table itself. */ +void write_symdef() { register struct ranlib *ran; @@ -683,6 +689,7 @@ is_outhead(headp) return !BADMAGIC(*headp) && headp->oh_nname != 0; } +void do_object(f, size) long size; { diff --git a/util/ego/bo/bo.c b/util/ego/bo/bo.c index c093fe8ab..9024e7b56 100644 --- a/util/ego/bo/bo.c +++ b/util/ego/bo/bo.c @@ -150,7 +150,7 @@ STATIC bo_optloop(p,b,x,bra,bcc) -STATIC bo_tryloop(p,loop) +STATIC void bo_tryloop(p,loop) proc_p p; lset loop; { @@ -207,6 +207,7 @@ STATIC mv_code(b1,b2) } } +void bo_switch(b) bblock_p b; { @@ -303,6 +304,7 @@ STATIC bo_cleanproc(p) } } +void bo_optimize(p) proc_p p; { diff --git a/util/ego/ca/ca.c b/util/ego/ca/ca.c index acfba4829..095736665 100644 --- a/util/ego/ca/ca.c +++ b/util/ego/ca/ca.c @@ -130,7 +130,7 @@ STATIC int makedmap(dbl) return cnt; } -STATIC getdnames(dumpd) +STATIC void getdnames(dumpd) FILE* dumpd; { /* Read the names of the datalabels from @@ -151,7 +151,7 @@ STATIC getdnames(dumpd) } } -STATIC getpnames(dumpp) +STATIC void getpnames(dumpp) FILE* dumpp; { /* Read the names of the procedures from diff --git a/util/ego/cf/cf_loop.c b/util/ego/cf/cf_loop.c index b3b2d5c70..61184eddc 100644 --- a/util/ego/cf/cf_loop.c +++ b/util/ego/cf/cf_loop.c @@ -298,7 +298,7 @@ STATIC mark_succ(b,lp) } -STATIC mark_blocks(lp) +STATIC void mark_blocks(lp) loop_p lp; { /* Mark the strong and firm blocks of a loop. diff --git a/util/ego/cj/cj.c b/util/ego/cj/cj.c index 2ae26f3da..1447af8a7 100644 --- a/util/ego/cj/cj.c +++ b/util/ego/cj/cj.c @@ -56,7 +56,7 @@ STATIC int Scj; /* number of optimizations found */ -STATIC showinstr(); +STATIC void showinstr(); @@ -289,6 +289,7 @@ STATIC bool try_pred(b) +void cj_optimize(p) proc_p p; { @@ -334,7 +335,7 @@ main(argc,argv) extern char em_mnem[]; /* The mnemonics of the EM instructions. */ -STATIC showinstr(lnp) line_p lnp; { +STATIC void showinstr(lnp) line_p lnp; { /* Makes the instruction in `lnp' human readable. Only lines that * can occur in expressions that are going to be eliminated are diff --git a/util/ego/cs/cs.c b/util/ego/cs/cs.c index 21e6b488f..df651c9c4 100644 --- a/util/ego/cs/cs.c +++ b/util/ego/cs/cs.c @@ -34,7 +34,7 @@ STATIC cs_clear() start_valnum(); } -STATIC cs_optimize(p) +STATIC void cs_optimize(p) proc_p p; { /* Optimize all basic blocks of one procedure. */ diff --git a/util/ego/cs/cs_avail.c b/util/ego/cs/cs_avail.c index d97a19b41..1f766a85c 100644 --- a/util/ego/cs/cs_avail.c +++ b/util/ego/cs/cs_avail.c @@ -75,7 +75,7 @@ STATIC bool same_avail(kind, avp1, avp2) /* NOTREACHED */ } -STATIC check_local(avp) +STATIC void check_local(avp) avail_p avp; { /* Check if the local in which the result of avp was stored, diff --git a/util/ego/cs/cs_debug.c b/util/ego/cs/cs_debug.c index bfa0dc66d..bf43d8c12 100644 --- a/util/ego/cs/cs_debug.c +++ b/util/ego/cs/cs_debug.c @@ -17,7 +17,7 @@ extern char em_mnem[]; /* The mnemonics of the EM instructions. */ -STATIC showinstr(lnp) +STATIC void showinstr(lnp) line_p lnp; { /* Makes the instruction in `lnp' human readable. Only lines that diff --git a/util/ego/cs/cs_kill.c b/util/ego/cs/cs_kill.c index 7c9e90064..520366f23 100644 --- a/util/ego/cs/cs_kill.c +++ b/util/ego/cs/cs_kill.c @@ -234,7 +234,7 @@ STATIC kill_local(enp, indir) } } -STATIC kill_sim() +STATIC void kill_sim() { /* A store is done into the ENIGNMASK. */ diff --git a/util/ego/cs/cs_stack.c b/util/ego/cs/cs_stack.c index 5b3743434..7927438a5 100644 --- a/util/ego/cs/cs_stack.c +++ b/util/ego/cs/cs_stack.c @@ -39,6 +39,7 @@ Push(tkp) #define WORD_MULTIPLE(n) ((n / ws) * ws + ( n % ws ? ws : 0 )) +void Pop(tkp, size) token_p tkp; offset size; diff --git a/util/ego/ic/ic_lib.c b/util/ego/ic/ic_lib.c index 638038afc..7721bf27e 100644 --- a/util/ego/ic/ic_lib.c +++ b/util/ego/ic/ic_lib.c @@ -33,7 +33,7 @@ STATIC skip_string(n) } } -STATIC skip_arguments() +STATIC void skip_arguments() { /* Skip the arguments of a MES pseudo. The argument * list is terminated by a sp_cend byte. diff --git a/util/ego/il/il1_aux.c b/util/ego/il/il1_aux.c index 76e8ae2f3..d8da36dea 100644 --- a/util/ego/il/il1_aux.c +++ b/util/ego/il/il1_aux.c @@ -89,6 +89,7 @@ remov_formals(p) +void rem_indir_acc(p) proc_p p; { diff --git a/util/ego/il/il1_aux.h b/util/ego/il/il1_aux.h index 8b9db59d7..af8fe1ecf 100644 --- a/util/ego/il/il1_aux.h +++ b/util/ego/il/il1_aux.h @@ -18,7 +18,7 @@ extern rem_actuals(); /* (actual_p atcs) extern remov_formals(); /* (proc_p p) * Remove the formals-list of p from core. */ -extern rem_indir_acc(); /* (proc_p p) +extern void rem_indir_acc(); /* (proc_p p) * Remove formal that may be accessed * indirectly from formal lists of p */ diff --git a/util/ego/il/il1_cal.c b/util/ego/il/il1_cal.c index 69d12002e..1d0a2dc95 100644 --- a/util/ego/il/il1_cal.c +++ b/util/ego/il/il1_cal.c @@ -60,7 +60,7 @@ STATIC bool chck_asp(p,l) -STATIC inc_count(caller,callee) +STATIC void inc_count(caller,callee) proc_p caller, callee; { /* Update the call-count information. diff --git a/util/ego/il/il1_formal.c b/util/ego/il/il1_formal.c index c906f2580..94e2e32f7 100644 --- a/util/ego/il/il1_formal.c +++ b/util/ego/il/il1_formal.c @@ -103,6 +103,7 @@ STATIC inc_use(f,b) +void formal(p,b,off,type,usage) proc_p p; bblock_p b; diff --git a/util/ego/il/il1_formal.h b/util/ego/il/il1_formal.h index 7df35c1bb..bd2aea74d 100644 --- a/util/ego/il/il1_formal.h +++ b/util/ego/il/il1_formal.h @@ -8,7 +8,7 @@ * I L 1 _ F O R M A L . C */ -extern formal(); /* (proc_p p; bblock_p b; offset off; +extern void formal(); /* (proc_p p; bblock_p b; offset off; * int type, usage) * Analyze a reference to a parameter of p. * The type denotes its size (single,double, diff --git a/util/ego/il/il3_change.c b/util/ego/il/il3_change.c index 6347167c3..4528e8502 100644 --- a/util/ego/il/il3_change.c +++ b/util/ego/il/il3_change.c @@ -201,7 +201,7 @@ line_p make_label(l,p) /* modify */ -STATIC act_info(off,acts,ab_off,act_out,off_out) +STATIC void act_info(off,acts,ab_off,act_out,off_out) offset off, ab_off, *off_out; actual_p acts, *act_out; { @@ -499,6 +499,7 @@ STATIC line_p first_nonpseudo(l) +void insert(text,l,firstline) line_p text,l,firstline; { diff --git a/util/ego/il/il3_change.h b/util/ego/il/il3_change.h index 9899c8664..95c14f11c 100644 --- a/util/ego/il/il3_change.h +++ b/util/ego/il/il3_change.h @@ -35,7 +35,7 @@ extern mod_actuals(); /* (call_p nc,c; line_p lab; * call nc the same way as the text of * call c would be modified. */ -extern insert(); /* (line_p text,l,firstline) +extern void insert(); /* (line_p text,l,firstline) * Insert the modified EM text. * Pseudos are put after the pseudos * of the caller. diff --git a/util/ego/il/il_aux.c b/util/ego/il/il_aux.c index 2bb5e4564..d35120eb4 100644 --- a/util/ego/il/il_aux.c +++ b/util/ego/il/il_aux.c @@ -149,6 +149,7 @@ STATIC short remlines(l) +void remunit(kind,p,l) short kind; proc_p p; diff --git a/util/ego/lv/lv.c b/util/ego/lv/lv.c index 9fe50befd..6a640a1cb 100644 --- a/util/ego/lv/lv.c +++ b/util/ego/lv/lv.c @@ -591,6 +591,7 @@ lv_flags(p) } +void lv_optimize(p) proc_p p; { diff --git a/util/ego/ra/ra.c b/util/ego/ra/ra.c index fdb345f0b..fd05cdef0 100644 --- a/util/ego/ra/ra.c +++ b/util/ego/ra/ra.c @@ -349,6 +349,7 @@ ra_initialize() } +void ra_optimize(p) proc_p p; { diff --git a/util/ego/ra/ra_items.c b/util/ego/ra/ra_items.c index 05e16756c..a7411befb 100644 --- a/util/ego/ra/ra_items.c +++ b/util/ego/ra/ra_items.c @@ -260,7 +260,7 @@ STATIC init_item(a,b) -STATIC add_item(item,t,items) +STATIC void add_item(item,t,items) item_p item; time_p t; item_p items[]; diff --git a/util/ego/ra/ra_xform.c b/util/ego/ra/ra_xform.c index 28c295f0d..fea3e0757 100644 --- a/util/ego/ra/ra_xform.c +++ b/util/ego/ra/ra_xform.c @@ -551,6 +551,8 @@ rem_locals(p,allocs) } p->p_localbytes = nrlocals; } + +void rem_formals(p,allocs) proc_p p; alloc_p allocs; diff --git a/util/ego/share/locals.c b/util/ego/share/locals.c index b8b92f253..7da423b7f 100644 --- a/util/ego/share/locals.c +++ b/util/ego/share/locals.c @@ -29,7 +29,7 @@ short nrglobals; short nrlocals; local_p *locals; /* dynamic array */ -STATIC localvar(off,size,locs,reg,score) +STATIC void localvar(off,size,locs,reg,score) offset off; short size; local_p *locs; @@ -90,7 +90,7 @@ STATIC check_message(l,locs) -STATIC check_local_use(l,locs) +STATIC void check_local_use(l,locs) line_p l; local_p *locs; { @@ -186,7 +186,7 @@ make_localtab(p) -find_local(off,nr_out,found_out) +void find_local(off,nr_out,found_out) offset off; short *nr_out; bool *found_out; @@ -211,7 +211,7 @@ find_local(off,nr_out,found_out) -var_nr(l,nr_out,found_out) +void var_nr(l,nr_out,found_out) line_p l; short *nr_out; bool *found_out; diff --git a/util/ego/share/locals.h b/util/ego/share/locals.h index f71512ee5..60792372f 100644 --- a/util/ego/share/locals.h +++ b/util/ego/share/locals.h @@ -17,11 +17,11 @@ extern make_localtab(); /* (proc_p p) * these variables ('locals') and count them * ('nrlocals'). Also collect register messages. */ -extern var_nr(); /* (line_p l; short *nr_out;bool *found_out) +extern void var_nr(); /* (line_p l; short *nr_out;bool *found_out) * Compute the 'variable number' of the * variable referenced by EM instruction l. */ -extern find_local(); /* (offset off; short *nr_out; bool *found_out) +extern void find_local(); /* (offset off; short *nr_out; bool *found_out) * Try to find the local variable at the given * offset. Return its local-number. */ diff --git a/util/ego/share/put.c b/util/ego/share/put.c index 732377933..9cbfe7339 100644 --- a/util/ego/share/put.c +++ b/util/ego/share/put.c @@ -377,6 +377,7 @@ STATIC outlset(s,p) +void putunit(kind,p,l,gf,lf) short kind; proc_p p; diff --git a/util/ego/share/put.h b/util/ego/share/put.h index 2df761328..c6287cdaf 100644 --- a/util/ego/share/put.h +++ b/util/ego/share/put.h @@ -28,7 +28,7 @@ extern putptable(); /* (proc_p head, FILE *pf, bool all) * the fields computed by CF will not be * written (used by the IC phase). */ -extern putunit(); /* (short kind; proc_p p; line_p l; +extern void putunit(); /* (short kind; proc_p p; line_p l; * FILE *gf, *lf) * If kind = LTEXT, then write * the control flow graph to file gf, diff --git a/util/ego/sp/sp.c b/util/ego/sp/sp.c index dcc0a99f9..b04895647 100644 --- a/util/ego/sp/sp.c +++ b/util/ego/sp/sp.c @@ -193,6 +193,7 @@ STATIC mark_unsave_blocks(p) } +void sp_optimize(p) proc_p p; { diff --git a/util/ego/sr/sr.c b/util/ego/sr/sr.c index fcc9b413e..5f2194ed1 100644 --- a/util/ego/sr/sr.c +++ b/util/ego/sr/sr.c @@ -218,6 +218,7 @@ STATIC sr_cleanproc(p) } +void sr_optimize(p) proc_p p; { diff --git a/util/ego/sr/sr_cand.c b/util/ego/sr/sr_cand.c index ea478c01a..45babca7e 100644 --- a/util/ego/sr/sr_cand.c +++ b/util/ego/sr/sr_cand.c @@ -131,7 +131,7 @@ STATIC bool not_dismissed(lnp) } -STATIC try_cand(lnp,b) +STATIC void try_cand(lnp,b) line_p lnp; bblock_p b; { diff --git a/util/ego/sr/sr_iv.c b/util/ego/sr/sr_iv.c index 88af2e0d1..43e4b89c1 100644 --- a/util/ego/sr/sr_iv.c +++ b/util/ego/sr/sr_iv.c @@ -116,7 +116,7 @@ STATIC int sign(lnp) } -STATIC try_patterns(lnp) +STATIC void try_patterns(lnp) line_p lnp; { /* lnp is a STL x; try to recognize diff --git a/util/ego/sr/sr_reduce.c b/util/ego/sr/sr_reduce.c index 5b8e78295..d5ae81bb0 100644 --- a/util/ego/sr/sr_reduce.c +++ b/util/ego/sr/sr_reduce.c @@ -544,7 +544,7 @@ STATIC reduce(code,vars) -STATIC try_multiply(lp,ivs,vars,b,mul) +STATIC void try_multiply(lp,ivs,vars,b,mul) loop_p lp; lset ivs,vars; bblock_p b; @@ -606,7 +606,7 @@ STATIC try_multiply(lp,ivs,vars,b,mul) -STATIC try_leftshift(lp,ivs,vars,b,shft) +STATIC void try_leftshift(lp,ivs,vars,b,shft) loop_p lp; lset ivs,vars; bblock_p b; @@ -657,7 +657,7 @@ STATIC try_leftshift(lp,ivs,vars,b,shft) } -STATIC try_array(lp,ivs,vars,b,arr) +STATIC void try_array(lp,ivs,vars,b,arr) loop_p lp; lset ivs,vars; bblock_p b; diff --git a/util/ego/sr/sr_xform.c b/util/ego/sr/sr_xform.c index ca1c521b7..7adc32121 100644 --- a/util/ego/sr/sr_xform.c +++ b/util/ego/sr/sr_xform.c @@ -138,6 +138,7 @@ STATIC adjust_jump(newtarg,oldtarg,c) } +void make_header(lp) loop_p lp; { diff --git a/util/ego/sr/sr_xform.h b/util/ego/sr/sr_xform.h index 9bf1f3bd7..a6065c90d 100644 --- a/util/ego/sr/sr_xform.h +++ b/util/ego/sr/sr_xform.h @@ -16,7 +16,7 @@ extern line_p move_pointer(); /* (offset tmp; int dir ) */ * onto/from the stack, depending on dir(ection). * We accept all kinds of pointer sizes. */ -extern make_header() ; /* (loop_p lp) */ +extern void make_header() ; /* (loop_p lp) */ /* Make sure that the loop has a header block, i.e. a block * has the loop entry block as its only successor and * that dominates the loop entry block. diff --git a/util/ego/ud/ud.c b/util/ego/ud/ud.c index 610fd7a5e..afcba53a5 100644 --- a/util/ego/ud/ud.c +++ b/util/ego/ud/ud.c @@ -531,6 +531,7 @@ STATIC ud_cleanup(p) } +void ud_optimize(p) proc_p p; { diff --git a/util/ego/ud/ud_const.c b/util/ego/ud/ud_const.c index 9e854bd38..d1a2a438f 100644 --- a/util/ego/ud/ud_const.c +++ b/util/ego/ud/ud_const.c @@ -131,7 +131,7 @@ bool affected(use,v,l) -STATIC search_backwards(use,v,found,def) +STATIC void search_backwards(use,v,found,def) line_p use, *def; short v; bool *found; diff --git a/util/ego/ud/ud_copy.c b/util/ego/ud/ud_copy.c index 3761dba2d..213f7252a 100644 --- a/util/ego/ud/ud_copy.c +++ b/util/ego/ud/ud_copy.c @@ -42,7 +42,7 @@ short nrcopies; /* number of copies in the current procedure #define COUNT 0 #define MAP 1 -STATIC traverse_defs(p,action) +STATIC void traverse_defs(p,action) proc_p p; int action; { @@ -121,7 +121,7 @@ STATIC bool is_changed(varl,start,stop) -STATIC gen_kill_copies(p) +STATIC void gen_kill_copies(p) proc_p p; { /* Compute C_GEN and C_KILL for every basic block diff --git a/util/ego/ud/ud_defs.c b/util/ego/ud/ud_defs.c index f6272acf8..875d01425 100644 --- a/util/ego/ud/ud_defs.c +++ b/util/ego/ud/ud_defs.c @@ -249,7 +249,7 @@ STATIC impl_globl_defs(p,gen_p) -STATIC impl_gen_defs(l,gen_p) +STATIC void impl_gen_defs(l,gen_p) line_p l; cset *gen_p; { diff --git a/util/led/extract.c b/util/led/extract.c index 3b0983c9d..5878d527d 100644 --- a/util/led/extract.c +++ b/util/led/extract.c @@ -23,6 +23,9 @@ static redefine(); static transfer(); extern ind_t savechar(); + +void namerelocate(); + /* * Get section sizes and symboltable information from present module. */ @@ -149,6 +152,7 @@ process(head) * Otherwise we just add the accumulated size of all normal parts in preceding * sections with the same size. */ +void namerelocate(name) register struct outname *name; { diff --git a/util/led/main.c b/util/led/main.c index 426438ec6..2ec6ca2f8 100644 --- a/util/led/main.c +++ b/util/led/main.c @@ -35,9 +35,9 @@ static setbase(); static struct outname *makename(); static pass1(); static evaluate(); -static norm_commons(); +static void norm_commons(); static complete_sections(); -static change_names(); +static void change_names(); static bool tstbit(); static second_pass(); static pass2(); @@ -45,6 +45,8 @@ static pass2(); static do_statistics(); #endif +void addbase(); + main(argc, argv) int argc; char **argv; @@ -395,7 +397,7 @@ long sect_comm[MAXSECT]; * just like "normal" names. We also count the total size of common names * within each section to be able to compute the final size in the machine. */ -static +static void norm_commons() { register struct outname *name; @@ -492,7 +494,7 @@ complete_sections() * For each name we add the base of its section to its value, unless * the output has to be able to be linked again, as indicated by RFLAG. */ -static +static void change_names() { register int cnt; @@ -565,6 +567,7 @@ tstbit(indx, string) /* * Add the base of the section of a name to its value. */ +void addbase(name) struct outname *name; { diff --git a/util/led/memory.c b/util/led/memory.c index b99447172..6349c826a 100644 --- a/util/led/memory.c +++ b/util/led/memory.c @@ -519,6 +519,7 @@ core_free(piece, p) * Reset index into piece of memory for modules and * take care that the allocated pieces will not be moved. */ +void freeze_core() { register int i; diff --git a/util/led/output.c b/util/led/output.c index cb7abceb2..0ee622e3a 100644 --- a/util/led/output.c +++ b/util/led/output.c @@ -10,7 +10,7 @@ static char rcsid[] = "$Id$"; #include "const.h" #include "memory.h" -static generate_section_names(); +static void generate_section_names(); extern struct outhead outhead; extern bool incore; @@ -51,7 +51,7 @@ beginoutput() * Generate names for all sections and put them after the global names. * Section names are used for relocation. */ -static +static void generate_section_names() { register struct outname *name; diff --git a/util/led/save.c b/util/led/save.c index a311d0413..3804413d9 100644 --- a/util/led/save.c +++ b/util/led/save.c @@ -22,6 +22,7 @@ static char rcsid[] = "$Id$"; extern bool incore; extern char *core_alloc(); +void savemagic() { register char *p; @@ -35,6 +36,7 @@ savemagic() } } +void savehdr(hdr) struct ar_hdr *hdr; { @@ -91,6 +93,7 @@ savechar(piece, off) * allocation, but the string of which name->on_foff is the offset may be * destroyed, so we save that first. */ +void savelocal(name) struct outname *name; { diff --git a/util/ncgg/coerc.c b/util/ncgg/coerc.c index 893f81be3..d6334d5a3 100644 --- a/util/ncgg/coerc.c +++ b/util/ncgg/coerc.c @@ -24,6 +24,7 @@ int nmoves; move_t l_moves[MAXMOVES]; short posmoves[MAXREGS+MAXTOKENS][SETSIZE]; +void n_move(s1,e1,s2,e2,vi) struct varinfo *vi; { register move_p mp; register i,j; @@ -81,6 +82,7 @@ int ntests; test_t l_tests[MAXTESTS]; short postests[SETSIZE]; +void n_test(s,e,vi) struct varinfo *vi; { register test_p tp; register i; @@ -162,6 +164,7 @@ n_stack(s,e,p,vi) struct varinfo *vi; { sp[i] |= l_sets[s].set_val[i]; } +void checkstacking(sp) register short *sp; { register i; register short *chkset; @@ -186,6 +189,7 @@ set_t unstackset; /*VARARGS5*/ +void n_coerc(ti,be,al,ge,rp,in) struct varinfo *al,*ge,*rp; iocc_t in; { register c3_p c3p; register i; diff --git a/util/ncgg/output.c b/util/ncgg/output.c index 50458e369..77e3eb41f 100644 --- a/util/ncgg/output.c +++ b/util/ncgg/output.c @@ -662,6 +662,7 @@ finishio() { outars(); } +void codecoco(cocono) { if (cocono== -1) diff --git a/util/ncgg/set.c b/util/ncgg/set.c index cb31c3594..d2d9b0d8f 100644 --- a/util/ncgg/set.c +++ b/util/ncgg/set.c @@ -85,7 +85,7 @@ set_t ident_to_set(name) char *name; { return(result); } -static +static void checksize(s) register set_p s; { diff --git a/util/ncgg/subr.c b/util/ncgg/subr.c index 90bf44eb2..08c7c650f 100644 --- a/util/ncgg/subr.c +++ b/util/ncgg/subr.c @@ -175,6 +175,7 @@ n_prop(name,size) char *name; int size; { l_props[propno].pr_size = size; } +void prophall(n) { register i; short hallset[SETSIZE]; @@ -279,6 +280,7 @@ setallreg(vi) struct varinfo *vi; { } } +void freevi(vip) register struct varinfo *vip; { register i; diff --git a/util/opt/cleanup.c b/util/opt/cleanup.c index 2c1f912eb..f09feeb7b 100644 --- a/util/opt/cleanup.c +++ b/util/opt/cleanup.c @@ -20,6 +20,7 @@ static char rcsid[] = "$Id$"; */ +void cleanup() { FILE *infile; register c; diff --git a/util/opt/flow.c b/util/opt/flow.c index 77f6042c2..73ae715af 100644 --- a/util/opt/flow.c +++ b/util/opt/flow.c @@ -21,6 +21,8 @@ static char rcsid[] = "$Id$"; * Author: Hans van Staveren */ +void reach(); + flow() { findreach(); /* determine reachable labels */ @@ -51,6 +53,7 @@ findreach() { } } +void reach(lnp) register line_p lnp; { register num_p np; diff --git a/util/opt/getline.c b/util/opt/getline.c index c3ed1bb78..9ecdf08fd 100644 --- a/util/opt/getline.c +++ b/util/opt/getline.c @@ -188,6 +188,7 @@ int table2() { return(table3(n)); } +void getlines() { register line_p lnp; register instr; diff --git a/util/opt/reg.c b/util/opt/reg.c index 00fc2e3b2..6066c9f19 100644 --- a/util/opt/reg.c +++ b/util/opt/reg.c @@ -21,6 +21,7 @@ static char rcsid[] = "$Id$"; * Author: Hans van Staveren */ +void regvar(ap) register arg_p ap; { register reg_p rp; register i; @@ -96,6 +97,7 @@ outtes() { } } +void incregusage(off) offset off; { register reg_p rp; diff --git a/util/opt/tes.c b/util/opt/tes.c index ab6ce3bbd..b3d4efda1 100644 --- a/util/opt/tes.c +++ b/util/opt/tes.c @@ -68,6 +68,7 @@ tes_pseudos() } } +void tes_instr(lnp, x, y) line_p lnp, x, y; { From e7eb563ee9b42866fda99062c06bf08c3930c94b Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 11 Nov 2016 20:16:43 +0100 Subject: [PATCH 169/230] Disable gethostid() in the build system Lua; it's unused and doesn't work on Haiku. --- first/lua-5.1/lposix.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/first/lua-5.1/lposix.c b/first/lua-5.1/lposix.c index ebe6b9c03..4bdf9328f 100644 --- a/first/lua-5.1/lposix.c +++ b/first/lua-5.1/lposix.c @@ -702,6 +702,7 @@ static int Pgetpid(lua_State *L) /** getpid([options]) */ } +#if 0 static int Phostid(lua_State *L) /** hostid() */ { char b[32]; @@ -709,6 +710,7 @@ static int Phostid(lua_State *L) /** hostid() */ lua_pushstring(L, b); return 1; } +#endif static int Pttyname(lua_State *L) /** ttyname([fd]) */ @@ -1060,7 +1062,7 @@ static const luaL_reg R[] = {"getpasswd", Pgetpasswd}, {"getpid", Pgetpid}, {"glob", Pglob}, - {"hostid", Phostid}, + //{"hostid", Phostid}, {"kill", Pkill}, {"link", Plink}, {"mkdir", Pmkdir}, From d82df74a7a33cfab66a86b13efcad751d331d26d Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 11 Nov 2016 20:17:10 +0100 Subject: [PATCH 170/230] Rename addr_t to address_t to avoid clashes with the system addr_t. --- mach/proto/ncg/data.h | 4 ++-- mach/proto/ncg/gencode.c | 4 ++-- mach/proto/ncg/result.h | 2 +- util/LLgen/build.lua | 6 ++++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/mach/proto/ncg/data.h b/mach/proto/ncg/data.h index c1d0e183e..ddd232b98 100644 --- a/mach/proto/ncg/data.h +++ b/mach/proto/ncg/data.h @@ -12,13 +12,13 @@ typedef struct cost { typedef struct { string ea_str; word ea_off; -} addr_t; +} address_t; typedef struct { int t_token; /* kind of token, -1 for register */ union { word aw; /* integer type */ - addr_t aa; /* address type */ + address_t aa; /* address type */ int ar; /* register type */ } t_att[TOKENSIZE]; } token_t,*token_p; diff --git a/mach/proto/ncg/gencode.c b/mach/proto/ncg/gencode.c index 415d59f51..68676868e 100644 --- a/mach/proto/ncg/gencode.c +++ b/mach/proto/ncg/gencode.c @@ -72,7 +72,7 @@ genstr(stringno) { fputs(codestrings[stringno],codefile); } -string ad2str(ad) addr_t ad; { +string ad2str(ad) address_t ad; { static char buf[100]; if (ad.ea_str==0) @@ -87,7 +87,7 @@ string ad2str(ad) addr_t ad; { return(mystrcpy(buf)); } -praddr(ad) addr_t ad; { +praddr(ad) address_t ad; { if (ad.ea_str==0 || *(ad.ea_str) == '\0') fprintf(codefile,WRD_FMT,ad.ea_off); diff --git a/mach/proto/ncg/result.h b/mach/proto/ncg/result.h index 7ceb2f114..fdb9e16e1 100644 --- a/mach/proto/ncg/result.h +++ b/mach/proto/ncg/result.h @@ -9,7 +9,7 @@ struct result { union { word e_con; int e_reg; - addr_t e_addr; + address_t e_addr; } e_v; /* value */ }; diff --git a/util/LLgen/build.lua b/util/LLgen/build.lua index 44abc871c..9cde5630c 100644 --- a/util/LLgen/build.lua +++ b/util/LLgen/build.lua @@ -1,3 +1,8 @@ +clibrary { + name = "headers", + hdrs = { "./src/*.h" } +} + cprogram { name = "llgen", @@ -6,6 +11,7 @@ cprogram { -- do this. srcs = { "./src/*.c" }, + deps = { "+headers" }, vars = { ["+cflags"] = { "-DLIBDIR=\\\""..posix.getcwd().."/"..cwd().."/lib\\\"", From b5c1d622f5a92b22adeeac97291b6656b28950b7 Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 11 Nov 2016 21:17:45 +0100 Subject: [PATCH 171/230] Rework the way stack frames are laid out to be simpler and, hopefully, more correct. Saved registers are now placed in what may be the right place. --- mach/powerpc/mcg/platform.c | 57 ++++++++++++++++++++++++++----------- mach/proto/mcg/hop.c | 6 +++- mach/proto/mcg/procedure.h | 7 +++-- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index b8bd44744..36c505a9f 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -6,13 +6,13 @@ * | --------------- <- ab * | old FR * | old FP - * | --------------- <- st, fp (a.k.a. lb) + * | --------------- <- fp (a.k.a. lb) * | locals - * | --------------- - * | spills * | --------------- + * | spills + * | --------------- <- sb * | saved regs - * | --------------- <- sp + * | --------------- <- sp, rb * V ...user area... * * st indexes up; lb indexes down. @@ -31,17 +31,31 @@ void platform_calculate_offsets(void) { struct hreg* hreg = current_proc->usedregs.item[i]; + if (!(hreg->attrs & burm_volatile_ATTR) && + ((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR))) + { + hreg->offset = current_proc->saved_size; + current_proc->saved_size += 8; + array_append(&saved_regs, hreg); + } + } + for (i=0; iusedregs.count; i++) + { + struct hreg* hreg = current_proc->usedregs.item[i]; + if (!(hreg->attrs & burm_volatile_ATTR) && ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) { + hreg->offset = current_proc->saved_size; current_proc->saved_size += 4; array_append(&saved_regs, hreg); } } - current_proc->fp_to_st = -current_proc->locals_size; current_proc->fp_to_ab = 8; current_proc->fp_to_lb = 0; + current_proc->fp_to_sb = -(current_proc->locals_size + current_proc->spills_size); + current_proc->fp_to_rb = current_proc->fp_to_sb - current_proc->saved_size; } struct hop* platform_prologue(void) @@ -52,9 +66,20 @@ struct hop* platform_prologue(void) current_proc->locals_size; struct hop* hop = new_hop(current_proc->entry, NULL); - hop_add_insel(hop, "! saved_size = %d bytes", current_proc->saved_size); - hop_add_insel(hop, "! spills_size = %d bytes", current_proc->spills_size); - hop_add_insel(hop, "! locals_size = %d bytes", current_proc->locals_size); + hop_add_insel(hop, "! params @ fp+%d", current_proc->fp_to_ab); + hop_add_insel(hop, "! lr @ fp+4"); + hop_add_insel(hop, "! fp @ fp+0"); + hop_add_insel(hop, "! locals @ fp-%d to fp+0", + current_proc->locals_size); + hop_add_insel(hop, "! spills @ fp-%d to fp-%d", + -current_proc->fp_to_sb, current_proc->locals_size); + for (i=0; iid, -(current_proc->fp_to_rb + hreg->offset)); + } + hop_add_insel(hop, "addi sp, sp, %d", -(spoffset + 8)); hop_add_insel(hop, "mfspr r0, lr"); hop_add_insel(hop, "stw fp, %d(sp)", spoffset + 0); @@ -67,10 +92,11 @@ struct hop* platform_prologue(void) { struct hreg* hreg = saved_regs.item[i]; if (hreg->attrs & burm_int_ATTR) - hop_add_insel(hop, "stw %H, %d(fp)", hreg, saved_offset); + hop_add_insel(hop, "stw %H, %d(fp)", + hreg, current_proc->fp_to_rb + saved_offset); else if (hreg->attrs & burm_float_ATTR) - hop_add_insel(hop, "stfs %H, %d(fp)", hreg, saved_offset); - saved_offset += 4; + hop_add_insel(hop, "stfs %H, %d(fp)", + hreg, current_proc->fp_to_rb + saved_offset); } return hop; } @@ -81,16 +107,15 @@ struct hop* platform_epilogue(void) int i; int saved_offset; - /* Saved reg offsets are negative. */ - saved_offset = -(current_proc->locals_size + current_proc->spills_size); for (i=0; iattrs & burm_int_ATTR) - hop_add_insel(hop, "lwz %H, %d(fp)", hreg, saved_offset); + hop_add_insel(hop, "lwz %H, %d(fp)", + hreg, current_proc->fp_to_rb + saved_offset); else if (hreg->attrs & burm_float_ATTR) - hop_add_insel(hop, "lfs %H, %d(fp)", hreg, saved_offset); - saved_offset += 4; + hop_add_insel(hop, "lfs %H, %d(fp)", + hreg, current_proc->fp_to_rb + saved_offset); } hop_add_insel(hop, "lwz r0, 4(fp)"); diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 27ea8be03..77c6dc260 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -113,6 +113,10 @@ void hop_add_insel(struct hop* hop, const char* fmt, ...) hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int))); break; + case 's': + hop_add_string_insel(hop, va_arg(ap, const char*)); + break; + case 'S': hop_add_st_offset_insel(hop, va_arg(ap, struct hreg*)); break; @@ -248,7 +252,7 @@ char* hop_render(struct hop* hop) break; case INSEL_ST_OFFSET: - appendf("%d", current_proc->fp_to_st + insel->u.hreg->offset); + appendf("%d", current_proc->fp_to_sb + insel->u.hreg->offset); break; case INSEL_AB_OFFSET: diff --git a/mach/proto/mcg/procedure.h b/mach/proto/mcg/procedure.h index ead7abc9b..226db804c 100644 --- a/mach/proto/mcg/procedure.h +++ b/mach/proto/mcg/procedure.h @@ -16,9 +16,10 @@ struct procedure int locals_size; int spills_size; int saved_size; - int fp_to_st; - int fp_to_ab; - int fp_to_lb; + int fp_to_ab; /* argument base (indexes up) */ + int fp_to_lb; /* locals base (indexes down) */ + int fp_to_sb; /* spill base (indexes up) */ + int fp_to_rb; /* saved registers base (indexes up) */ ARRAYOF(struct basicblock) blocks; IMAPOF(struct local) locals; ARRAYOF(struct hreg) usedregs; From 852d3a691d22f664e24741ffe5cb545c96ce5cdb Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 11 Nov 2016 21:48:36 +0100 Subject: [PATCH 172/230] Update the table to return call output values in the right registers. Fix the register allocator so the corrupted registers only apply to throughs (otherwise, you can't put output registers in corrupted registers). --- mach/powerpc/mcg/table | 22 +++++++++++----------- mach/proto/mcg/pass_registerallocator.c | 8 +++----- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 486d983ed..a6f416b65 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -19,7 +19,7 @@ REGISTERS r6 int volatile; r5 int volatile; r4 int volatile; - r3 int volatile ret; + r3 int volatile iret; r31 int; r30 int; @@ -185,7 +185,7 @@ PATTERNS emit "addi sp, sp, 8" cost 8; - SETRET.I(in:(ret)reg) + SETRET.I(in:(iret)reg) emit "! setret4" cost 1; @@ -392,12 +392,12 @@ PATTERNS emit "li32 %out.1, 0" cost 8; - out:(ret)reg = FROMF.I(in:(dret)reg) + out:(iret)reg = FROMF.I(in:(dret)reg) with corrupted(volatile) emit "bl .fromf2i" cost 4; - out:(ret)reg = FROMD.I(in:(dret)reg) + out:(iret)reg = FROMD.I(in:(dret)reg) with corrupted(volatile) emit "bl .fromd2i" cost 4; @@ -407,17 +407,17 @@ PATTERNS emit "bl .fromf2l" cost 4; - out:(dret)reg = FROMSI.D(in:(ret)reg) + out:(dret)reg = FROMSI.D(in:(iret)reg) with corrupted(volatile) emit "bl .fromsi2d" cost 4; - out:(fret)reg = FROMUI.F(in:(ret)reg) + out:(fret)reg = FROMUI.F(in:(iret)reg) with corrupted(volatile) emit "bl .fromui2f" cost 4; - out:(dret)reg = FROMUI.D(in:(ret)reg) + out:(dret)reg = FROMUI.D(in:(iret)reg) with corrupted(volatile) emit "bl .fromui2d" cost 4; @@ -493,8 +493,8 @@ PATTERNS cost 4; CALLLABEL(CALL) - out:(int)reg = CALLLABEL(CALL.I) - out:(long)reg = CALLLABEL(CALL.L) + out:(iret)reg = CALLLABEL(CALL.I) + out:(lret)reg = CALLLABEL(CALL.L) #define CALLINDIRECT(insn) \ insn (dest:(int)reg) \ @@ -504,8 +504,8 @@ PATTERNS cost 8; CALLINDIRECT(CALL) - out:(int)reg = CALLINDIRECT(CALL.I) - out:(long)reg = CALLINDIRECT(CALL.L) + out:(iret)reg = CALLINDIRECT(CALL.I) + out:(lret)reg = CALLINDIRECT(CALL.L) JUMP(dest:LABEL.I) emit "b $dest" diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 7c348f0a3..a064adb8e 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -153,8 +153,7 @@ static bool allocatable_stackable_input(struct hreg* hreg, struct vreg* vreg) static bool allocatable_stackable_output(struct hreg* hreg, struct vreg* vreg) { return !register_used(current_outs, hreg) && - (hreg->attrs & vreg->type) && - !(hreg->attrs & current_hop->insndata->corrupts); + (hreg->attrs & vreg->type); } static bool allocatable_input(struct hreg* hreg, struct vreg* vreg) @@ -174,7 +173,8 @@ static bool allocatable_output(struct hreg* hreg, struct vreg* vreg) static bool allocatable_through(struct hreg* hreg, struct vreg* vreg) { return allocatable_stackable_input(hreg, vreg) && - allocatable_stackable_output(hreg, vreg); + allocatable_stackable_output(hreg, vreg) && + !(hreg->attrs & current_hop->insndata->corrupts); } static struct hreg* find_input_reg(struct vreg* vreg) @@ -203,9 +203,7 @@ static struct hreg* find_output_reg(struct vreg* vreg) { hreg = hregs.item[i]; if (allocatable_output(hreg, vreg)) - { return hreg; - } } return NULL; From 48e74f46fc26ce0a4068f2b718eca09501f5d6e2 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 12 Nov 2016 19:20:58 +0100 Subject: [PATCH 173/230] Add the very experimental qemuppc plat, intended to generate minimal images which can be emulated using qemu (for, hopefully, a test suite). Currently it generates images which won't run because there's no RAM. --- build.lua | 1 + plat/linuxppc/descr | 3 +- plat/qemuppc/README | 42 ++++++++++ plat/qemuppc/boot.s | 74 +++++++++++++++++ plat/qemuppc/build-pkg.lua | 25 ++++++ plat/qemuppc/build-tools.lua | 33 ++++++++ plat/qemuppc/descr | 89 ++++++++++++++++++++ plat/qemuppc/include/ack/config.h | 14 ++++ plat/qemuppc/include/build.lua | 24 ++++++ plat/qemuppc/include/sys/ioctl.h | 76 +++++++++++++++++ plat/qemuppc/include/unistd.h | 123 ++++++++++++++++++++++++++++ plat/qemuppc/libsys/_hol0.s | 20 +++++ plat/qemuppc/libsys/_sys_rawread.s | 19 +++++ plat/qemuppc/libsys/_sys_rawwrite.s | 20 +++++ plat/qemuppc/libsys/brk.c | 43 ++++++++++ plat/qemuppc/libsys/build.lua | 16 ++++ plat/qemuppc/libsys/close.c | 14 ++++ plat/qemuppc/libsys/creat.c | 15 ++++ plat/qemuppc/libsys/getpid.c | 13 +++ plat/qemuppc/libsys/isatty.c | 8 ++ plat/qemuppc/libsys/kill.c | 14 ++++ plat/qemuppc/libsys/libsys.h | 11 +++ plat/qemuppc/libsys/lseek.c | 14 ++++ plat/qemuppc/libsys/open.c | 14 ++++ plat/qemuppc/libsys/read.c | 38 +++++++++ plat/qemuppc/libsys/signal.c | 15 ++++ plat/qemuppc/libsys/time.c | 17 ++++ plat/qemuppc/libsys/trap.s | 105 ++++++++++++++++++++++++ plat/qemuppc/libsys/write.c | 48 +++++++++++ 29 files changed, 946 insertions(+), 2 deletions(-) create mode 100644 plat/qemuppc/README create mode 100644 plat/qemuppc/boot.s create mode 100644 plat/qemuppc/build-pkg.lua create mode 100644 plat/qemuppc/build-tools.lua create mode 100644 plat/qemuppc/descr create mode 100644 plat/qemuppc/include/ack/config.h create mode 100644 plat/qemuppc/include/build.lua create mode 100644 plat/qemuppc/include/sys/ioctl.h create mode 100644 plat/qemuppc/include/unistd.h create mode 100644 plat/qemuppc/libsys/_hol0.s create mode 100644 plat/qemuppc/libsys/_sys_rawread.s create mode 100644 plat/qemuppc/libsys/_sys_rawwrite.s create mode 100644 plat/qemuppc/libsys/brk.c create mode 100644 plat/qemuppc/libsys/build.lua create mode 100644 plat/qemuppc/libsys/close.c create mode 100644 plat/qemuppc/libsys/creat.c create mode 100644 plat/qemuppc/libsys/getpid.c create mode 100644 plat/qemuppc/libsys/isatty.c create mode 100644 plat/qemuppc/libsys/kill.c create mode 100644 plat/qemuppc/libsys/libsys.h create mode 100644 plat/qemuppc/libsys/lseek.c create mode 100644 plat/qemuppc/libsys/open.c create mode 100644 plat/qemuppc/libsys/read.c create mode 100644 plat/qemuppc/libsys/signal.c create mode 100644 plat/qemuppc/libsys/time.c create mode 100644 plat/qemuppc/libsys/trap.s create mode 100644 plat/qemuppc/libsys/write.c diff --git a/build.lua b/build.lua index 05a4eafcd..fd8582fd9 100644 --- a/build.lua +++ b/build.lua @@ -9,6 +9,7 @@ vars.plats = { "linux386", "linux68k", "linuxppc", + "qemuppc", "pc86", "rpi", } diff --git a/plat/linuxppc/descr b/plat/linuxppc/descr index 79188640a..12bece6e9 100644 --- a/plat/linuxppc/descr +++ b/plat/linuxppc/descr @@ -33,8 +33,7 @@ var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi name be from .m.g to .s - # Change this back to ncg to revert to the old code generator - program {EM}/lib/ack/{PLATFORM}/mcg + program {EM}/lib/ack/{PLATFORM}/ncg mapflag -gdb GF=-gdb args {GF?} < stdout diff --git a/plat/qemuppc/README b/plat/qemuppc/README new file mode 100644 index 000000000..412e33ad1 --- /dev/null +++ b/plat/qemuppc/README @@ -0,0 +1,42 @@ +# $Source: /cvsroot/tack/Ack/plat/linux386/README,v $ +# $State: Exp $ +# $Revision: 1.2 $ + + +The linux386 platform +===================== + +linux386 is an i386-based BSP that produces Linux ELF executables. + +This port only implements a very limited number of system calls; basically, +just enough to make the demo apps run. Adding more is easy, but there are some +subtleties that require more thought. The port should be considered only in +proof-of-concept stage right now. + +Important note: you *can't* link access ELF shared libraries from these +executables. In other words, you have to all your work from inside ACK. + +IEEE floating point is available, but requires an FPU. + +The executables are generated with aelfslod and are extremely simple; there's +one rwx ELF section which contains all the application's code and data. This +is not optimal, but it does work. + + +Bugs +==== + +isatty() is a stub and always returns 0. + + +Example command line +==================== + +ack -mlinux386 -O -o linux386.exe examples/paranoia.c + +The file linux386.exe can then be run on a i386 Linux machine (or on an +emulation thereof). + + +David Given +dg@cowlark.com diff --git a/plat/qemuppc/boot.s b/plat/qemuppc/boot.s new file mode 100644 index 000000000..dbd61ec1b --- /dev/null +++ b/plat/qemuppc/boot.s @@ -0,0 +1,74 @@ +# +! $Source: /cvsroot/tack/Ack/plat/linux386/boot.s,v $ +! $State: Exp $ +! $Revision: 1.3 $ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +begtext: + ! This code is placed at the beginning of the ELF executable and is the + ! first thing that runs. + ! + ! On entry, the stack looks like this: + ! + ! sp+... NULL + ! sp+8+(4*argc) env (X quads) + ! sp+4+(4*argc) NULL + ! sp+4 argv (argc quads) + ! sp argc + ! + ! The ACK actually expects: + ! + ! sp+8 argc + ! sp+4 ptr to argv + ! sp ptr to env + + li32 r3, envp + stwu r3, -4(sp) + + li32 r3, argv + stwu r3, -4(sp) + + li32 r3, 1 ! argc + stwu r3, -4(sp) + + bl __m_a_i_n + ! falls through + +.define __exit +.extern __exit +.define EXIT +.extern EXIT +__exit: +EXIT: + b EXIT + +! Define symbols at the beginning of our various segments, so that we can find +! them. (Except .text, which has already been done.) + +.sect .data; begdata: +.sect .rom; begrom: +.sect .bss; begbss: + +! Some magic data. All EM systems need these. + +.define _errno +.comm _errno, 4 ! Posix errno storage + +! The argv and env arrays. + +.sect .rom +argv: .data4 exename, 0 +envp: .data4 0 +exename: .asciz 'qemuppc.img' + +.define .trppc, .ignmask +.comm .trppc, 4 ! ptr to user trap handler +.comm .ignmask, 4 ! user trap ignore mask diff --git a/plat/qemuppc/build-pkg.lua b/plat/qemuppc/build-pkg.lua new file mode 100644 index 000000000..e30e83efc --- /dev/null +++ b/plat/qemuppc/build-pkg.lua @@ -0,0 +1,25 @@ +include("plat/build.lua") + +ackfile { + name = "boot", + srcs = { "./boot.s" }, + vars = { plat = "qemuppc" } +} + +build_plat_libs { + name = "libs", + arch = "powerpc", + plat = "qemuppc", +} + +installable { + name = "pkg", + map = { + "+tools", + "+libs", + "./include+pkg", + ["$(PLATIND)/qemuppc/boot.o"] = "+boot", + ["$(PLATIND)/qemuppc/libsys.a"] = "./libsys+lib", + } +} + diff --git a/plat/qemuppc/build-tools.lua b/plat/qemuppc/build-tools.lua new file mode 100644 index 000000000..e4f3f534b --- /dev/null +++ b/plat/qemuppc/build-tools.lua @@ -0,0 +1,33 @@ +include("plat/build.lua") + +build_as { + name = "as", + arch = "powerpc", +} + +build_mcg { + name = "mcg", + arch = "powerpc", +} + +build_ncg { + name = "ncg", + arch = "powerpc", +} + +build_top { + name = "top", + arch = "powerpc", +} + +return installable { + name = "tools", + map = { + ["$(PLATDEP)/qemuppc/as"] = "+as", + ["$(PLATDEP)/qemuppc/ncg"] = "+ncg", + ["$(PLATDEP)/qemuppc/mcg"] = "+mcg", + ["$(PLATDEP)/qemuppc/top"] = "+top", + ["$(PLATIND)/descr/qemuppc"] = "./descr", + "util/opt+pkg", + } +} diff --git a/plat/qemuppc/descr b/plat/qemuppc/descr new file mode 100644 index 000000000..f28e7482d --- /dev/null +++ b/plat/qemuppc/descr @@ -0,0 +1,89 @@ +# plat/linuxppc/descr + +var w=4 +var wa=4 +var p={w} +var pa={w} +var s=2 +var sa={s} +var l={w} +var la={w} +var f={w} +var fa={w} +var d=8 +var da={d} +var x=8 +var xa={x} +var ARCH=powerpc +var PLATFORM=qemuppc +var PLATFORMDIR={EM}/share/ack/{PLATFORM} +var CPP_F=-D__unix +var ALIGN=-a0:4 -a1:4 -a2:4 -a3:4 -b0:0x01000000 +var C_LIB={PLATFORMDIR}/libc-ansi.a +# bitfields reversed for compatibility with (g)cc. +var CC_ALIGN=-Vr +var OLD_C_LIB={C_LIB} +var MACHOPT_F= + +# Override the setting in fe so that files compiled for qemuppc can see +# the platform-specific headers. + +var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi + +name be + from .m.g + to .s + # Change this back to ncg to revert to the old code generator + program {EM}/lib/ack/{PLATFORM}/ncg + mapflag -gdb GF=-gdb + args {GF?} < + stdout + need .e +end +name asopt + from .s + to .so + program {EM}/lib/ack/{PLATFORM}/top + args + optimizer + stdin + stdout +end +name as + from .s.so + to .o + program {EM}/lib/ack/{PLATFORM}/as + args - -o > < + prep cond +end +name led + from .o.a + to .out + program {EM}/lib/ack/em_led + mapflag -l* LNAME={PLATFORMDIR}/lib* + mapflag -fp FLOATS={EM}/{LIB}fp + args {ALIGN} {SEPID?} \ + (.e:{HEAD}={PLATFORMDIR}/boot.o) \ + ({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.c={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.mod={PLATFORMDIR}/modula2.o) \ + ({RTS}:.p={PLATFORMDIR}/pascal.o) \ + -o > < \ + (.p:{TAIL}={PLATFORMDIR}/libpascal.a) \ + (.b:{TAIL}={PLATFORMDIR}/libbasic.a) \ + (.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \ + (.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \ + (.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \ + {FLOATS?} \ + (.e:{TAIL}={PLATFORMDIR}/libem.a \ + {PLATFORMDIR}/libsys.a \ + {PLATFORMDIR}/libend.a) + linker +end +name cv + from .out + to .exe + program {EM}/bin/aslod + args < > + outfile qemuppc.img +end diff --git a/plat/qemuppc/include/ack/config.h b/plat/qemuppc/include/ack/config.h new file mode 100644 index 000000000..f58ee3a43 --- /dev/null +++ b/plat/qemuppc/include/ack/config.h @@ -0,0 +1,14 @@ +/* $Source: /cvsroot/tack/Ack/plat/linux386/include/ack/config.h,v $ + * $State: Exp $ + * $Revision: 1.1 $ + */ + +#ifndef _ACK_CONFIG_H +#define _ACK_CONFIG_H + +/* We're providing a time() system call rather than wanting a wrapper around + * gettimeofday() in the libc. */ + +#define ACKCONF_TIME_IS_A_SYSCALL + +#endif diff --git a/plat/qemuppc/include/build.lua b/plat/qemuppc/include/build.lua new file mode 100644 index 000000000..dc1b0bb43 --- /dev/null +++ b/plat/qemuppc/include/build.lua @@ -0,0 +1,24 @@ +include("plat/build.lua") + +headermap = {} +packagemap = {} + +local function addheader(h) + headermap[h] = "./"..h + packagemap["$(PLATIND)/qemuppc/include/"..h] = "./"..h +end + +addheader("ack/config.h") +addheader("sys/ioctl.h") +addheader("unistd.h") + +acklibrary { + name = "headers", + hdrs = headermap +} + +installable { + name = "pkg", + map = packagemap +} + diff --git a/plat/qemuppc/include/sys/ioctl.h b/plat/qemuppc/include/sys/ioctl.h new file mode 100644 index 000000000..af41165d7 --- /dev/null +++ b/plat/qemuppc/include/sys/ioctl.h @@ -0,0 +1,76 @@ +/* $Source: /cvsroot/tack/Ack/plat/linux386/include/sys/ioctl.h,v $ + * $State: Exp $ + * $Revision: 1.1 $ + */ + +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +/* These are copied from the ioctl_list(2) man page. */ + +/* */ + +#define FIOSETOWN 0x00008901 +#define SIOCSPGRP 0x00008902 +#define FIOGETOWN 0x00008903 +#define SIOCGPGRP 0x00008904 +#define SIOCATMARK 0x00008905 +#define SIOCGSTAMP 0x00008906 + +/* */ + +#define TCGETS 0x00005401 +#define TCSETS 0x00005402 +#define TCSETSW 0x00005403 +#define TCSETSF 0x00005404 +#define TCGETA 0x00005405 +#define TCSETA 0x00005406 +#define TCSETAW 0x00005407 +#define TCSETAF 0x00005408 +#define TCSBRK 0x00005409 +#define TCXONC 0x0000540A +#define TCFLSH 0x0000540B +#define TIOCEXCL 0x0000540C +#define TIOCNXCL 0x0000540D +#define TIOCSCTTY 0x0000540E +#define TIOCGPGRP 0x0000540F +#define TIOCSPGRP 0x00005410 +#define TIOCOUTQ 0x00005411 +#define TIOCSTI 0x00005412 +#define TIOCGWINSZ 0x00005413 +#define TIOCSWINSZ 0x00005414 +#define TIOCMGET 0x00005415 +#define TIOCMBIS 0x00005416 +#define TIOCMBIC 0x00005417 +#define TIOCMSET 0x00005418 +#define TIOCGSOFTCAR 0x00005419 +#define TIOCSSOFTCAR 0x0000541A +#define FIONREAD 0x0000541B +#define TIOCINQ 0x0000541B +#define TIOCLINUX 0x0000541C +#define TIOCCONS 0x0000541D +#define TIOCGSERIAL 0x0000541E +#define TIOCSSERIAL 0x0000541F +#define TIOCPKT 0x00005420 +#define FIONBIO 0x00005421 +#define TIOCNOTTY 0x00005422 +#define TIOCSETD 0x00005423 +#define TIOCGETD 0x00005424 +#define TCSBRKP 0x00005425 +#define TIOCTTYGSTRUCT 0x00005426 +#define FIONCLEX 0x00005450 +#define FIOCLEX 0x00005451 +#define FIOASYNC 0x00005452 +#define TIOCSERCONFIG 0x00005453 +#define TIOCSERGWILD 0x00005454 +#define TIOCSERSWILD 0x00005455 +#define TIOCGLCKTRMIOS 0x00005456 +#define TIOCSLCKTRMIOS 0x00005457 +#define TIOCSERGSTRUCT 0x00005458 +#define TIOCSERGETLSR 0x00005459 +#define TIOCSERGETMULTI 0x0000545A +#define TIOCSERSETMULTI 0x0000545B + + + +#endif diff --git a/plat/qemuppc/include/unistd.h b/plat/qemuppc/include/unistd.h new file mode 100644 index 000000000..5cbdc1b5d --- /dev/null +++ b/plat/qemuppc/include/unistd.h @@ -0,0 +1,123 @@ +/* + * unistd.h - standard system calls + */ +/* $Id$ */ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include +#include + +/* Types */ + +typedef int pid_t; +typedef int mode_t; + +typedef long suseconds_t; + +/* Time handling. */ + +struct timeval +{ + time_t tv_sec; + suseconds_t tv_usec; +}; + +struct timezone +{ + int tz_minuteswest; + int tz_dsttime; +}; /* obsolete, unused */ + +extern int gettimeofday(struct timeval* tv, struct timezone* tz); +extern int settimeofday(const struct timeval* tv, const struct timezone* tz); + +/* File access. */ + +enum +{ + O_ACCMODE = 0x3, + + O_RDONLY = 0, + O_WRONLY = 1, + O_RDWR = 2, + + O_CREAT = 0x10, + O_TRUNC = 0x20, + O_APPEND = 0x40 +}; + +extern int open(const char* path, int access, ...); +extern int creat(const char* path, mode_t mode); +extern int close(int d); +extern int read(int fd, void* buffer, size_t count); +extern int write(int fd, void* buffer, size_t count); +extern off_t lseek(int fildes, off_t offset, int whence); +extern int fcntl(int fd, int op, ...); + +/* Special variables */ + +extern char** environ; + +/* Implemented system calls */ + +extern void _exit(int); +extern pid_t getpid(void); +extern int brk(void* ptr); +extern void* sbrk(intptr_t increment); +extern int isatty(int d); + +/* Signal handling */ + +typedef int sig_atomic_t; + +#define SIG_ERR ((sighandler_t) -1) /* Error return. */ +#define SIG_DFL ((sighandler_t) 0) /* Default action. */ +#define SIG_IGN ((sighandler_t) 1) /* Ignore signal. */ + +#define SIGHUP 1 /* Hangup (POSIX). */ +#define SIGINT 2 /* Interrupt (ANSI). */ +#define SIGQUIT 3 /* Quit (POSIX). */ +#define SIGILL 4 /* Illegal instruction (ANSI). */ +#define SIGTRAP 5 /* Trace trap (POSIX). */ +#define SIGABRT 6 /* Abort (ANSI). */ +#define SIGIOT 6 /* IOT trap (4.2 BSD). */ +#define SIGBUS 7 /* BUS error (4.2 BSD). */ +#define SIGFPE 8 /* Floating-point exception (ANSI). */ +#define SIGKILL 9 /* Kill, unblockable (POSIX). */ +#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ +#define SIGSEGV 11 /* Segmentation violation (ANSI). */ +#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ +#define SIGPIPE 13 /* Broken pipe (POSIX). */ +#define SIGALRM 14 /* Alarm clock (POSIX). */ +#define SIGTERM 15 /* Termination (ANSI). */ +#define SIGSTKFLT 16 /* Stack fault. */ +#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ +#define SIGCHLD 17 /* Child status has changed (POSIX). */ +#define SIGCONT 18 /* Continue (POSIX). */ +#define SIGSTOP 19 /* Stop, unblockable (POSIX). */ +#define SIGTSTP 20 /* Keyboard stop (POSIX). */ +#define SIGTTIN 21 /* Background read from tty (POSIX). */ +#define SIGTTOU 22 /* Background write to tty (POSIX). */ +#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ +#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ +#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ +#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ +#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ +#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ +#define SIGPOLL SIGIO /* Pollable event occurred (System V). */ +#define SIGIO 29 /* I/O now possible (4.2 BSD). */ +#define SIGPWR 30 /* Power failure restart (System V). */ +#define SIGSYS 31 /* Bad system call. */ +#define SIGUNUSED 31 + +#define _NSIG 32 /* Biggest signal number + 1 + (not including real-time signals). */ +typedef void (*sighandler_t)(int); +extern sighandler_t signal(int signum, sighandler_t handler); +extern int raise(int signum); + + + +#endif diff --git a/plat/qemuppc/libsys/_hol0.s b/plat/qemuppc/libsys/_hol0.s new file mode 100644 index 000000000..fcb58727b --- /dev/null +++ b/plat/qemuppc/libsys/_hol0.s @@ -0,0 +1,20 @@ +# +! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_hol0.s,v $ +! $State: Exp $ +! $Revision: 1.1 $ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! +! This data block is used to store information about the current line number +! and file. + +.define hol0 +.comm hol0, 8 diff --git a/plat/qemuppc/libsys/_sys_rawread.s b/plat/qemuppc/libsys/_sys_rawread.s new file mode 100644 index 000000000..1f2cd9d1f --- /dev/null +++ b/plat/qemuppc/libsys/_sys_rawread.s @@ -0,0 +1,19 @@ +# +#include "powerpc.h" + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Reads a single byte. + +.define __sys_rawread +__sys_rawread: + li32 r3, 0 + bclr ALWAYS, 0, 0 + \ No newline at end of file diff --git a/plat/qemuppc/libsys/_sys_rawwrite.s b/plat/qemuppc/libsys/_sys_rawwrite.s new file mode 100644 index 000000000..e9a1cc7ec --- /dev/null +++ b/plat/qemuppc/libsys/_sys_rawwrite.s @@ -0,0 +1,20 @@ +# +#include "powerpc.h" + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Writes a single byte to the console. + +.define __sys_rawwrite +.extern __sys_rawwrite + +__sys_rawwrite: + bclr ALWAYS, 0, 0 + \ No newline at end of file diff --git a/plat/qemuppc/libsys/brk.c b/plat/qemuppc/libsys/brk.c new file mode 100644 index 000000000..02e213399 --- /dev/null +++ b/plat/qemuppc/libsys/brk.c @@ -0,0 +1,43 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +#define OUT_OF_MEMORY (void*)(-1) /* sbrk returns this on failure */ +#define STACK_BUFFER 128 /* number of bytes to leave for stack */ + +extern char _end[1]; +static char* current = _end; + +int brk(void* newend) +{ + /* This variable is used to figure out the current stack pointer, + * by taking its address. */ + char dummy; + char* p = newend; + + if ((p > (&dummy - STACK_BUFFER)) || + (p < _end)) + return -1; + + current = p; + return 0; +} + +void* sbrk(intptr_t increment) +{ + char* old; + + if (increment == 0) + return current; + + old = current; + if (brk(old + increment) < 0) + return OUT_OF_MEMORY; + + return old; +} diff --git a/plat/qemuppc/libsys/build.lua b/plat/qemuppc/libsys/build.lua new file mode 100644 index 000000000..7281bbc61 --- /dev/null +++ b/plat/qemuppc/libsys/build.lua @@ -0,0 +1,16 @@ +acklibrary { + name = "lib", + srcs = { + "./*.s", + "./*.c", + }, + deps = { + "lang/cem/libcc.ansi/headers+headers", + "plat/qemuppc/include+headers", + "mach/powerpc/libem+headers_qemuppc", + }, + vars = { + plat = "qemuppc" + } +} + \ No newline at end of file diff --git a/plat/qemuppc/libsys/close.c b/plat/qemuppc/libsys/close.c new file mode 100644 index 000000000..1c570029b --- /dev/null +++ b/plat/qemuppc/libsys/close.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int close(int fd) +{ + errno = EBADF; + return -1; +} diff --git a/plat/qemuppc/libsys/creat.c b/plat/qemuppc/libsys/creat.c new file mode 100644 index 000000000..34ace747c --- /dev/null +++ b/plat/qemuppc/libsys/creat.c @@ -0,0 +1,15 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include "libsys.h" + +int open(const char* path, int access, ...) +{ + errno = EACCES; + return -1; +} diff --git a/plat/qemuppc/libsys/getpid.c b/plat/qemuppc/libsys/getpid.c new file mode 100644 index 000000000..5e6eb003e --- /dev/null +++ b/plat/qemuppc/libsys/getpid.c @@ -0,0 +1,13 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +pid_t getpid(void) +{ + return 0; +} diff --git a/plat/qemuppc/libsys/isatty.c b/plat/qemuppc/libsys/isatty.c new file mode 100644 index 000000000..8bee360e0 --- /dev/null +++ b/plat/qemuppc/libsys/isatty.c @@ -0,0 +1,8 @@ +#include +#include +#include + +int isatty(int fd) +{ + return 1; +} diff --git a/plat/qemuppc/libsys/kill.c b/plat/qemuppc/libsys/kill.c new file mode 100644 index 000000000..4a179c47c --- /dev/null +++ b/plat/qemuppc/libsys/kill.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int kill(pid_t pid, int sig) +{ + errno = EINVAL; + return -1; +} diff --git a/plat/qemuppc/libsys/libsys.h b/plat/qemuppc/libsys/libsys.h new file mode 100644 index 000000000..d4095cada --- /dev/null +++ b/plat/qemuppc/libsys/libsys.h @@ -0,0 +1,11 @@ +#ifndef LIBSYS_H +#define LIBSYS_H + +extern void _sys_rawwrite(unsigned char b); +extern unsigned char _sys_rawread(void); + +extern void _sys_write_tty(char c); + +/* extern int _sys_ttyflags; */ + +#endif diff --git a/plat/qemuppc/libsys/lseek.c b/plat/qemuppc/libsys/lseek.c new file mode 100644 index 000000000..ecbc4b520 --- /dev/null +++ b/plat/qemuppc/libsys/lseek.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +off_t lseek(int fd, off_t offset, int whence) +{ + errno = EINVAL; + return -1; +} diff --git a/plat/qemuppc/libsys/open.c b/plat/qemuppc/libsys/open.c new file mode 100644 index 000000000..8f18317c5 --- /dev/null +++ b/plat/qemuppc/libsys/open.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include "libsys.h" + +int creat(const char* path, int mode) +{ + return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode); +} diff --git a/plat/qemuppc/libsys/read.c b/plat/qemuppc/libsys/read.c new file mode 100644 index 000000000..21fe90ebb --- /dev/null +++ b/plat/qemuppc/libsys/read.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "libsys.h" + +int read(int fd, void* buffer, size_t count) +{ + char i; + + /* We're only allowed to read from fd 0, 1 or 2. */ + + if ((fd < 0) || (fd > 2)) + { + errno = EBADF; + return -1; + } + + /* Empty buffer? */ + + if (count == 0) + return 0; + + /* Read one byte. */ + + i = _sys_rawread(); +#if 0 + if ((i == '\r') && !(_sys_ttyflags & RAW)) + i = '\n'; + if (_sys_ttyflags & ECHO) + _sys_write_tty(i); +#endif + if (i == '\r') + i = '\n'; + _sys_write_tty(i); + + *(char*)buffer = i; + return 1; +} diff --git a/plat/qemuppc/libsys/signal.c b/plat/qemuppc/libsys/signal.c new file mode 100644 index 000000000..a87b9ced2 --- /dev/null +++ b/plat/qemuppc/libsys/signal.c @@ -0,0 +1,15 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include +#include "libsys.h" + +sighandler_t signal(int signum, sighandler_t handler) +{ + return SIG_DFL; +} diff --git a/plat/qemuppc/libsys/time.c b/plat/qemuppc/libsys/time.c new file mode 100644 index 000000000..5ef17b841 --- /dev/null +++ b/plat/qemuppc/libsys/time.c @@ -0,0 +1,17 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include +#include "libsys.h" + +time_t time(time_t* t) +{ + if (t) + *t = 0; + return 0; +} diff --git a/plat/qemuppc/libsys/trap.s b/plat/qemuppc/libsys/trap.s new file mode 100644 index 000000000..09d3b0b21 --- /dev/null +++ b/plat/qemuppc/libsys/trap.s @@ -0,0 +1,105 @@ +# +! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_syscall.s,v $ +! $State: Exp $ +! $Revision: 1.1 $ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +#define IFFALSE 4 +#define IFTRUE 12 +#define ALWAYS 20 + +#define LT 0 +#define GT 1 +#define EQ 2 +#define OV 3 + +EARRAY = 0 +ERANGE = 1 +ESET = 2 +EIOVFL = 3 +EFOVFL = 4 +EFUNFL = 5 +EIDIVZ = 6 +EFDIVZ = 7 +EIUND = 8 +EFUND = 9 +ECONV = 10 +ESTACK = 16 +EHEAP = 17 +EILLINS = 18 +EODDZ = 19 +ECASE = 20 +EMEMFLT = 21 +EBADPTR = 22 +EBADPC = 23 +EBADLAE = 24 +EBADMON = 25 +EBADLIN = 26 +EBADGTO = 27 +EUNIMPL = 63 ! unimplemented em-instruction called + +! EM trap handling. + +.define .trap_ecase +.trap_ecase: + addi r3, r0, ECASE + b .trap + +.define .trap_earray +.trap_earray: + addi r3, r0, EARRAY + b .trap + +.define .trap +.trap: + cmpi cr0, 0, r3, 15 ! traps >15 can't be ignored + bc IFTRUE, LT, 1f + + addi r4, r0, 1 + rlwnm r4, r4, r3, 0, 31 ! calculate trap bit + li32 r5, .ignmask + lwz r5, 0(r5) ! load ignore mask + and. r4, r4, r5 ! compare + bclr IFFALSE, EQ, 0 ! return if non-zero + +1: + li32 r4, .trppc + lwz r5, 0(r4) ! load user trap routine + or. r5, r5, r5 ! test + bc IFTRUE, EQ, fatal ! if no user trap routine, bail out + + addi r0, r0, 0 + stw r0, 0(r4) ! reset trap routine + + mfspr r0, lr + stwu r0, -4(sp) ! save old lr + + stwu r3, -4(sp) + mtspr ctr, r5 + bcctrl ALWAYS, 0, 0 ! call trap routine + + lwz r0, 4(sp) ! load old lr again + addi sp, sp, 8 ! retract over stack usage + bclr ALWAYS, 0, 0 ! return + +fatal: + addi r3, r0, 1 + li32 r4, message + addi r5, r0, 6 + addi r0, r0, 4 ! write() + sc 0 + + addi r0, r0, 1 ! exit() + sc 0 + +.sect .rom +message: + .ascii "TRAP!\n" diff --git a/plat/qemuppc/libsys/write.c b/plat/qemuppc/libsys/write.c new file mode 100644 index 000000000..8d2dd0d74 --- /dev/null +++ b/plat/qemuppc/libsys/write.c @@ -0,0 +1,48 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include "libsys.h" + +void _sys_write_tty(char c) +{ + _sys_rawwrite(c); +#if 0 + if ((c == '\n') && !(_sys_ttyflags & RAW)) + _sys_rawwrite('\r'); +#endif + if (c == '\n') + _sys_rawwrite('\r'); +} + +int write(int fd, void* buffer, size_t count) +{ + int i; + char* p = buffer; + + /* We're only allowed to write to fd 0, 1 or 2. */ + + if ((fd < 0) || (fd > 2)) + { + errno = EBADF; + return -1; + } + + /* Write all data. */ + + i = 0; + while (i < count) + { + _sys_write_tty(*p++); + + i++; + } + + /* No failures. */ + + return count; +} From f52cb45e4997c2af60222a9bd50f08f7bebe1b8b Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 12 Nov 2016 22:09:54 +0100 Subject: [PATCH 174/230] Add just enough Open Firmware support for an output console. --- plat/qemuppc/boot.s | 14 +++++ plat/qemuppc/libsys/_sys_rawread.s | 19 ------- plat/qemuppc/libsys/_sys_rawwrite.s | 20 -------- plat/qemuppc/libsys/libsys.h | 2 + plat/qemuppc/libsys/openfirmware.c | 80 +++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 39 deletions(-) delete mode 100644 plat/qemuppc/libsys/_sys_rawread.s delete mode 100644 plat/qemuppc/libsys/_sys_rawwrite.s create mode 100644 plat/qemuppc/libsys/openfirmware.c diff --git a/plat/qemuppc/boot.s b/plat/qemuppc/boot.s index dbd61ec1b..2dd9a4c5c 100644 --- a/plat/qemuppc/boot.s +++ b/plat/qemuppc/boot.s @@ -30,6 +30,9 @@ begtext: ! sp+4 ptr to argv ! sp ptr to env + li32 r3, __openfirmware_ptr + stw r5, 0(r3) + li32 r3, envp stwu r3, -4(sp) @@ -39,6 +42,7 @@ begtext: li32 r3, 1 ! argc stwu r3, -4(sp) + bl _openfirmware_init bl __m_a_i_n ! falls through @@ -50,6 +54,15 @@ __exit: EXIT: b EXIT +.define _openfirmware_call +.extern _openfirmware_call +_openfirmware_call: + lwz r3, 0(sp) + li32 r4, __openfirmware_ptr + lwz r4, 0(r4) + mtspr ctr, r4 + bcctr 20, 0, 0 + ! Define symbols at the beginning of our various segments, so that we can find ! them. (Except .text, which has already been done.) @@ -72,3 +85,4 @@ exename: .asciz 'qemuppc.img' .define .trppc, .ignmask .comm .trppc, 4 ! ptr to user trap handler .comm .ignmask, 4 ! user trap ignore mask +.comm __openfirmware_ptr, 4 ! OpenFirmware entry point diff --git a/plat/qemuppc/libsys/_sys_rawread.s b/plat/qemuppc/libsys/_sys_rawread.s deleted file mode 100644 index 1f2cd9d1f..000000000 --- a/plat/qemuppc/libsys/_sys_rawread.s +++ /dev/null @@ -1,19 +0,0 @@ -# -#include "powerpc.h" - -! Declare segments (the order is important). - -.sect .text -.sect .rom -.sect .data -.sect .bss - -.sect .text - -! Reads a single byte. - -.define __sys_rawread -__sys_rawread: - li32 r3, 0 - bclr ALWAYS, 0, 0 - \ No newline at end of file diff --git a/plat/qemuppc/libsys/_sys_rawwrite.s b/plat/qemuppc/libsys/_sys_rawwrite.s deleted file mode 100644 index e9a1cc7ec..000000000 --- a/plat/qemuppc/libsys/_sys_rawwrite.s +++ /dev/null @@ -1,20 +0,0 @@ -# -#include "powerpc.h" - -! Declare segments (the order is important). - -.sect .text -.sect .rom -.sect .data -.sect .bss - -.sect .text - -! Writes a single byte to the console. - -.define __sys_rawwrite -.extern __sys_rawwrite - -__sys_rawwrite: - bclr ALWAYS, 0, 0 - \ No newline at end of file diff --git a/plat/qemuppc/libsys/libsys.h b/plat/qemuppc/libsys/libsys.h index d4095cada..cf9878b87 100644 --- a/plat/qemuppc/libsys/libsys.h +++ b/plat/qemuppc/libsys/libsys.h @@ -1,6 +1,8 @@ #ifndef LIBSYS_H #define LIBSYS_H +extern uint32_t openfirmware_call(void* array); + extern void _sys_rawwrite(unsigned char b); extern unsigned char _sys_rawread(void); diff --git a/plat/qemuppc/libsys/openfirmware.c b/plat/qemuppc/libsys/openfirmware.c new file mode 100644 index 000000000..ad0c282ee --- /dev/null +++ b/plat/qemuppc/libsys/openfirmware.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include "libsys.h" + +static void* stdout_handle; + +static void* of_finddevice(const char* name) +{ + struct + { + const char* method; + int ins, outs; + const char* name; + void* phandle; + } args; + + args.method = "finddevice"; + args.ins = 1; + args.outs = 1; + args.name = name; + openfirmware_call(&args); + return args.phandle; +} + +static int of_getprop(void* phandle, const char* name, void* dest, int destlen) +{ + struct + { + const char* method; + int ins, outs; + void* phandle; + const char* name; + void* dest; + int destlen; + int flag; + } args; + + args.method = "getprop"; + args.ins = 4; + args.outs = 1; + args.phandle = phandle; + args.name = name; + args.dest = dest; + args.destlen = destlen; + openfirmware_call(&args); + return args.flag; +} + +void openfirmware_init(void) +{ + void* chosen = of_finddevice("/chosen"); + of_getprop(chosen, "stdout", &stdout_handle, sizeof(stdout_handle)); +} + +unsigned char _sys_rawread(void) +{ + return 0; +} + +void _sys_rawwrite(unsigned char c) +{ + struct + { + const char* method; + int ins, outs; + void* ihandle; + void* address; + int len; + int actual; + } args; + + args.method = "write"; + args.ins = 3; + args.outs = 1; + args.ihandle = stdout_handle; + args.address = &c; + args.len = 1; + openfirmware_call(&args); +} From e9fe1d70a6cf3fdb8d61f62d49d2bd711c466833 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 13 Nov 2016 13:28:09 +0100 Subject: [PATCH 175/230] Fix (or at least, work around) an issue with library order. Make sure the Basic error symbols are actually defined. --- first/ackbuilder.lua | 3 ++- first/build.lua | 5 +++-- lang/basic/lib/error.c | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/first/ackbuilder.lua b/first/ackbuilder.lua index f66bcee1d..81e86b528 100644 --- a/first/ackbuilder.lua +++ b/first/ackbuilder.lua @@ -729,9 +729,10 @@ definerule("simplerule", definerule("installable", { map = { type="targets", default={} }, + deps = { type="targets", default={} }, }, function (e) - local deps = {} + local deps = filenamesof(e.deps) local commands = {} local srcs = {} local outs = {} diff --git a/first/build.lua b/first/build.lua index 3240f9f1a..85df519a8 100644 --- a/first/build.lua +++ b/first/build.lua @@ -226,6 +226,7 @@ definerule("cprogram", }, function (e) local libs = matching(filenamesof(e.deps), "%.a$") + local srcs = {} if (#e.srcs > 0) then for _, f in pairs( matching( @@ -240,7 +241,7 @@ definerule("cprogram", "%.a$" ) ) do - libs[#libs+1] = f + srcs[#srcs+1] = f end end @@ -248,7 +249,7 @@ definerule("cprogram", name = e.name, cwd = e.cwd, deps = e.deps, - ins = libs, + ins = { srcs, libs }, outleaves = { e.name }, commands = e.commands, } diff --git a/lang/basic/lib/error.c b/lang/basic/lib/error.c index b2d893adc..becc69d7a 100644 --- a/lang/basic/lib/error.c +++ b/lang/basic/lib/error.c @@ -1,6 +1,9 @@ #include #include +int _errsym; +int _erlsym; + /* error takes an error value in the range of 0-255 */ /* and generates a trap */ @@ -52,9 +55,6 @@ char *errortable[255]={ error(index) int index; { - extern int _errsym; - extern int _erlsym; - _setline(); if( index<0 || index >40 ) printf("LINE %d:ERROR %d: Unprintable error\n",_erlsym,index); From 6a4f465f53bfe40c807275352d9a013475fe9bcf Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 13 Nov 2016 13:37:22 +0100 Subject: [PATCH 176/230] Add a rather bodged test framework for the qemuppc plat, which only runs if the qemu-system-ppc emulator is installed. --- build.lua | 10 ++++++++ plat/qemuppc/build-pkg.lua | 1 + plat/qemuppc/tests/_dummy.c | 8 ++++++ plat/qemuppc/tests/build.lua | 44 ++++++++++++++++++++++++++++++++ plat/qemuppc/tests/div.c | 17 ++++++++++++ plat/qemuppc/tests/lib/build.lua | 8 ++++++ plat/qemuppc/tests/lib/test.c | 29 +++++++++++++++++++++ plat/qemuppc/tests/lib/test.h | 14 ++++++++++ plat/qemuppc/tests/testdriver.sh | 27 ++++++++++++++++++++ 9 files changed, 158 insertions(+) create mode 100644 plat/qemuppc/tests/_dummy.c create mode 100644 plat/qemuppc/tests/build.lua create mode 100644 plat/qemuppc/tests/div.c create mode 100644 plat/qemuppc/tests/lib/build.lua create mode 100644 plat/qemuppc/tests/lib/test.c create mode 100644 plat/qemuppc/tests/lib/test.h create mode 100755 plat/qemuppc/tests/testdriver.sh diff --git a/build.lua b/build.lua index fd8582fd9..cc550cb9e 100644 --- a/build.lua +++ b/build.lua @@ -13,11 +13,18 @@ vars.plats = { "pc86", "rpi", } +vars.plats_with_tests = { + "qemuppc", +} local plat_packages = {} +local test_packages = {} for _, p in ipairs(vars.plats) do plat_packages[#plat_packages+1] = "plat/"..p.."+pkg" end +for _, p in ipairs(vars.plats_with_tests) do + test_packages[#test_packages+1] = "plat/"..p.."/tests+tests" +end installable { name = "ack", @@ -35,6 +42,9 @@ installable { "util/opt+pkg", "examples+pkg", plat_packages + }, + deps = { + test_packages } } diff --git a/plat/qemuppc/build-pkg.lua b/plat/qemuppc/build-pkg.lua index e30e83efc..0478bbd4d 100644 --- a/plat/qemuppc/build-pkg.lua +++ b/plat/qemuppc/build-pkg.lua @@ -18,6 +18,7 @@ installable { "+tools", "+libs", "./include+pkg", + "util/amisc+aslod-pkg", ["$(PLATIND)/qemuppc/boot.o"] = "+boot", ["$(PLATIND)/qemuppc/libsys.a"] = "./libsys+lib", } diff --git a/plat/qemuppc/tests/_dummy.c b/plat/qemuppc/tests/_dummy.c new file mode 100644 index 000000000..4a56d8238 --- /dev/null +++ b/plat/qemuppc/tests/_dummy.c @@ -0,0 +1,8 @@ +#include "test.h" + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(0 == 0); + finished(); +} \ No newline at end of file diff --git a/plat/qemuppc/tests/build.lua b/plat/qemuppc/tests/build.lua new file mode 100644 index 000000000..ec4cbf610 --- /dev/null +++ b/plat/qemuppc/tests/build.lua @@ -0,0 +1,44 @@ +include("plat/build.lua") + +local qemu = "qemu-system-ppc" +local tests = {} + +if os.execute("which "..qemu.." > /dev/null") ~= 0 then + print("warning: skipping tests which require ", qemu) +else + local testcases = filenamesof("./*.c", "./*.s", "./*.e") + + for _, f in ipairs(testcases) do + local fs = replace(basename(f), "%..$", "") + + local bin = ackprogram { + name = fs.."_bin", + srcs = { f }, + deps = { "plat/qemuppc/tests/lib+lib" }, + vars = { + plat = "qemuppc", + lang = "e", + } + } + + tests[#tests+1] = normalrule { + name = fs, + outleaves = { "stamp" }, + ins = { + bin, + "./testdriver.sh" + }, + commands = { + "%{ins[2]} "..qemu.." %{ins[1]} 5", + "touch %{outs}" + } + } + end +end + +normalrule { + name = "tests", + outleaves = { "stamp" }, + ins = tests, + commands = { "touch %{outs}" } +} \ No newline at end of file diff --git a/plat/qemuppc/tests/div.c b/plat/qemuppc/tests/div.c new file mode 100644 index 000000000..dfa96ae16 --- /dev/null +++ b/plat/qemuppc/tests/div.c @@ -0,0 +1,17 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int three = 3; +int two = 2; +int one = 1; +int zero = 0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((three/two) == 1); + ASSERT((-three/two) == -1); + ASSERT((-three/-two) == 1); + ASSERT((three/-two) == -1); + finished(); +} \ No newline at end of file diff --git a/plat/qemuppc/tests/lib/build.lua b/plat/qemuppc/tests/lib/build.lua new file mode 100644 index 000000000..cb6b5cbea --- /dev/null +++ b/plat/qemuppc/tests/lib/build.lua @@ -0,0 +1,8 @@ +include("plat/build.lua") + +acklibrary { + name = "lib", + srcs = { "./test.c" }, + hdrs = { "./test.h" }, + vars = { plat = "qemuppc" } +} diff --git a/plat/qemuppc/tests/lib/test.c b/plat/qemuppc/tests/lib/test.c new file mode 100644 index 000000000..9da7e8101 --- /dev/null +++ b/plat/qemuppc/tests/lib/test.c @@ -0,0 +1,29 @@ +#include "test.h" + +void finished(void) +{ + static const char s[] = "@@FINISHED\n"; + write(1, s, sizeof(s)); +} + +void writehex(uint32_t code) +{ + char buf[8]; + char* p = &buf[8]; + + do + { + *--p = "0123456789abcdef"[code & 0xf]; + code >>= 4; + } + while (code > 0); + + write(1, p, buf+8-p); +} + +void fail(uint32_t code) +{ + write(1, "@@FAIL ", 7); + writehex(code); + write(1, "\n", 1); +} diff --git a/plat/qemuppc/tests/lib/test.h b/plat/qemuppc/tests/lib/test.h new file mode 100644 index 000000000..96537a2cb --- /dev/null +++ b/plat/qemuppc/tests/lib/test.h @@ -0,0 +1,14 @@ +#ifndef TEST_H +#define TEST_H + +#include +#include + +extern void finished(void); +extern void writehex(uint32_t code); +extern void fail(uint32_t code); + +#define ASSERT(condition) \ + if (!(condition)) fail(__LINE__) + +#endif diff --git a/plat/qemuppc/tests/testdriver.sh b/plat/qemuppc/tests/testdriver.sh new file mode 100755 index 000000000..84abdab1a --- /dev/null +++ b/plat/qemuppc/tests/testdriver.sh @@ -0,0 +1,27 @@ +#!/bin/sh +qemu=$1 +img=$2 +timeout=$3 + +pipe=/tmp/testdriver.$$.pipe +mknod $pipe p +trap "rm $pipe" EXIT + +timeout $timeout $qemu -nographic -kernel $img >$pipe 2>&1 & +pid=$! + +status=0 +while read line < $pipe; do + case "$line" in + *@@FAIL*) + echo $line + status=1 + ;; + + *@@FINISHED*) + kill $pid + ;; + esac +done + +exit $status From e7132183fb97c8012f15b580ae2d8848761c1efb Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 13 Nov 2016 14:04:58 +0100 Subject: [PATCH 177/230] Fix buffer overrun: if LABEL_STARTER is seen but LABEL_TERMINATOR is not, the label parser will keep going forever looking for the end of the label. It now stops at the end of the string. --- mach/proto/top/top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mach/proto/top/top.c b/mach/proto/top/top.c index 178dd450e..5d57fa1de 100644 --- a/mach/proto/top/top.c +++ b/mach/proto/top/top.c @@ -330,7 +330,7 @@ labeldef(ip) int oplen; p = ip->rest_line; - while( *p != LABEL_TERMINATOR) p++; + while(*p && (*p != LABEL_TERMINATOR)) p++; oplen = p - ip->rest_line; if (oplen == 0 || oplen > MAXOPLEN) return; strncpy(ip->op[0],ip->rest_line,oplen); From 0699e7af9793ba9d1427aa1e6273bb624c0cdeaa Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 13 Nov 2016 14:10:44 +0100 Subject: [PATCH 178/230] Attempt to enable the qemuppc tests on Travis. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 408e5d59b..c6568fb11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ addons: apt: packages: - ed + - qemu-system-ppc git: depth: 10 From 1ef4780af49478cac51254c25e74661fc5ab9789 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 13 Nov 2016 14:17:38 +0100 Subject: [PATCH 179/230] Typo fix. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c6568fb11..e63c1225d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ addons: apt: packages: - ed - - qemu-system-ppc + - qemu-system-ppc git: depth: 10 From 91c15c1c63d2a609fede28775c0b45c0aa86a680 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 13 Nov 2016 14:20:14 +0100 Subject: [PATCH 180/230] Precise's qemu package is qemu-system. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e63c1225d..045db0981 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ addons: apt: packages: - ed - - qemu-system-ppc + - qemu-system git: depth: 10 From 408b69b17d7d2e9566f027903f8878a5009344a2 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 13 Nov 2016 20:50:23 +0100 Subject: [PATCH 181/230] aelflod and aslod now default to not showing the memory dump. --- util/amisc/aelflod.1 | 2 +- util/amisc/aelflod.c | 15 ++++++++++----- util/amisc/aslod.1 | 2 +- util/amisc/aslod.c | 15 ++++++++++----- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/util/amisc/aelflod.1 b/util/amisc/aelflod.1 index 6e22d53d2..24001ba2d 100644 --- a/util/amisc/aelflod.1 +++ b/util/amisc/aelflod.1 @@ -2,7 +2,7 @@ .SH NAME aelflod \- ACK ELF loader .SH SYNOPSIS -aelflod [-h] inputfile outputfile +aelflod [-h] [-v] inputfile outputfile .SH DESCRIPTION .I aelflod converts an absolute ack.out file into a simple binary memory diff --git a/util/amisc/aelflod.c b/util/amisc/aelflod.c index 398b223b2..e3692ac01 100644 --- a/util/amisc/aelflod.c +++ b/util/amisc/aelflod.c @@ -1,7 +1,4 @@ /* - * $Source$ - * $State$ - * * Simple tool to produce an utterly basic ELF executable * from an absolute ack.out file. Suitable for operating * systems like Linux. @@ -24,6 +21,7 @@ #include #include #include +#include #include #include #include "out.h" @@ -68,6 +66,8 @@ const char elf_le_ident_string[] = { char hdr[HDR_LENGTH] ; +bool verbose = false; + /* Segment numbers understood by aelflod. */ enum { @@ -299,6 +299,10 @@ int main(int argc, char* argv[]) elfmachine = atoi(&argv[1][2]); break; + case 'v': + verbose = true; + break; + default: syntaxerror: fatal("syntax error --- try -h for help"); @@ -451,8 +455,9 @@ int main(int argc, char* argv[]) /* Summarise what we've done. */ + if (verbose) { - long ss = 0; + uint32_t ss = 0; printf(" address length\n"); printf(" ehdr : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base & ~0x1FFF, codeoffset); printf(" text : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base, outsect[TEXT].os_size); @@ -463,7 +468,7 @@ int main(int argc, char* argv[]) ss += outsect[ROM].os_size; ss += outsect[DATA].os_size; ss += outsect[BSS].os_size; - printf("TOTAL : %08lX\n", ss); + printf("TOTAL : %08"PRIx32"\n", ss); } return 0; diff --git a/util/amisc/aslod.1 b/util/amisc/aslod.1 index 7e291838f..a786b13e6 100644 --- a/util/amisc/aslod.1 +++ b/util/amisc/aslod.1 @@ -2,7 +2,7 @@ .SH NAME aslod \- ACK simple loader .SH SYNOPSIS -aslod [-h] inputfile outputfile +aslod [-h] [-v] inputfile outputfile .SH DESCRIPTION .I aslod converts an absolute ack.out file into a simple binary memory diff --git a/util/amisc/aslod.c b/util/amisc/aslod.c index 307f72cb1..afc8f8c3e 100644 --- a/util/amisc/aslod.c +++ b/util/amisc/aslod.c @@ -14,14 +14,12 @@ * CVS...) * * dtrg, 2006-10-17 - * - * $Source$ - * $State$ */ #include #include #include +#include #include #include #include @@ -53,6 +51,8 @@ FILE* output; /* Output stream */ char hdr[HDR_LENGTH] ; +bool verbose = false; + /* Segment numbers understood by aslod. */ enum { @@ -206,6 +206,10 @@ int main(int argc, char* argv[]) program); exit(0); + case 'v': + verbose = true; + break; + default: syntaxerror: fatal("syntax error --- try -h for help"); @@ -301,8 +305,9 @@ int main(int argc, char* argv[]) /* Summarise what we've done. */ + if (verbose) { - long ss = 0; + uint32_t ss = 0; printf(" base : %08"PRIx32"\n", outsect[TEXT].os_base) ; printf(" text = %08"PRIx32"\n", outsect[TEXT].os_size); printf(" rom = %08"PRIx32"\n", outsect[ROM].os_size); @@ -312,7 +317,7 @@ int main(int argc, char* argv[]) ss += outsect[ROM].os_size; ss += outsect[DATA].os_size; ss += outsect[BSS].os_size; - printf("TOTAL = %08lX\n", ss); + printf("TOTAL = %08"PRIx32"\n", ss); } return 0; From 0289b1004ead089ab2a1ccab33102e61a3fba4b8 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 14 Nov 2016 21:47:49 +0100 Subject: [PATCH 182/230] Allow values left on the stack at the end of the procedure (it's legal!). --- mach/proto/mcg/treebuilder.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index b0ef5ba87..fcd13611c 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1643,7 +1643,8 @@ static void generate_tree(struct basicblock* bb) print_stack(); } - assert(stackptr == 0); + /* Yes, we are allowed to leave stuff on the stack at the end of the procedure. + * It's discarded as part of the function return. */ } void tb_procedure(void) From c6bce0aaee0456a1eee81d7bd9332c1feaaae4dc Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 14 Nov 2016 22:01:25 +0100 Subject: [PATCH 183/230] Add basic integer comparison test. --- plat/qemuppc/tests/intcmp.c | 65 +++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 plat/qemuppc/tests/intcmp.c diff --git a/plat/qemuppc/tests/intcmp.c b/plat/qemuppc/tests/intcmp.c new file mode 100644 index 000000000..dd7f1da75 --- /dev/null +++ b/plat/qemuppc/tests/intcmp.c @@ -0,0 +1,65 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int one = 1; +int zero = 0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(zero == zero); + ASSERT(one != zero); + ASSERT(zero < one); + ASSERT(zero <= one); + ASSERT(zero <= zero); + ASSERT(one > zero); + ASSERT(one >= zero); + ASSERT(one >= one); + + ASSERT(zero == 0); + ASSERT(one != 0); + ASSERT(zero < 1); + ASSERT(zero <= 1); + ASSERT(zero <= 0); + ASSERT(one > 0); + ASSERT(one >= 0); + ASSERT(one >= 1); + + ASSERT(0 == zero); + ASSERT(1 != zero); + ASSERT(0 < one); + ASSERT(0 <= one); + ASSERT(0 <= zero); + ASSERT(1 > zero); + ASSERT(1 >= zero); + ASSERT(1 >= one); + + ASSERT((unsigned int)zero == (unsigned int)zero); + ASSERT((unsigned int)one != (unsigned int)zero); + ASSERT((unsigned int)zero < (unsigned int)one); + ASSERT((unsigned int)zero <= (unsigned int)one); + ASSERT((unsigned int)zero <= (unsigned int)zero); + ASSERT((unsigned int)one > (unsigned int)zero); + ASSERT((unsigned int)one >= (unsigned int)zero); + ASSERT((unsigned int)one >= (unsigned int)one); + + ASSERT((unsigned int)zero == (unsigned int)0); + ASSERT((unsigned int)one != (unsigned int)0); + ASSERT((unsigned int)zero < (unsigned int)1); + ASSERT((unsigned int)zero <= (unsigned int)1); + ASSERT((unsigned int)zero <= (unsigned int)0); + ASSERT((unsigned int)one > (unsigned int)0); + ASSERT((unsigned int)one >= (unsigned int)0); + ASSERT((unsigned int)one >= (unsigned int)1); + + ASSERT((unsigned int)0 == (unsigned int)zero); + ASSERT((unsigned int)1 != (unsigned int)zero); + ASSERT((unsigned int)0 < (unsigned int)one); + ASSERT((unsigned int)0 <= (unsigned int)one); + ASSERT((unsigned int)0 <= (unsigned int)zero); + ASSERT((unsigned int)1 > (unsigned int)zero); + ASSERT((unsigned int)1 >= (unsigned int)zero); + ASSERT((unsigned int)1 >= (unsigned int)one); + + finished(); +} \ No newline at end of file From 5e8babf098ec00a6bafe9a0fd5f9cfb53746af56 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 14 Nov 2016 22:12:13 +0100 Subject: [PATCH 184/230] Add a basic integer shift test. --- plat/qemuppc/tests/intshift.c | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 plat/qemuppc/tests/intshift.c diff --git a/plat/qemuppc/tests/intshift.c b/plat/qemuppc/tests/intshift.c new file mode 100644 index 000000000..dd280142c --- /dev/null +++ b/plat/qemuppc/tests/intshift.c @@ -0,0 +1,52 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int one = 1; +int zero = 0; +int minusone = -1; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((one <>zero) == 1); + ASSERT((one >>one) == 0); + ASSERT((minusone>>zero) == -1); + ASSERT((minusone>>one) == -1); + + ASSERT(((unsigned int)one >>(unsigned int)zero) == 1); + ASSERT(((unsigned int)one >>(unsigned int)one) == 0); + ASSERT(((unsigned int)minusone>>(unsigned int)zero) == 0xffffffff); + ASSERT(((unsigned int)minusone>>(unsigned int)one) == 0x7fffffff); + + ASSERT((one <<0) == 1); + ASSERT((one <<1) == 2); + ASSERT((minusone<<0) == -1); + ASSERT((minusone<<1) == -2); + + ASSERT(((unsigned int)one <<(unsigned int)0) == 1); + ASSERT(((unsigned int)one <<(unsigned int)1) == 2); + ASSERT(((unsigned int)minusone<<(unsigned int)0) == -1); + ASSERT(((unsigned int)minusone<<(unsigned int)1) == -2); + + ASSERT((one >>0) == 1); + ASSERT((one >>1) == 0); + ASSERT((minusone>>0) == -1); + ASSERT((minusone>>1) == -1); + + ASSERT(((unsigned int)one >>(unsigned int)0) == 1); + ASSERT(((unsigned int)one >>(unsigned int)1) == 0); + ASSERT(((unsigned int)minusone>>(unsigned int)0) == 0xffffffff); + ASSERT(((unsigned int)minusone>>(unsigned int)1) == 0x7fffffff); + + finished(); +} \ No newline at end of file From cc686ded62b4e5b6731d944cda0c0f2974776d5f Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 15 Nov 2016 20:25:11 +0100 Subject: [PATCH 185/230] Get subtractions the right way round. --- mach/powerpc/mcg/table | 2 +- plat/qemuppc/tests/intsub.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 plat/qemuppc/tests/intsub.c diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index a6f416b65..03daee94e 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -609,7 +609,7 @@ PATTERNS ALUCC(ADD.I, "addi") out:(int)reg = SUB.I(left:(int)reg, right:(int)reg) - emit "subf %out, %left, %right" + emit "subf %out, %right, %left" cost 4; out:(int)reg = SUB.I(left:(int)reg, right:CONST.I) diff --git a/plat/qemuppc/tests/intsub.c b/plat/qemuppc/tests/intsub.c new file mode 100644 index 000000000..72ba0ff08 --- /dev/null +++ b/plat/qemuppc/tests/intsub.c @@ -0,0 +1,31 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int two = 2; +int one = 1; +int zero = 0; +int minusone = -1; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((two - one) == 1); + ASSERT((one - two) == -1); + + ASSERT((two - 1) == 1); + ASSERT((one - 2) == -1); + + ASSERT((2 - one) == 1); + ASSERT((1 - two) == -1); + + ASSERT(((unsigned int)two - (unsigned int)one) == 1); + ASSERT(((unsigned int)one - (unsigned int)two) == 0xffffffff); + + ASSERT(((unsigned int)two - (unsigned int)1) == 1); + ASSERT(((unsigned int)one - (unsigned int)2) == 0xffffffff); + + ASSERT(((unsigned int)2 - (unsigned int)one) == 1); + ASSERT(((unsigned int)1 - (unsigned int)two) == 0xffffffff); + + finished(); +} \ No newline at end of file From 86c832ef86f98dff9cad6a86f9e29f4e4d383107 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 15 Nov 2016 21:54:15 +0100 Subject: [PATCH 186/230] Put saved registers in *actually* the write place. I hope. --- mach/powerpc/mcg/platform.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index 36c505a9f..da94083e0 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -34,8 +34,8 @@ void platform_calculate_offsets(void) if (!(hreg->attrs & burm_volatile_ATTR) && ((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR))) { - hreg->offset = current_proc->saved_size; current_proc->saved_size += 8; + hreg->offset = current_proc->saved_size; array_append(&saved_regs, hreg); } } @@ -46,8 +46,8 @@ void platform_calculate_offsets(void) if (!(hreg->attrs & burm_volatile_ATTR) && ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) { - hreg->offset = current_proc->saved_size; current_proc->saved_size += 4; + hreg->offset = current_proc->saved_size; array_append(&saved_regs, hreg); } } @@ -61,7 +61,6 @@ void platform_calculate_offsets(void) struct hop* platform_prologue(void) { int i; - int saved_offset; int spoffset = current_proc->saved_size + current_proc->spills_size + current_proc->locals_size; struct hop* hop = new_hop(current_proc->entry, NULL); @@ -73,7 +72,7 @@ struct hop* platform_prologue(void) current_proc->locals_size); hop_add_insel(hop, "! spills @ fp-%d to fp-%d", -current_proc->fp_to_sb, current_proc->locals_size); - for (i=0; i=0; i--) { struct hreg* hreg = saved_regs.item[i]; hop_add_insel(hop, "! %s @ fp-%d", @@ -87,16 +86,15 @@ struct hop* platform_prologue(void) hop_add_insel(hop, "addi fp, sp, %d", spoffset); /* Saved reg offsets are negative. */ - saved_offset = -(current_proc->locals_size + current_proc->spills_size); for (i=0; iattrs & burm_int_ATTR) hop_add_insel(hop, "stw %H, %d(fp)", - hreg, current_proc->fp_to_rb + saved_offset); + hreg, current_proc->fp_to_rb + hreg->offset); else if (hreg->attrs & burm_float_ATTR) hop_add_insel(hop, "stfs %H, %d(fp)", - hreg, current_proc->fp_to_rb + saved_offset); + hreg, current_proc->fp_to_rb + hreg->offset); } return hop; } @@ -105,17 +103,16 @@ struct hop* platform_epilogue(void) { struct hop* hop = new_hop(current_proc->exit, NULL); int i; - int saved_offset; for (i=0; iattrs & burm_int_ATTR) hop_add_insel(hop, "lwz %H, %d(fp)", - hreg, current_proc->fp_to_rb + saved_offset); + hreg, current_proc->fp_to_rb + hreg->offset); else if (hreg->attrs & burm_float_ATTR) hop_add_insel(hop, "lfs %H, %d(fp)", - hreg, current_proc->fp_to_rb + saved_offset); + hreg, current_proc->fp_to_rb + hreg->offset); } hop_add_insel(hop, "lwz r0, 4(fp)"); From 581fa4a457639b1941c87c737cfa1ce368b2cd59 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 15 Nov 2016 21:55:10 +0100 Subject: [PATCH 187/230] Reenable eviction of corrupted registers, which had been broken by a previous change. Change the register move code to get swaps right, or at least righter. --- mach/proto/mcg/pass_registerallocator.c | 45 ++++++++++++++++++------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index a064adb8e..3e0c9b43b 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -347,13 +347,11 @@ static void add_through_register(struct vreg* vreg, struct hreg* hreg) if (hreg) { - bool unusedin = allocatable_stackable_input(hreg, vreg); - bool unusedout = allocatable_stackable_output(hreg, vreg); + bool unused = allocatable_through(hreg, vreg); struct vreg* inuse = pmap_findleft(current_ins, hreg); struct vreg* outuse = pmap_findleft(current_outs, hreg); - if ((unusedin || (inuse == vreg)) && - (unusedout || (outuse == vreg))) + if (unused || ((inuse == vreg) && (outuse == vreg))) { /* Input and output are either free or already assigned to this * vreg. */ @@ -594,15 +592,14 @@ static int insert_moves(struct basicblock* bb, int index, struct hreg* src = pmap_findright(srcregs, vreg); assert(src != NULL); - if (src != dest) - pmap_add(&copies, src, dest); + pmap_add(&copies, src, dest); } while (copies.count > 0) { struct hreg* src; struct hreg* dest; - struct hreg* temp; + struct hreg* other; struct hop* hop; /* Try and find a destination which isn't a source. */ @@ -627,14 +624,38 @@ static int insert_moves(struct basicblock* bb, int index, } else { - /* There's nowhere to copy to --- the copies that are left form a cycle. - * So we need to swap instead. */ + /* Okay, so there's nowhere to free to move src to. This could be + * because it's already in the right place. */ src = copies.item[0].left; dest = pmap_findleft(&copies, src); - hop = platform_swap(bb, src, dest); - pmap_remove(&copies, src, dest); - pmap_remove(&copies, dest, src); + + if (src == dest) + { + /* This register is already in the right place! */ + + pmap_remove(&copies, src, dest); + continue; + } + else + { + /* It's not in the right place. That means we have a cycle, and need to do + * a swap. */ + + /* (src->dest, other->src) */ + hop = platform_swap(bb, src, dest); + pmap_remove(&copies, src, dest); + + /* Now src and dest are swapped. We know that the old src is in the right place + * and now contains dest. Any copies from the old dest (now containing src) must + * be patched to point at the old src. */ + + for (i=0; ihops, hop, index + inserted); From edfee3357648278f5b476b2fc1d29a2571608940 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 16 Nov 2016 20:50:14 +0100 Subject: [PATCH 188/230] Cleanup; the test driver is now way more robust. --- plat/qemuppc/tests/lib/test.c | 6 ++++-- plat/qemuppc/tests/testdriver.sh | 27 ++++++++++----------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/plat/qemuppc/tests/lib/test.c b/plat/qemuppc/tests/lib/test.c index 9da7e8101..02d98773b 100644 --- a/plat/qemuppc/tests/lib/test.c +++ b/plat/qemuppc/tests/lib/test.c @@ -1,5 +1,7 @@ #include "test.h" +/* No CRT in this file (this includes stdio and stdlib!). */ + void finished(void) { static const char s[] = "@@FINISHED\n"; @@ -9,7 +11,7 @@ void finished(void) void writehex(uint32_t code) { char buf[8]; - char* p = &buf[8]; + char* p = &buf[sizeof(buf)]; do { @@ -18,7 +20,7 @@ void writehex(uint32_t code) } while (code > 0); - write(1, p, buf+8-p); + write(1, p, buf + sizeof(buf) - p); } void fail(uint32_t code) diff --git a/plat/qemuppc/tests/testdriver.sh b/plat/qemuppc/tests/testdriver.sh index 84abdab1a..8cce48d1c 100755 --- a/plat/qemuppc/tests/testdriver.sh +++ b/plat/qemuppc/tests/testdriver.sh @@ -3,25 +3,18 @@ qemu=$1 img=$2 timeout=$3 -pipe=/tmp/testdriver.$$.pipe +pipe=/tmp/$$.testdriver.pipe mknod $pipe p -trap "rm $pipe" EXIT +trap "rm -f $pipe" EXIT -timeout $timeout $qemu -nographic -kernel $img >$pipe 2>&1 & -pid=$! +result=/tmp/$$.testdriver.result +trap "rm -f $result" EXIT -status=0 -while read line < $pipe; do - case "$line" in - *@@FAIL*) - echo $line - status=1 - ;; +pidfile=/tmp/$$.testdriver.pid +trap "rm -f $pidfile" EXIT - *@@FINISHED*) - kill $pid - ;; - esac -done +($qemu -nographic -kernel $img 2>&1 & echo $! > $pidfile ) | tee $result | \ + grep -l @@FINISHED | (read dummy && kill $(cat $pidfile)) -exit $status +grep @@FAIL $result && cat $result && exit 1 +exit 0 \ No newline at end of file From 81bc2c74c51e391461940bf827b4ae70958af84c Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 16 Nov 2016 20:52:15 +0100 Subject: [PATCH 189/230] A bb's regsin are no longer the same as those of its first instruction; occasionally the first hop of a block would try to rearrange its registers (due to evicted throughs), resulting in the phi moves copying values into the wrong registers. --- mach/proto/mcg/basicblock.h | 8 +++----- mach/proto/mcg/pass_registerallocator.c | 25 +++++++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h index 323fa4dd5..362a05f7f 100644 --- a/mach/proto/mcg/basicblock.h +++ b/mach/proto/mcg/basicblock.h @@ -24,11 +24,9 @@ struct basicblock ARRAYOF(struct vreg) liveins; ARRAYOF(struct vreg) liveouts; - /* Register assignments on entry and exit. These are *pointers* (because - * they just point to the regsin/regsout of the first and last hop - * respectively). */ - register_assignment_t* regsin; - register_assignment_t* regsout; + /* Register assignments on entry and exit. */ + register_assignment_t regsin; + register_assignment_t* regsout; /* points at regsout of the last insn. */ bool is_fake : 1; bool is_root : 1; diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 3e0c9b43b..a5436bc73 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -54,7 +54,6 @@ static void wire_up_blocks_ins_outs(void) { struct basicblock* bb = dominance.preorder.item[i]; assert(bb->hops.count >= 1); - bb->regsin = &bb->hops.item[0]->regsin; bb->regsout = &bb->hops.item[bb->hops.count-1]->regsout; } } @@ -462,7 +461,7 @@ static void assign_hregs_to_vregs(void) for (i=0; iregsin; + register_assignment_t* old = &bb->regsin; tracef('R', "R: considering block %s\n", bb->name); @@ -568,8 +567,7 @@ static void assign_hregs_to_vregs(void) } tracef('R', "]\n"); - if (j > 0) - j += insert_moves(bb, j, old, in); + j += insert_moves(bb, j, old, in); old = out; } @@ -692,15 +690,16 @@ static void insert_phi_copies(void) { struct vreg* vreg = bb->phis.item[k].left; struct phi* phi = bb->phis.item[k].right; - struct hreg* dest = pmap_findright(bb->regsin, vreg); + struct hreg* src = pmap_findright(prevbb->regsout, phi->ir->result); + struct hreg* dest = pmap_findright(&bb->regsin, vreg); if ((phi->prev == prevbb) && dest) { /* We inserted critical edges to guarantee this. */ assert(prevbb->nexts.count == 1); - tracef('R', "R: map %%%d -> %%%d (%s)\n", - phi->ir->result->id, + tracef('R', "R: phi map %%%d (%s) -> %%%d (%s)\n", + phi->ir->result->id, src->id, vreg->id, dest->id); pmap_put(&destregs, dest, phi->ir->result); @@ -709,12 +708,18 @@ static void insert_phi_copies(void) /* Add any non-phi inputs. */ - for (k=0; kregsin->count; k++) + for (k=0; kregsin.count; k++) { - struct hreg* hreg = bb->regsin->item[k].left; - struct vreg* vreg = bb->regsin->item[k].right; + struct hreg*hreg = bb->regsin.item[k].left; + struct vreg* vreg = bb->regsin.item[k].right; + struct hreg* src = pmap_findright(prevbb->regsout, vreg); if (!pmap_findleft(&bb->phis, vreg)) + { + tracef('R', "R: input map %%%d (%s) -> (%s)\n", + vreg->id, src->id, hreg->id); + pmap_add(&destregs, hreg, vreg); + } } /* The last instruction of a block should be the jump that sends us From 71e6ca26d5515fff3aca8664c01b578020e64931 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 16 Nov 2016 20:56:45 +0100 Subject: [PATCH 190/230] Add another test. --- plat/qemuppc/tests/intadd.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 plat/qemuppc/tests/intadd.c diff --git a/plat/qemuppc/tests/intadd.c b/plat/qemuppc/tests/intadd.c new file mode 100644 index 000000000..8e4868a62 --- /dev/null +++ b/plat/qemuppc/tests/intadd.c @@ -0,0 +1,31 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int two = 2; +int one = 1; +int zero = 0; +int minusone = -1; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((two + one) == 3); + ASSERT((two + minusone) == 1); + + ASSERT((two + 1) == 3); + ASSERT((two + -1) == 1); + + ASSERT((1 + two) == 3); + ASSERT((-1 + two) == 1); + + ASSERT(((unsigned int)two + (unsigned int)one) == 3); + ASSERT(((unsigned int)two + (unsigned int)minusone) == 1); + + ASSERT(((unsigned int)two + (unsigned int) 1) == 3); + ASSERT(((unsigned int)two + (unsigned int)-1) == 1); + + ASSERT(((unsigned int)1 + (unsigned int)two) == 3); + ASSERT(((unsigned int)-1 + (unsigned int)two) == 1); + + finished(); +} \ No newline at end of file From c25ad82a89f878d81ae8ad89d75aa796ad804408 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 16 Nov 2016 21:08:03 +0100 Subject: [PATCH 191/230] Tests can now specify (via a hacky filename suffix) which runtime they want. --- plat/qemuppc/tests/build.lua | 7 ++++++- plat/qemuppc/tests/{intadd.c => intadd_e.c} | 0 plat/qemuppc/tests/{intcmp.c => intcmp_e.c} | 0 plat/qemuppc/tests/{div.c => intdiv_e.c} | 0 plat/qemuppc/tests/{intshift.c => intshift_e.c} | 0 plat/qemuppc/tests/{intsub.c => intsub_e.c} | 0 plat/qemuppc/tests/lib/test.c | 2 +- 7 files changed, 7 insertions(+), 2 deletions(-) rename plat/qemuppc/tests/{intadd.c => intadd_e.c} (100%) rename plat/qemuppc/tests/{intcmp.c => intcmp_e.c} (100%) rename plat/qemuppc/tests/{div.c => intdiv_e.c} (100%) rename plat/qemuppc/tests/{intshift.c => intshift_e.c} (100%) rename plat/qemuppc/tests/{intsub.c => intsub_e.c} (100%) diff --git a/plat/qemuppc/tests/build.lua b/plat/qemuppc/tests/build.lua index ec4cbf610..024961fda 100644 --- a/plat/qemuppc/tests/build.lua +++ b/plat/qemuppc/tests/build.lua @@ -10,6 +10,10 @@ else for _, f in ipairs(testcases) do local fs = replace(basename(f), "%..$", "") + local _, _, lang = fs:find("_(.)$") + if not lang then + lang = "e" + end local bin = ackprogram { name = fs.."_bin", @@ -17,7 +21,8 @@ else deps = { "plat/qemuppc/tests/lib+lib" }, vars = { plat = "qemuppc", - lang = "e", + lang = lang, + ackcflags = "-O0" } } diff --git a/plat/qemuppc/tests/intadd.c b/plat/qemuppc/tests/intadd_e.c similarity index 100% rename from plat/qemuppc/tests/intadd.c rename to plat/qemuppc/tests/intadd_e.c diff --git a/plat/qemuppc/tests/intcmp.c b/plat/qemuppc/tests/intcmp_e.c similarity index 100% rename from plat/qemuppc/tests/intcmp.c rename to plat/qemuppc/tests/intcmp_e.c diff --git a/plat/qemuppc/tests/div.c b/plat/qemuppc/tests/intdiv_e.c similarity index 100% rename from plat/qemuppc/tests/div.c rename to plat/qemuppc/tests/intdiv_e.c diff --git a/plat/qemuppc/tests/intshift.c b/plat/qemuppc/tests/intshift_e.c similarity index 100% rename from plat/qemuppc/tests/intshift.c rename to plat/qemuppc/tests/intshift_e.c diff --git a/plat/qemuppc/tests/intsub.c b/plat/qemuppc/tests/intsub_e.c similarity index 100% rename from plat/qemuppc/tests/intsub.c rename to plat/qemuppc/tests/intsub_e.c diff --git a/plat/qemuppc/tests/lib/test.c b/plat/qemuppc/tests/lib/test.c index 02d98773b..33d72f3ce 100644 --- a/plat/qemuppc/tests/lib/test.c +++ b/plat/qemuppc/tests/lib/test.c @@ -25,7 +25,7 @@ void writehex(uint32_t code) void fail(uint32_t code) { - write(1, "@@FAIL ", 7); + write(1, "@@FAIL on line 0x", 7); writehex(code); write(1, "\n", 1); } From 745eb8f17b23711483c2058c3fdc3370944a5886 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 16 Nov 2016 21:13:00 +0100 Subject: [PATCH 192/230] Now _errsym and _erlsym are defined in the standard library, don't define them in the program. --- lang/basic/src/gencode.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lang/basic/src/gencode.c b/lang/basic/src/gencode.c index 8c7a50e95..8fb611dc0 100644 --- a/lang/basic/src/gencode.c +++ b/lang/basic/src/gencode.c @@ -617,11 +617,7 @@ prologcode() C_df_dnam("_iomode"); C_rom_scon("O",(arith)2); C_exa_dnam("_errsym"); - C_df_dnam("_errsym"); - C_bss_cst((arith)BEMINTSIZE,(arith)0,1); C_exa_dnam("_erlsym"); - C_df_dnam("_erlsym"); - C_bss_cst((arith)BEMINTSIZE,(arith)0,1); } From 43439c6d0c121751473503b8e70464e869cc39aa Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 17 Nov 2016 22:04:32 +0100 Subject: [PATCH 193/230] Remember to push the result of lor onto the stack. --- mach/proto/mcg/treebuilder.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index fcd13611c..01e486500 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1261,20 +1261,24 @@ static void insn_ivalue(int opcode, arith value) switch (value) { case 0: - appendir( - new_ir1( - IR_FPTOLB, EM_pointersize, - new_ir0( - IR_GETFP, EM_pointersize + push( + appendir( + new_ir1( + IR_FPTOLB, EM_pointersize, + new_ir0( + IR_GETFP, EM_pointersize + ) ) ) ); break; case 1: - appendir( - new_ir0( - IR_GETSP, EM_pointersize + push( + appendir( + new_ir0( + IR_GETSP, EM_pointersize + ) ) ); break; From a4616b71241060d1e6c0c59e0a05b27f762f0d32 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 17 Nov 2016 22:04:50 +0100 Subject: [PATCH 194/230] Betterer timeout handling. --- plat/qemuppc/tests/testdriver.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plat/qemuppc/tests/testdriver.sh b/plat/qemuppc/tests/testdriver.sh index 8cce48d1c..3424e9626 100755 --- a/plat/qemuppc/tests/testdriver.sh +++ b/plat/qemuppc/tests/testdriver.sh @@ -13,8 +13,10 @@ trap "rm -f $result" EXIT pidfile=/tmp/$$.testdriver.pid trap "rm -f $pidfile" EXIT -($qemu -nographic -kernel $img 2>&1 & echo $! > $pidfile ) | tee $result | \ - grep -l @@FINISHED | (read dummy && kill $(cat $pidfile)) +( $qemu -nographic -kernel $img 2>&1 & echo $! > $pidfile ) \ + | tee $result \ + | ( timeout $timeout grep -l -q @@FINISHED ; echo ) \ + | ( read dummy && kill $(cat $pidfile) ) -grep @@FAIL $result && cat $result && exit 1 +( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1 exit 0 \ No newline at end of file From 5208e5f7516ab9ac7e5891eae6960faf6c2e05c2 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 19 Nov 2016 10:42:22 +0100 Subject: [PATCH 195/230] Yet another OB1 stack format fix. --- mach/powerpc/mcg/platform.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index da94083e0..65b158cac 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -34,8 +34,8 @@ void platform_calculate_offsets(void) if (!(hreg->attrs & burm_volatile_ATTR) && ((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR))) { - current_proc->saved_size += 8; hreg->offset = current_proc->saved_size; + current_proc->saved_size += 8; array_append(&saved_regs, hreg); } } @@ -46,8 +46,8 @@ void platform_calculate_offsets(void) if (!(hreg->attrs & burm_volatile_ATTR) && ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) { - current_proc->saved_size += 4; hreg->offset = current_proc->saved_size; + current_proc->saved_size += 4; array_append(&saved_regs, hreg); } } @@ -65,6 +65,9 @@ struct hop* platform_prologue(void) current_proc->locals_size; struct hop* hop = new_hop(current_proc->entry, NULL); + hop_add_insel(hop, "! locals_size = %d", current_proc->locals_size); + hop_add_insel(hop, "! spills_size = %d", current_proc->spills_size); + hop_add_insel(hop, "! saved_size = %d", current_proc->saved_size); hop_add_insel(hop, "! params @ fp+%d", current_proc->fp_to_ab); hop_add_insel(hop, "! lr @ fp+4"); hop_add_insel(hop, "! fp @ fp+0"); From d31bc6a3f90429d94536174143645fc87c3fc739 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 19 Nov 2016 10:55:41 +0100 Subject: [PATCH 196/230] Made csa and csb work with mcg; adjust the libem functions and the corresponding invocation in the ncg table so the same helpers can be used for both mcg and ncg. Add a new IR opcode, FARJUMP, which jumps to a helper function but saves volatile registers. --- mach/powerpc/libem/csa.s | 7 +++++-- mach/powerpc/libem/csb.s | 7 +++++-- mach/powerpc/mcg/table | 5 +++++ mach/powerpc/ncg/table | 4 ++-- mach/proto/mcg/treebuilder.c | 7 +++---- plat/qemuppc/descr | 3 +-- plat/qemuppc/tests/_dummy.c | 2 +- plat/qemuppc/tests/csa_e.c | 26 ++++++++++++++++++++++++++ plat/qemuppc/tests/csb_e.c | 26 ++++++++++++++++++++++++++ util/mcgg/ir.dat | 1 + 10 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 plat/qemuppc/tests/csa_e.c create mode 100644 plat/qemuppc/tests/csb_e.c diff --git a/mach/powerpc/libem/csa.s b/mach/powerpc/libem/csa.s index 64954ff4e..88e6e176a 100644 --- a/mach/powerpc/libem/csa.s +++ b/mach/powerpc/libem/csa.s @@ -12,11 +12,14 @@ ! address and jumps to it. ! traps if resulting address is zero ! -! On entry: r3 = address of CSA table -! r4 = value +! Stack: ( value tableaddr -- ) .define .csa .csa: + lwz r3, 0(sp) + lwz r4, 4(sp) + addi sp, sp, 8 + lwz r5, 0(r3) ! load default mtspr ctr, r5 diff --git a/mach/powerpc/libem/csb.s b/mach/powerpc/libem/csb.s index cbedc8c11..a8df85d7f 100644 --- a/mach/powerpc/libem/csb.s +++ b/mach/powerpc/libem/csb.s @@ -12,11 +12,14 @@ ! address and jumps to it. ! traps if resulting address is zero ! -! On entry: r3 = address of CSB table -! r4 = value +! Stack: ( value tableaddr -- ) .define .csb .csb: + lwz r3, 0(sp) + lwz r4, 4(sp) + addi sp, sp, 8 + lwz r5, 0(r3) ! load default mtspr ctr, r5 diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 03daee94e..79ac7c577 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -466,6 +466,11 @@ PATTERNS emit "b $addr" cost 4; + FARJUMP(addr:LABEL.I) + with corrupted(volatile) + emit "b $addr" + cost 4; + JUMP(dest:(int)reg) emit "mtspr ctr, %dest" emit "bcctrl 20, 0, 0" diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index ed107aceb..6f10c7d4c 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -1898,12 +1898,12 @@ PATTERNS addi SP, SP, {CONST, 12} pat csa /* Array-lookup switch */ - with GPR3 GPR4 STACK + with STACK gen b {LABEL, ".csa"} pat csb /* Table-lookup switch */ - with GPR3 GPR4 STACK + with STACK gen b {LABEL, ".csb"} diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 01e486500..66347447f 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1130,9 +1130,8 @@ static void insn_ivalue(int opcode, arith value) case op_csa: case op_csb: { - const char* helper = aprintf(".%s%d", - (opcode == op_csa) ? "csa" : "csb", - value); + const char* helper = aprintf(".%s", + (opcode == op_csa) ? "csa" : "csb"); struct ir* descriptor = pop(EM_pointersize); if (descriptor->opcode != IR_LABEL) @@ -1143,7 +1142,7 @@ static void insn_ivalue(int opcode, arith value) materialise_stack(); appendir( new_ir2( - IR_JUMP, 0, + IR_FARJUMP, 0, new_labelir(helper), extract_block_refs(bb_get(descriptor->u.lvalue)) ) diff --git a/plat/qemuppc/descr b/plat/qemuppc/descr index f28e7482d..c0bc1eab0 100644 --- a/plat/qemuppc/descr +++ b/plat/qemuppc/descr @@ -33,8 +33,7 @@ var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi name be from .m.g to .s - # Change this back to ncg to revert to the old code generator - program {EM}/lib/ack/{PLATFORM}/ncg + program {EM}/lib/ack/{PLATFORM}/mcg mapflag -gdb GF=-gdb args {GF?} < stdout diff --git a/plat/qemuppc/tests/_dummy.c b/plat/qemuppc/tests/_dummy.c index 4a56d8238..48104b5aa 100644 --- a/plat/qemuppc/tests/_dummy.c +++ b/plat/qemuppc/tests/_dummy.c @@ -5,4 +5,4 @@ void _m_a_i_n(void) { ASSERT(0 == 0); finished(); -} \ No newline at end of file +} diff --git a/plat/qemuppc/tests/csa_e.c b/plat/qemuppc/tests/csa_e.c new file mode 100644 index 000000000..355b75ee7 --- /dev/null +++ b/plat/qemuppc/tests/csa_e.c @@ -0,0 +1,26 @@ +#include "test.h" + +int csa(int i) +{ + switch (i) + { + case 2: return 2; + case 3: return 3; + case 4: return 4; + default: return 0; + } +} + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(csa(0) == 0); + ASSERT(csa(1) == 0); + ASSERT(csa(2) == 2); + ASSERT(csa(3) == 3); + ASSERT(csa(4) == 4); + ASSERT(csa(5) == 0); + ASSERT(csa(6) == 0); + + finished(); +} \ No newline at end of file diff --git a/plat/qemuppc/tests/csb_e.c b/plat/qemuppc/tests/csb_e.c new file mode 100644 index 000000000..c86d31fa6 --- /dev/null +++ b/plat/qemuppc/tests/csb_e.c @@ -0,0 +1,26 @@ +#include "test.h" + +int csa(int i) +{ + switch (i) + { + case 200: return 200; + case 300: return 300; + case 400: return 400; + default: return 0; + } +} + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(csa(0) == 0); + ASSERT(csa(100) == 0); + ASSERT(csa(200) == 200); + ASSERT(csa(300) == 300); + ASSERT(csa(400) == 400); + ASSERT(csa(500) == 0); + ASSERT(csa(600) == 0); + + finished(); +} \ No newline at end of file diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 1db593efc..b34f37fbb 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -103,6 +103,7 @@ S ?=i. SETRET # Flow control --- these never return V .=i. JUMP +V .=i. FARJUMP V .=i. CJUMPEQ V .=i. CJUMPLT V .=i. CJUMPLE From db3564f35ab4d3f4dbdbb1b13bc758ba22644487 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 19 Nov 2016 11:09:07 +0100 Subject: [PATCH 197/230] Use .hol0 as an additional name for hol0; mcg requires it. --- plat/linux/libsys/_hol0.s | 9 +++++---- plat/qemuppc/libsys/_hol0.s | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/plat/linux/libsys/_hol0.s b/plat/linux/libsys/_hol0.s index fcb58727b..d3d16db72 100644 --- a/plat/linux/libsys/_hol0.s +++ b/plat/linux/libsys/_hol0.s @@ -10,11 +10,12 @@ .sect .data .sect .bss -.sect .text - -! ! This data block is used to store information about the current line number ! and file. .define hol0 -.comm hol0, 8 +.define .hol0 +.sect .bss +hol0: +.hol0: + .space 8 diff --git a/plat/qemuppc/libsys/_hol0.s b/plat/qemuppc/libsys/_hol0.s index fcb58727b..d3d16db72 100644 --- a/plat/qemuppc/libsys/_hol0.s +++ b/plat/qemuppc/libsys/_hol0.s @@ -10,11 +10,12 @@ .sect .data .sect .bss -.sect .text - -! ! This data block is used to store information about the current line number ! and file. .define hol0 -.comm hol0, 8 +.define .hol0 +.sect .bss +hol0: +.hol0: + .space 8 From cc660b230fd4deab49fac4dbe3f95ca78cc118b7 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 19 Nov 2016 11:39:13 +0100 Subject: [PATCH 198/230] Floats and doubles are now written out correctly. --- mach/proto/mcg/data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index cbaa4c3eb..13352ed37 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -85,7 +85,7 @@ void data_float(const char* data, size_t size, bool is_ro) for (i=1; i Date: Sat, 19 Nov 2016 11:42:30 +0100 Subject: [PATCH 199/230] cif8 and cuf8 work now. More tests. --- mach/powerpc/mcg/table | 14 ++++++++++---- plat/qemuppc/tests/cif8_e.c | 20 ++++++++++++++++++++ plat/qemuppc/tests/cuf8_e.c | 16 ++++++++++++++++ plat/qemuppc/tests/doublecmp_e.c | 20 ++++++++++++++++++++ 4 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 plat/qemuppc/tests/cif8_e.c create mode 100644 plat/qemuppc/tests/cuf8_e.c create mode 100644 plat/qemuppc/tests/doublecmp_e.c diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 79ac7c577..b6bc0ac48 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -407,9 +407,12 @@ PATTERNS emit "bl .fromf2l" cost 4; - out:(dret)reg = FROMSI.D(in:(iret)reg) + out:(double)reg = FROMSI.D(in:(int)reg) with corrupted(volatile) - emit "bl .fromsi2d" + emit "stwu %in, -4(sp)" + emit "bl .cif8" + emit "lfd %out, 0(sp)" + emit "addi sp, sp, 8" cost 4; out:(fret)reg = FROMUI.F(in:(iret)reg) @@ -417,9 +420,12 @@ PATTERNS emit "bl .fromui2f" cost 4; - out:(dret)reg = FROMUI.D(in:(iret)reg) + out:(double)reg = FROMUI.D(in:(int)reg) with corrupted(volatile) - emit "bl .fromui2d" + emit "stwu %in, -4(sp)" + emit "bl .cuf8" + emit "lfd %out, 0(sp)" + emit "addi sp, sp, 8" cost 4; out:(lret)reg = FROMIPAIR.L(in1:(int)reg, in2:(int)reg) diff --git a/plat/qemuppc/tests/cif8_e.c b/plat/qemuppc/tests/cif8_e.c new file mode 100644 index 000000000..e81c2f7c2 --- /dev/null +++ b/plat/qemuppc/tests/cif8_e.c @@ -0,0 +1,20 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int one = 1; +int zero = 0; +int minusone = -1; +int big = 0x7fffffff; +int minusbig = -0x8000000; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((double)zero == 0.0); + ASSERT((double)one == 1.0); + ASSERT((double)minusone == -1.0); + ASSERT((double)big == 2147483647.0); + /* ASSERT((double)minusbig == -2147483648.0); FIXME: fails for now */ + + finished(); +} \ No newline at end of file diff --git a/plat/qemuppc/tests/cuf8_e.c b/plat/qemuppc/tests/cuf8_e.c new file mode 100644 index 000000000..a3517b24c --- /dev/null +++ b/plat/qemuppc/tests/cuf8_e.c @@ -0,0 +1,16 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +unsigned int one_u = 1; +unsigned int zero_u = 0; +unsigned int big_u = 0xffffffff; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((double)zero_u == 0.0); + ASSERT((double)one_u == 1.0); + ASSERT((double)big_u == 4294967295.0); + + finished(); +} \ No newline at end of file diff --git a/plat/qemuppc/tests/doublecmp_e.c b/plat/qemuppc/tests/doublecmp_e.c new file mode 100644 index 000000000..f6c1582dc --- /dev/null +++ b/plat/qemuppc/tests/doublecmp_e.c @@ -0,0 +1,20 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +double one = 1.0; +double zero = 0.0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT(zero == zero); + ASSERT(one != zero); + ASSERT(zero < one); + ASSERT(zero <= one); + ASSERT(zero <= zero); + ASSERT(one > zero); + ASSERT(one >= zero); + ASSERT(one >= one); + + finished(); +} \ No newline at end of file From 5423a175c683a0ba0c68caf12feeb6ad94905386 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 10:00:59 +0100 Subject: [PATCH 200/230] Install openbios on Travis (needed by qemu-system-ppc). --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 045db0981..77146f1b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ addons: packages: - ed - qemu-system + - openbios-ppc git: depth: 10 From 3f45a7d6333fb2b31ebaffc2e09f8ee3128f7bc0 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 10:09:58 +0100 Subject: [PATCH 201/230] Need sudo to install openbios-ppc. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 77146f1b3..8ff3af1bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ addons: git: depth: 10 +sudo: required language: c script: - make PREFIX=/tmp/acki From 84c7b6ba90aead85dadc8772e4e557702bd8a178 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 10:36:30 +0100 Subject: [PATCH 202/230] No, sudo doesn't get openbios-ppc installed. I added a whitelisting request: https://github.com/travis-ci/apt-package-whitelist/issues/3745 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8ff3af1bc..77146f1b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,6 @@ addons: git: depth: 10 -sudo: required language: c script: - make PREFIX=/tmp/acki From 132baac78a9c92694bd55790f0cfb7998ad590ab Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 10:46:53 +0100 Subject: [PATCH 203/230] Add some more tests. --- plat/qemuppc/tests/intdiv_e.c | 19 +++++++++++++++---- plat/qemuppc/tests/intrem_e.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 plat/qemuppc/tests/intrem_e.c diff --git a/plat/qemuppc/tests/intdiv_e.c b/plat/qemuppc/tests/intdiv_e.c index dfa96ae16..c90964ced 100644 --- a/plat/qemuppc/tests/intdiv_e.c +++ b/plat/qemuppc/tests/intdiv_e.c @@ -9,9 +9,20 @@ int zero = 0; /* Bypasses the CRT, so there's no stdio or BSS initialisation. */ void _m_a_i_n(void) { - ASSERT((three/two) == 1); - ASSERT((-three/two) == -1); - ASSERT((-three/-two) == 1); - ASSERT((three/-two) == -1); + ASSERT((three / two) == 1); + ASSERT((-three / two) == -1); + ASSERT((-three / -two) == 1); + ASSERT((three / -two) == -1); + + ASSERT((three / 2) == 1); + ASSERT((-three / 2) == -1); + ASSERT((-three / -2) == 1); + ASSERT((three / -2) == -1); + + ASSERT((3 / two) == 1); + ASSERT((-3 / two) == -1); + ASSERT((-3 / -two) == 1); + ASSERT((3 / -two) == -1); + finished(); } \ No newline at end of file diff --git a/plat/qemuppc/tests/intrem_e.c b/plat/qemuppc/tests/intrem_e.c new file mode 100644 index 000000000..40f68d654 --- /dev/null +++ b/plat/qemuppc/tests/intrem_e.c @@ -0,0 +1,28 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +int three = 3; +int two = 2; +int one = 1; +int zero = 0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((three % two) == 1); + ASSERT((-three % two) == -1); + ASSERT((-three % -two) == -1); + ASSERT((three % -two) == 1); + + ASSERT((three % 2) == 1); + ASSERT((-three % 2) == -1); + ASSERT((-three % -2) == -1); + ASSERT((three % -2) == 1); + + ASSERT((3 % two) == 1); + ASSERT((-3 % two) == -1); + ASSERT((-3 % -two) == -1); + ASSERT((3 % -two) == 1); + + finished(); +} \ No newline at end of file From d5328492d7d8637bface29b5c7548b8103d4befc Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 11:27:40 +0100 Subject: [PATCH 204/230] Better handling of float conversions; more tests; converting to unsigned ints works now. --- mach/powerpc/mcg/table | 24 +++++++++++++++---- mach/proto/mcg/treebuilder.c | 6 ++--- plat/qemuppc/tests/from_d_to_si_e.c | 20 ++++++++++++++++ plat/qemuppc/tests/from_d_to_ui_e.c | 16 +++++++++++++ .../tests/{cif8_e.c => from_si_to_d_e.c} | 0 .../tests/{cuf8_e.c => from_ui_to_d_e.c} | 0 util/mcgg/ir.dat | 6 +++-- 7 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 plat/qemuppc/tests/from_d_to_si_e.c create mode 100644 plat/qemuppc/tests/from_d_to_ui_e.c rename plat/qemuppc/tests/{cif8_e.c => from_si_to_d_e.c} (100%) rename plat/qemuppc/tests/{cuf8_e.c => from_ui_to_d_e.c} (100%) diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index b6bc0ac48..8511dbb5b 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -392,17 +392,33 @@ PATTERNS emit "li32 %out.1, 0" cost 8; - out:(iret)reg = FROMF.I(in:(dret)reg) + out:(iret)reg = FROMSF.I(in:(dret)reg) with corrupted(volatile) emit "bl .fromf2i" cost 4; - out:(iret)reg = FROMD.I(in:(dret)reg) + out:(int)reg = FROMSD.I(in:(double)reg) + with preserved(%in) + emit "fctiwz %in, %in" + emit "stfdu %in, -8(sp)" + emit "lwz %out, 4(sp)" + emit "addi sp, sp, 8" + cost 16; + + out:(int)reg = FROMUD.I(in:(double)reg) with corrupted(volatile) - emit "bl .fromd2i" + emit "stfdu %in, -8(sp)" + emit "bl .cfu8" + emit "lwz %out, 0(sp)" + emit "addi sp, sp, 4" + cost 16; + + out:(lret)reg = FROMSF.L(in:(fret)reg) + with corrupted(volatile) + emit "bl .fromf2l" cost 4; - out:(lret)reg = FROMF.L(in:(fret)reg) + out:(lret)reg = FROMUF.I(in:(fret)reg) with corrupted(volatile) emit "bl .fromf2l" cost 4; diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 66347447f..5462cbf79 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -404,11 +404,11 @@ static void insn_simple(int opcode) case op_cii: simple_convert(IR_FROMSI); break; case op_ciu: simple_convert(IR_FROMSI); break; case op_cui: simple_convert(IR_FROMUI); break; - case op_cfu: simple_convert(IR_FROMF); break; /* FIXME: technically wrong */ - case op_cfi: simple_convert(IR_FROMF); break; + case op_cfu: simple_convert(IR_FROMUF); break; + case op_cfi: simple_convert(IR_FROMSF); break; case op_cif: simple_convert(IR_FROMSI); break; case op_cuf: simple_convert(IR_FROMUI); break; - case op_cff: simple_convert(IR_FROMF); break; + case op_cff: simple_convert(IR_FROMSF); break; case op_cmp: push( diff --git a/plat/qemuppc/tests/from_d_to_si_e.c b/plat/qemuppc/tests/from_d_to_si_e.c new file mode 100644 index 000000000..8c7e31c3e --- /dev/null +++ b/plat/qemuppc/tests/from_d_to_si_e.c @@ -0,0 +1,20 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +double one = 1.0; +double zero = 0.0; +double minusone = -1.0; +double big = 2147483647.0; +double minusbig = -2147483648.0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((int)zero == 0); + ASSERT((int)one == 1); + ASSERT((int)minusone == -1); + ASSERT((int)big == 2147483647); + ASSERT((int)minusbig == -2147483648); + + finished(); +} \ No newline at end of file diff --git a/plat/qemuppc/tests/from_d_to_ui_e.c b/plat/qemuppc/tests/from_d_to_ui_e.c new file mode 100644 index 000000000..b16667502 --- /dev/null +++ b/plat/qemuppc/tests/from_d_to_ui_e.c @@ -0,0 +1,16 @@ +#include "test.h" + +/* Constants in globals to defeat constant folding. */ +double one = 1.0; +double zero = 0.0; +double big = 4294967295.0; + +/* Bypasses the CRT, so there's no stdio or BSS initialisation. */ +void _m_a_i_n(void) +{ + ASSERT((unsigned int)zero == 0); + ASSERT((unsigned int)one == 1); + ASSERT((unsigned int)big == 4294967295); + + finished(); +} \ No newline at end of file diff --git a/plat/qemuppc/tests/cif8_e.c b/plat/qemuppc/tests/from_si_to_d_e.c similarity index 100% rename from plat/qemuppc/tests/cif8_e.c rename to plat/qemuppc/tests/from_si_to_d_e.c diff --git a/plat/qemuppc/tests/cuf8_e.c b/plat/qemuppc/tests/from_ui_to_d_e.c similarity index 100% rename from plat/qemuppc/tests/cuf8_e.c rename to plat/qemuppc/tests/from_ui_to_d_e.c diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index b34f37fbb..4b7c4e920 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -69,8 +69,10 @@ S ?=I. FROMUI S ?=L. FROMUL S ?=I. FROMSI S ?=L. FROMSL -S ?=F. FROMF -S ?=D. FROMD +S ?=F. FROMUF +S ?=D. FROMUD +S ?=F. FROMSF +S ?=D. FROMSD S L=II FROMIPAIR S I=L. FROML0 S I=L. FROML1 From 196fa914b38f0a8dc53ecee25e9e5a52cf5447f7 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 11:57:21 +0100 Subject: [PATCH 205/230] lxa now works, I hope; traps are better (and stubbed out on qemuppc). --- mach/proto/mcg/treebuilder.c | 31 ++++++++++++++--- plat/qemuppc/libsys/trap.s | 64 ++++++++---------------------------- 2 files changed, 39 insertions(+), 56 deletions(-) diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 5462cbf79..18e77c94a 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -7,6 +7,7 @@ static struct ir* stack[64]; static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode); static struct ir* appendir(struct ir* ir); +static void insn_ivalue(int opcode, arith value); static void reset_stack(void) { @@ -486,7 +487,12 @@ static void insn_simple(int opcode) case op_trp: helper_function(".trp"); break; case op_sig: helper_function(".sig"); break; - case op_rtt: helper_function(".rtt"); break; + + case op_rtt: + { + insn_ivalue(op_ret, 0); + break; + } /* FIXME: These instructions are really complex and barely used * (Modula-2 bitset support, I believe). Leave them until later. */ @@ -1202,11 +1208,26 @@ static void insn_ivalue(int opcode, arith value) case op_lxa: { - /* What does this actually *do*? The spec doesn't say. */ - appendir( + struct ir* ir; + + /* Walk the static chain. */ + + ir = new_ir0( + IR_GETFP, EM_pointersize + ); + + while (value--) + { + ir = new_ir1( + IR_CHAINFP, EM_pointersize, + ir + ); + } + + push( new_ir1( - IR_CALL, 0, - new_labelir(".unimplemented_lxa") + IR_FPTOAB, EM_pointersize, + ir ) ); break; diff --git a/plat/qemuppc/libsys/trap.s b/plat/qemuppc/libsys/trap.s index 09d3b0b21..39e5b97ef 100644 --- a/plat/qemuppc/libsys/trap.s +++ b/plat/qemuppc/libsys/trap.s @@ -46,60 +46,22 @@ EBADLIN = 26 EBADGTO = 27 EUNIMPL = 63 ! unimplemented em-instruction called -! EM trap handling. - .define .trap_ecase .trap_ecase: - addi r3, r0, ECASE - b .trap + b .trp .define .trap_earray .trap_earray: - addi r3, r0, EARRAY - b .trap - -.define .trap -.trap: - cmpi cr0, 0, r3, 15 ! traps >15 can't be ignored - bc IFTRUE, LT, 1f - - addi r4, r0, 1 - rlwnm r4, r4, r3, 0, 31 ! calculate trap bit - li32 r5, .ignmask - lwz r5, 0(r5) ! load ignore mask - and. r4, r4, r5 ! compare - bclr IFFALSE, EQ, 0 ! return if non-zero - -1: + b .trp + +.define .trp +.trp: + b .trp ! spin forever + +.define .sig +.sig: + lwz r3, 0(sp) li32 r4, .trppc - lwz r5, 0(r4) ! load user trap routine - or. r5, r5, r5 ! test - bc IFTRUE, EQ, fatal ! if no user trap routine, bail out - - addi r0, r0, 0 - stw r0, 0(r4) ! reset trap routine - - mfspr r0, lr - stwu r0, -4(sp) ! save old lr - - stwu r3, -4(sp) - mtspr ctr, r5 - bcctrl ALWAYS, 0, 0 ! call trap routine - - lwz r0, 4(sp) ! load old lr again - addi sp, sp, 8 ! retract over stack usage - bclr ALWAYS, 0, 0 ! return - -fatal: - addi r3, r0, 1 - li32 r4, message - addi r5, r0, 6 - addi r0, r0, 4 ! write() - sc 0 - - addi r0, r0, 1 ! exit() - sc 0 - -.sect .rom -message: - .ascii "TRAP!\n" + stw r3, 0(r4) + bclr ALWAYS, 0, 0 ! return + \ No newline at end of file From 953c08839f330eb8e3c04eb8829a61cad21886a9 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 12:53:44 +0100 Subject: [PATCH 206/230] inn works now; add a helper for it. --- mach/powerpc/libem/build.lua | 1 + mach/powerpc/libem/inn.s | 26 ++++++++++++ mach/proto/mcg/treebuilder.c | 9 ++--- plat/qemuppc/tests/inn_e.e | 76 ++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 mach/powerpc/libem/inn.s create mode 100644 plat/qemuppc/tests/inn_e.e diff --git a/mach/powerpc/libem/build.lua b/mach/powerpc/libem/build.lua index dd9ec7542..318be381d 100644 --- a/mach/powerpc/libem/build.lua +++ b/mach/powerpc/libem/build.lua @@ -8,6 +8,7 @@ for _, plat in ipairs(vars.plats) do name = "lib_"..plat, srcs = { "./*.s", + "./*.e", }, vars = { plat = plat }, deps = { diff --git a/mach/powerpc/libem/inn.s b/mach/powerpc/libem/inn.s new file mode 100644 index 000000000..f5ae4c63e --- /dev/null +++ b/mach/powerpc/libem/inn.s @@ -0,0 +1,26 @@ +#include "powerpc.h" + +.sect .text + +/* Tests a bit in a bitset on the stack. + * + * Stack: ( bitset bitnum setsize -- bool ) + */ + +.define .inn +.inn: + lwz r3, 0(sp) /* r3 = size (bytes) */ + lwz r4, 4(sp) /* r4 = bit number */ + addi r5, sp, 8 /* r5 = base address of bit set */ + + srawi r6, r4, 3 /* r6 = byte address into set */ + andi. r7, r4, 7 /* r7 = bit within byte */ + + lbzx r8, r5, r6 /* r8 = individual byte from set */ + sraw r8, r8, r7 + rlwinm r8, r8, 0, 31, 31 + + addi sp, sp, 8 /* retract over the two words */ + add sp, sp, r3 /* retract over bitfield */ + stwu r8, -4(sp) /* push result */ + bclr ALWAYS, 0, 0 /* return */ diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 18e77c94a..2ead527fc 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1447,12 +1447,11 @@ static void insn_ivalue(int opcode, arith value) * (Modula-2 bitset support, I believe). Leave them until leter. */ case op_inn: { - appendir( - new_ir1( - IR_CALL, 0, - new_labelir(".unimplemented") - ) + push( + new_wordir(value) ); + + helper_function(".inn"); break; } diff --git a/plat/qemuppc/tests/inn_e.e b/plat/qemuppc/tests/inn_e.e new file mode 100644 index 000000000..4e53b35c5 --- /dev/null +++ b/plat/qemuppc/tests/inn_e.e @@ -0,0 +1,76 @@ +# + mes 2, 4, 4 + + exp $_m_a_i_n + pro $_m_a_i_n, 0 + + /* Test non-existent bit */ + +.1 + rom 0I1, 0I1, 0I1, 0I1 + loe .1 + loc 1 /* bit number */ + inn 4 + zeq *1 + + loc __LINE__ + cal $fail + ass 4 +1 + + /* Test existent bit */ + +.2 + rom 2I1, 0I1, 0I1, 0I1 + loe .2 + loc 1 /* bit number */ + inn 4 + zne *2 + + loc __LINE__ + cal $fail + ass 4 +2 + + /* Test non-existent high bit */ + +.3 + rom 0I1, 0I1, 0I1, 0I1 + rom 0I1, 0I1, 0I1, 0I1 +.31 + rom 33 /* to defeat constant folding */ + + lae .3 + loi 8 + loe .31 /* bit number */ + inn 8 + zeq *3 + + loc __LINE__ + cal $fail + ass 4 +3 + + /* Test existent high bit */ + +.4 + rom 0I1, 0I1, 0I1, 0I1 + rom 2I1, 0I1, 0I1, 0I1 +.41 + rom 33 /* to defeat constant folding */ + + lae .4 + loi 8 + loe .41 /* bit number */ + inn 8 + zne *4 + + loc __LINE__ + cal $fail + ass 4 +4 + + cal $finished + ret 0 + + end From 2d0bc7ef0d9ede851b409d7c958a4edfc60c671d Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 18:57:44 +0100 Subject: [PATCH 207/230] Finally fix the build system issue where ackprogram would try to explicitly link all the language libraries. --- plat/build.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/plat/build.lua b/plat/build.lua index a6774b920..85ba61bc9 100644 --- a/plat/build.lua +++ b/plat/build.lua @@ -62,11 +62,23 @@ definerule("ackprogram", deps = { type="targets", default={} }, }, function (e) + -- This bit is a hack. We *don't* want to link the language libraries here, + -- because the ack driver is going to pick the appropriate library itself and + -- we don't want more than one. But we still need to depend on them, so we use + -- a nasty hack. + + local platstamp = normalrule { + name = e.name.."/platstamp", + ins = { "plat/"..e.vars.plat.."+pkg" }, + outleaves = { "stamp" }, + commands = { "touch %{outs}" } + } + return cprogram { name = e.name, srcs = e.srcs, deps = { - "plat/"..e.vars.plat.."+pkg", + platstamp, "util/ack+pkg", "util/led+pkg", e.deps From f8fa3ece4241a1892505cd5270bdfadca2a82604 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 19:35:34 +0100 Subject: [PATCH 208/230] inn on ncg now passes the CPU tests. --- mach/powerpc/ncg/table | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 6f10c7d4c..77fdaedf1 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -328,6 +328,7 @@ INSTRUCTIONS lhax GPR:wo, GPR:ro, GPR:ro cost(4, 3). lhz GPR:wo, GPRINDIRECT:ro cost(4, 3). lhzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). + li32 GPR:wo, CONST:ro cost(8, 2). li32 GPR:wo, LABEL:ro cost(8, 2). lwzu GPR:wo, GPRINDIRECT:ro cost(4, 3). lwzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). @@ -1637,14 +1638,13 @@ PATTERNS gen bl {LABEL, ".set"} - pat inn defined($1) /* Test for set bit */ - leaving - set INT32 - and INT32 - - pat inn !defined($1) /* Test for set bit (variable) */ - with GPR3 STACK + pat inn /* Test for set bit */ + with STACK + kills ALL + uses REG gen + li32 %a, {CONST, $1} + stwu %a, {GPRINDIRECT, SP, 0-4} bl {LABEL, ".inn"} From 6e9c2d5c0d8befa457b6a89ff8eb74f9de03892c Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 20 Nov 2016 19:39:28 +0100 Subject: [PATCH 209/230] Also call .trp .trap, for ncg compatibility. --- plat/qemuppc/libsys/trap.s | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plat/qemuppc/libsys/trap.s b/plat/qemuppc/libsys/trap.s index 39e5b97ef..f05b907d0 100644 --- a/plat/qemuppc/libsys/trap.s +++ b/plat/qemuppc/libsys/trap.s @@ -55,7 +55,9 @@ EUNIMPL = 63 ! unimplemented em-instruction called b .trp .define .trp +.define .trap .trp: +.trap: b .trp ! spin forever .define .sig From 2367b011f59fdc40160b610c889d28f354634760 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 23 Nov 2016 21:53:14 +0100 Subject: [PATCH 210/230] Don't install qemu-system-ppc until openbios-ppc gets whitelisted by Travis. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 77146f1b3..c6e2f5913 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ addons: apt: packages: - ed - - qemu-system - openbios-ppc git: From 0aac9aafd3a4e81171d1a4a4ed50f39366df1450 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 23 Nov 2016 22:04:21 +0100 Subject: [PATCH 211/230] Combine brk() with sbrk(); modify brk() to update the sbrk(0) value. --- plat/linux/libsys/brk.c | 17 ----------------- plat/linux/libsys/sbrk.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 17 deletions(-) delete mode 100644 plat/linux/libsys/brk.c diff --git a/plat/linux/libsys/brk.c b/plat/linux/libsys/brk.c deleted file mode 100644 index 7ce5c5fc8..000000000 --- a/plat/linux/libsys/brk.c +++ /dev/null @@ -1,17 +0,0 @@ -/* $Source: /cvsroot/tack/Ack/plat/linux386/libsys/brk.c,v $ - * $State: Exp $ - * $Revision: 1.1 $ - */ - -#include -#include -#include -#include "libsys.h" - -int brk(void* end) -{ - int e = _syscall(__NR_brk, (quad) end, 0, 0); - if (e == -1) - errno = ENOMEM; - return e; -} diff --git a/plat/linux/libsys/sbrk.c b/plat/linux/libsys/sbrk.c index 35810ef89..0948a41b8 100644 --- a/plat/linux/libsys/sbrk.c +++ b/plat/linux/libsys/sbrk.c @@ -12,6 +12,16 @@ static char* current = NULL; +int brk(void* end) +{ + int e = _syscall(__NR_brk, (quad) end, 0, 0); + if (e == -1) + errno = ENOMEM; + else + current = end; + return e; +} + void* sbrk(intptr_t increment) { char* old; From 36ab90385fb33c3e7bec0fcb58de70ad1b464d4a Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 23 Nov 2016 22:06:24 +0100 Subject: [PATCH 212/230] Change sbrk() to take an int rather than an intptr_t (following the OpenBSD way rather than the Linux way; various non-C bits of the ACK assume it takes an int, so it's cleaner). --- plat/cpm/include/unistd.h | 2 +- plat/cpm/libsys/brk.c | 2 +- plat/linux/libsys/sbrk.c | 2 +- plat/linux386/include/unistd.h | 2 +- plat/linux68k/include/unistd.h | 2 +- plat/linuxppc/include/unistd.h | 2 +- plat/pc86/include/unistd.h | 2 +- plat/pc86/libsys/brk.c | 2 +- plat/qemuppc/include/unistd.h | 2 +- plat/qemuppc/libsys/brk.c | 2 +- plat/rpi/include/unistd.h | 2 +- plat/rpi/libsys/brk.c | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/plat/cpm/include/unistd.h b/plat/cpm/include/unistd.h index 2af9db921..ea4f51c0f 100644 --- a/plat/cpm/include/unistd.h +++ b/plat/cpm/include/unistd.h @@ -37,7 +37,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); extern off_t lseek(int fildes, off_t offset, int whence); extern int close(int d); diff --git a/plat/cpm/libsys/brk.c b/plat/cpm/libsys/brk.c index e29dc565b..0b83b2523 100644 --- a/plat/cpm/libsys/brk.c +++ b/plat/cpm/libsys/brk.c @@ -28,7 +28,7 @@ int brk(void* newend) return 0; } -void* sbrk(intptr_t increment) +void* sbrk(int increment) { char* old; diff --git a/plat/linux/libsys/sbrk.c b/plat/linux/libsys/sbrk.c index 0948a41b8..7aeeecb86 100644 --- a/plat/linux/libsys/sbrk.c +++ b/plat/linux/libsys/sbrk.c @@ -22,7 +22,7 @@ int brk(void* end) return e; } -void* sbrk(intptr_t increment) +void* sbrk(int increment) { char* old; char* new; diff --git a/plat/linux386/include/unistd.h b/plat/linux386/include/unistd.h index 715e321d7..35dc8dde7 100644 --- a/plat/linux386/include/unistd.h +++ b/plat/linux386/include/unistd.h @@ -67,7 +67,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); extern int brk(void* ptr); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); /* Signal handling */ diff --git a/plat/linux68k/include/unistd.h b/plat/linux68k/include/unistd.h index 5cbdc1b5d..307192f77 100644 --- a/plat/linux68k/include/unistd.h +++ b/plat/linux68k/include/unistd.h @@ -65,7 +65,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); extern int brk(void* ptr); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); /* Signal handling */ diff --git a/plat/linuxppc/include/unistd.h b/plat/linuxppc/include/unistd.h index 5cbdc1b5d..307192f77 100644 --- a/plat/linuxppc/include/unistd.h +++ b/plat/linuxppc/include/unistd.h @@ -65,7 +65,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); extern int brk(void* ptr); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); /* Signal handling */ diff --git a/plat/pc86/include/unistd.h b/plat/pc86/include/unistd.h index 2af9db921..ea4f51c0f 100644 --- a/plat/pc86/include/unistd.h +++ b/plat/pc86/include/unistd.h @@ -37,7 +37,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); extern off_t lseek(int fildes, off_t offset, int whence); extern int close(int d); diff --git a/plat/pc86/libsys/brk.c b/plat/pc86/libsys/brk.c index 02e213399..952a9c747 100644 --- a/plat/pc86/libsys/brk.c +++ b/plat/pc86/libsys/brk.c @@ -28,7 +28,7 @@ int brk(void* newend) return 0; } -void* sbrk(intptr_t increment) +void* sbrk(int increment) { char* old; diff --git a/plat/qemuppc/include/unistd.h b/plat/qemuppc/include/unistd.h index 5cbdc1b5d..307192f77 100644 --- a/plat/qemuppc/include/unistd.h +++ b/plat/qemuppc/include/unistd.h @@ -65,7 +65,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); extern int brk(void* ptr); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); /* Signal handling */ diff --git a/plat/qemuppc/libsys/brk.c b/plat/qemuppc/libsys/brk.c index 02e213399..952a9c747 100644 --- a/plat/qemuppc/libsys/brk.c +++ b/plat/qemuppc/libsys/brk.c @@ -28,7 +28,7 @@ int brk(void* newend) return 0; } -void* sbrk(intptr_t increment) +void* sbrk(int increment) { char* old; diff --git a/plat/rpi/include/unistd.h b/plat/rpi/include/unistd.h index a4d0c4507..196b823c4 100644 --- a/plat/rpi/include/unistd.h +++ b/plat/rpi/include/unistd.h @@ -59,7 +59,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); -extern void* sbrk(intptr_t increment); +extern void* sbrk(int increment); extern int isatty(int d); extern off_t lseek(int fildes, off_t offset, int whence); extern int close(int d); diff --git a/plat/rpi/libsys/brk.c b/plat/rpi/libsys/brk.c index 36c7d4a6f..171b8e5cf 100644 --- a/plat/rpi/libsys/brk.c +++ b/plat/rpi/libsys/brk.c @@ -30,7 +30,7 @@ int brk(void* newend) return 0; } -void* sbrk(intptr_t increment) +void* sbrk(int increment) { char* old; From 9481487e3d156ca18742c124735f1bc52ebfa616 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 23 Nov 2016 22:16:25 +0100 Subject: [PATCH 213/230] Implement calloc() (accidentally got dropped with the malloc rewrite). --- lang/cem/libcc.ansi/malloc/calloc.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 lang/cem/libcc.ansi/malloc/calloc.c diff --git a/lang/cem/libcc.ansi/malloc/calloc.c b/lang/cem/libcc.ansi/malloc/calloc.c new file mode 100644 index 000000000..2e9d3be16 --- /dev/null +++ b/lang/cem/libcc.ansi/malloc/calloc.c @@ -0,0 +1,23 @@ +#include +#include +#include + +void* calloc(size_t nmemb, size_t size) +{ + size_t bytes = nmemb * size; + void* ptr; + + /* Test for overflow. + * See http://stackoverflow.com/questions/1815367/multiplication-of-large-numbers-how-to-catch-overflow + */ + + if ((nmemb == 0) || (size == 0) || (nmemb > (SIZE_MAX / size))) + return NULL; + + ptr = malloc(bytes); + if (!ptr) + return NULL; + + memset(ptr, 0, bytes); + return ptr; +} From 6cd2a9ba81788cf89ae2ff1c7fcf4b5c4c715181 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 23 Nov 2016 22:22:04 +0100 Subject: [PATCH 214/230] Add a test for calloc(). --- plat/qemuppc/tests/calloc_c.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 plat/qemuppc/tests/calloc_c.c diff --git a/plat/qemuppc/tests/calloc_c.c b/plat/qemuppc/tests/calloc_c.c new file mode 100644 index 000000000..518aa7e49 --- /dev/null +++ b/plat/qemuppc/tests/calloc_c.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "test.h" + +int main(int argc, const char* argv[]) +{ + const char* p; + int i; + + ASSERT(0 == calloc(0, 0)); + ASSERT(0 == calloc(0, 1)); + ASSERT(0 == calloc(1, 0)); + ASSERT(0 == calloc(SIZE_MAX/2, 3)); + ASSERT(0 == calloc(SIZE_MAX/2, 2)); + ASSERT(0 != calloc(1, 1)); + + p = calloc(10, 1); + for (i=0; i<10; i++) + ASSERT(0 == p[i]); + + finished(); +} From 991f47098ceb2d812808f730d15f7fa21c79d33e Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 23 Nov 2016 22:28:21 +0100 Subject: [PATCH 215/230] Add a test for brk() and sbrk(). --- plat/qemuppc/tests/brk_c.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 plat/qemuppc/tests/brk_c.c diff --git a/plat/qemuppc/tests/brk_c.c b/plat/qemuppc/tests/brk_c.c new file mode 100644 index 000000000..aa0f7ef99 --- /dev/null +++ b/plat/qemuppc/tests/brk_c.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include "test.h" + +int main(int argc, const char* argv[]) +{ + void* p; + + ASSERT(-1 == (intptr_t)brk((void*)0xffffffff)); + ASSERT(ENOMEM == errno); + + p = sbrk(0); + ASSERT(p == sbrk(0)); + ASSERT(p == sbrk(8)); + ASSERT(p != sbrk(0)); + ASSERT(p != sbrk(-8)); + ASSERT(p == sbrk(0)); + + /* We assume the test environment has less than 2GB of RAM. */ + ASSERT(-1 == (intptr_t)sbrk(INT_MAX)); + ASSERT(-1 == (intptr_t)sbrk(INT_MIN)); + + finished(); +} + From 899f1ea4f311e48bc48557bbf3c227c7a088c828 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 24 Nov 2016 19:47:11 +0100 Subject: [PATCH 216/230] Forgot to check in the change to qemuppc's brk() to set errno on memory allocation failure. --- plat/qemuppc/libsys/brk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plat/qemuppc/libsys/brk.c b/plat/qemuppc/libsys/brk.c index 952a9c747..118bda3cf 100644 --- a/plat/qemuppc/libsys/brk.c +++ b/plat/qemuppc/libsys/brk.c @@ -22,7 +22,10 @@ int brk(void* newend) if ((p > (&dummy - STACK_BUFFER)) || (p < _end)) + { + errno = ENOMEM; return -1; + } current = p; return 0; From c084f9f224617f931ba391e8d63ecd6545a3ebc7 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 24 Nov 2016 20:35:26 +0100 Subject: [PATCH 217/230] Remove the Mark() and Release() procedures from the Pascal compiler and standard library, because they never worked and come from an achingly old version of the Pascal specification. Fix the implementations of New() and Dispose() to use the standard C memory allocator rather than rolling their own (also in C). Write test! --- lang/pc/comp/chk_expr.c | 7 -- lang/pc/comp/code.c | 10 --- lang/pc/comp/main.c | 4 - lang/pc/comp/required.h | 81 ++++++++++--------- lang/pc/libpc/build.lua | 1 - lang/pc/libpc/dis.c | 101 ------------------------ lang/pc/libpc/new.c | 126 +++--------------------------- lang/pc/libpc/sav.e | 49 ------------ plat/qemuppc/tests/build.lua | 2 +- plat/qemuppc/tests/newdispose_p.p | 34 ++++++++ 10 files changed, 90 insertions(+), 325 deletions(-) delete mode 100644 lang/pc/libpc/dis.c delete mode 100644 lang/pc/libpc/sav.e create mode 100644 plat/qemuppc/tests/newdispose_p.p diff --git a/lang/pc/comp/chk_expr.c b/lang/pc/comp/chk_expr.c index 1c5cb58ea..a9e8ba73a 100644 --- a/lang/pc/comp/chk_expr.c +++ b/lang/pc/comp/chk_expr.c @@ -1183,13 +1183,6 @@ ChkStandard(expp,left) expp->nd_type = NULLTYPE; break; - case R_MARK: - case R_RELEASE: - if( !(left = getarg(&arg, T_POINTER, 1, name, NULLTYPE)) ) - return 0; - expp->nd_type = NULLTYPE; - break; - case R_HALT: if( !arg->nd_right ) /* insert 0 parameter */ arg->nd_right = ZeroParam(); diff --git a/lang/pc/comp/code.c b/lang/pc/comp/code.c index 1c916c3dc..5cdc6644a 100644 --- a/lang/pc/comp/code.c +++ b/lang/pc/comp/code.c @@ -1076,16 +1076,6 @@ CodeStd(nd) C_asp(pointer_size + word_size); break; - case R_MARK: - case R_RELEASE: - CodeDAddress(left); - if( req == R_MARK ) - C_cal("_sav"); - else - C_cal("_rst"); - C_asp(pointer_size); - break; - case R_HALT: if( left ) CodePExpr(left); diff --git a/lang/pc/comp/main.c b/lang/pc/comp/main.c index cef708fcd..46eabf855 100644 --- a/lang/pc/comp/main.c +++ b/lang/pc/comp/main.c @@ -189,10 +189,6 @@ AddRequired() /* DYNAMIC ALLOCATION PROCEDURES */ (void) Enter("new", D_PROCEDURE, std_type, R_NEW); (void) Enter("dispose", D_PROCEDURE, std_type, R_DISPOSE); - if( !options['s'] ) { - (void) Enter("mark", D_PROCEDURE, std_type, R_MARK); - (void) Enter("release", D_PROCEDURE, std_type, R_RELEASE); - } /* MISCELLANEOUS PROCEDURE(S) */ if( !options['s'] ) diff --git a/lang/pc/comp/required.h b/lang/pc/comp/required.h index 20b9a5fad..e8a4becbe 100644 --- a/lang/pc/comp/required.h +++ b/lang/pc/comp/required.h @@ -1,48 +1,51 @@ /* REQUIRED PROCEDURES AND FUNCTIONS */ -/* PROCEDURES */ -/* FILE HANDLING */ -#define R_REWRITE 1 -#define R_PUT 2 -#define R_RESET 3 -#define R_GET 4 -#define R_PAGE 5 +enum +{ + R__UNUSED = 0, -/* DYNAMIC ALLOCATION */ -#define R_NEW 6 -#define R_DISPOSE 7 -#define R_MARK 8 -#define R_RELEASE 9 + /* PROCEDURES */ + /* FILE HANDLING */ + R_REWRITE, + R_PUT, + R_RESET, + R_GET, + R_PAGE, -/* MISCELLANEOUS PROCEDURE(S) */ -#define R_HALT 10 + /* DYNAMIC ALLOCATION */ + R_NEW, + R_DISPOSE, -/* TRANSFER */ -#define R_PACK 11 -#define R_UNPACK 12 + /* MISCELLANEOUS PROCEDURE(S) */ + R_HALT, -/* FUNCTIONS */ -/* ARITHMETIC */ -#define R_ABS 13 -#define R_SQR 14 -#define R_SIN 15 -#define R_COS 16 -#define R_EXP 17 -#define R_LN 18 -#define R_SQRT 19 -#define R_ARCTAN 20 + /* TRANSFER */ + R_PACK, + R_UNPACK, -/* TRANSFER */ -#define R_TRUNC 21 -#define R_ROUND 22 + /* FUNCTIONS */ + /* ARITHMETIC */ + R_ABS, + R_SQR, + R_SIN, + R_COS, + R_EXP, + R_LN, + R_SQRT, + R_ARCTAN, -/* ORDINAL */ -#define R_ORD 23 -#define R_CHR 24 -#define R_SUCC 25 -#define R_PRED 26 + /* TRANSFER */ + R_TRUNC, + R_ROUND, -/* BOOLEAN */ -#define R_ODD 27 -#define R_EOF 28 -#define R_EOLN 29 + /* ORDINAL */ + R_ORD, + R_CHR, + R_SUCC, + R_PRED, + + /* BOOLEAN */ + R_ODD, + R_EOF, + R_EOLN, +}; diff --git a/lang/pc/libpc/build.lua b/lang/pc/libpc/build.lua index 61c4f7a3e..7845991e5 100644 --- a/lang/pc/libpc/build.lua +++ b/lang/pc/libpc/build.lua @@ -11,7 +11,6 @@ for _, plat in ipairs(vars.plats) do "./fif.e", "./gto.e", "./hol0.e", - "./sav.e", "./sig.e", "./trap.e", "./trp.e", diff --git a/lang/pc/libpc/dis.c b/lang/pc/libpc/dis.c deleted file mode 100644 index c6a9bd2e7..000000000 --- a/lang/pc/libpc/dis.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * File: - dis.c - * - * dispose() built in standard procedure in Pascal (6.6.5.3) - * - * Re-implementation of storage allocator for Ack Pascal compiler - * under Linux, and other UNIX-like systems. - * - * Written by Erik Backerud, 2010-10-01 - * - * Original copyright and author info below: - */ -/* $Id$ */ -/* - * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. - * - * This product is part of the Amsterdam Compiler Kit. - * - * Permission to use, sell, duplicate or disclose this software must be - * obtained in writing. Requests for such permissions may be sent to - * - * Dr. Andrew S. Tanenbaum - * Wiskundig Seminarium - * Vrije Universiteit - * Postbox 7161 - * 1007 MC Amsterdam - * The Netherlands - * - */ - -/* Author: J.W. Stevenson */ - -#include - -#define assert() /* nothing */ - -/* - * use a singly linked list of free blocks. - */ -struct adm { - struct adm *next; - int size; -}; - -struct adm *freep = 0; /* first element on free list */ - -extern void _trp(int); - -/* - * Dispose - * Called with two arguments: - * n the size of the block to be freed, in bytes, - * pp address of pointer to data. - */ -void -_dis(int n, struct adm **pp) -{ - struct adm *block; /* the block of data being freed (inc. header) */ - struct adm *p, *q; - - if (*pp == 0) { - _trp(EFREE); - } - block = *pp - 1; - if (freep == 0) { - freep = block; - block->next = 0; - } else { - q = 0; /* trail one behind */ - for (p = freep; p < block; p = p->next) { - if (p == 0) { /* We reached the end of the free list. */ - break; - } - q = p; - /* check if block is contained in the free block p */ - if (p+p->size > block) { - _trp(EFREE); - } - } - if (p == block) { /* this block already freed */ - _trp(EFREE); - } - if (q == 0) { /* block is first */ - freep = block; - block->next = p; - } else { - q->next = block; - } - block->next = p; - /* merge with successor on free list? */ - if (block + block->size == p) { - block->size = block->size + p->size; - block->next = p->next; - } - /* merge with preceding block on free list? */ - if (q != 0 && q+q->size == block) { - q->size = q->size + block->size; - q->next = block->next; - } - } -} /* _dis */ diff --git a/lang/pc/libpc/new.c b/lang/pc/libpc/new.c index 427cb850c..b3425c176 100644 --- a/lang/pc/libpc/new.c +++ b/lang/pc/libpc/new.c @@ -1,120 +1,20 @@ -/* - * File: - new.c - * - * new() built in standard procedure in Pascal (6.6.5.3) - * - * Re-implementation of storage allocator for Ack Pascal compiler - * under Linux, and other UNIX-like systems. - * - * Written by Erik Backerud, 2010-10-01 - * - * Original copyright and author info below: - */ -/* $Id$ */ -/* - * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. - * - * This product is part of the Amsterdam Compiler Kit. - * - * Permission to use, sell, duplicate or disclose this software must be - * obtained in writing. Requests for such permissions may be sent to - * - * Dr. Andrew S. Tanenbaum - * Wiskundig Seminarium - * Vrije Universiteit - * Postbox 7161 - * 1007 MC Amsterdam - * The Netherlands - * - */ - -/* Author: J.W. Stevenson */ +#include #include #include -#define assert(x) /* nothing */ -#define UNDEF 0x8000 -#define NALLOC (1024) /* request this many units from OS */ - - -/* - * use a singly linked list of free blocks. - */ -struct adm { - struct adm *next; - int size; -}; - -extern struct adm *freep; - extern void _trp(int); /* called on error */ -extern void _dis(int, struct adm **); - - -/* - * Helper function to request 'nu' units of memory from the OS. - * A storage unit is sizeof(struct adm). Typically 8 bytes - * on a 32-bit machine like i386 etc. - */ -static struct adm * -morecore(unsigned nu) +void _new(int n, void** ptr) { - char *cp, *sbrk(int); - struct adm *up; - - if (nu < NALLOC) - nu = NALLOC; - cp = sbrk(nu * sizeof(struct adm)); - if (cp == (char *) -1) /* no space at all */ - return 0; - up = (struct adm*) cp; - up->size = nu; - up = up + 1; - _dis((nu - 1) * sizeof(struct adm), &up); - return freep; -} /* morecore */ - -/* - * Dispose - * Called with two arguments: - * n the size of the block to be freed, in bytes, - * pp address of pointer to data. - */ -void -_new(int n, struct adm **pp) -{ - int nunits; /* the unit of storage is sizeof(struct adm) */ - struct adm *p,*q; - - /* round up size of request */ - nunits = (n + sizeof(struct adm) - 1) / sizeof(struct adm) + 1; - - q = 0; - for (p = freep; ; p = p->next) { - if (p == 0) { - p = morecore(nunits); - if (p == 0) + void* p = malloc(n); + if (!p) _trp(EHEAP); - q = 0; - } - if (p->size >= nunits) { - if (p->size == nunits) { /* exact fit */ - if (q == 0) { /* first element on free list. */ - freep = p->next; - } else { - q->next = p->next; - } - } else { /* allocate tail end */ - q = p; - q->size = q->size - nunits; - p = q + q->size; - p->next = 0; - p->size = nunits; - } - break; - } - q = p; - } - *pp = p + 1; -} /* _new */ + + *ptr = p; +} + +void _dis(int n, void** ptr) +{ + free(*ptr); + *ptr = NULL; +} \ No newline at end of file diff --git a/lang/pc/libpc/sav.e b/lang/pc/libpc/sav.e deleted file mode 100644 index 3f5362f1c..000000000 --- a/lang/pc/libpc/sav.e +++ /dev/null @@ -1,49 +0,0 @@ -# -; $Id$ -; (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. -; -; This product is part of the Amsterdam Compiler Kit. -; -; Permission to use, sell, duplicate or disclose this software must be -; obtained in writing. Requests for such permissions may be sent to -; -; Dr. Andrew S. Tanenbaum -; Wiskundig Seminarium -; Vrije Universiteit -; Postbox 7161 -; 1007 MC Amsterdam -; The Netherlands -; - -/* Author: J.W. Stevenson */ - - - mes 2,EM_WSIZE,EM_PSIZE - -#define PTRAD 0 - -#define HP 2 - -; _sav called with one parameter: -; - address of pointer variable (PTRAD) - - exp $_sav - pro $_sav,0 - lor HP - lal PTRAD - loi EM_PSIZE - sti EM_PSIZE - ret 0 - end ? - -; _rst is called with one parameter: -; - address of pointer variable (PTRAD) - - exp $_rst - pro $_rst,0 - lal PTRAD - loi EM_PSIZE - loi EM_PSIZE - str HP - ret 0 - end ? diff --git a/plat/qemuppc/tests/build.lua b/plat/qemuppc/tests/build.lua index 024961fda..f0c2993c4 100644 --- a/plat/qemuppc/tests/build.lua +++ b/plat/qemuppc/tests/build.lua @@ -6,7 +6,7 @@ local tests = {} if os.execute("which "..qemu.." > /dev/null") ~= 0 then print("warning: skipping tests which require ", qemu) else - local testcases = filenamesof("./*.c", "./*.s", "./*.e") + local testcases = filenamesof("./*.c", "./*.s", "./*.e", "./*.p") for _, f in ipairs(testcases) do local fs = replace(basename(f), "%..$", "") diff --git a/plat/qemuppc/tests/newdispose_p.p b/plat/qemuppc/tests/newdispose_p.p new file mode 100644 index 000000000..36f09e99b --- /dev/null +++ b/plat/qemuppc/tests/newdispose_p.p @@ -0,0 +1,34 @@ +# +(*$U+ -- enables underscores in identifiers *) + +program markrelease; + +type + iptr = ^integer; + +var + ptr1 : iptr; + ptr2 : iptr; + +procedure finished; + extern; + +procedure fail(line: integer); + extern; + +#define ASSERT(cond) \ + if (not (cond)) then fail(__LINE__) + +begin + New(ptr1); + New(ptr2); + ASSERT(ptr1 <> ptr2); + + Dispose(ptr1); + Dispose(ptr2); + (* Not required by the Pascal standard, but our implementation sets the + * pointers to NULL after freeing them. *) + ASSERT(ptr1 = ptr2); + + finished +end. From ed181a8d2015ad0d90d0ec21d64ad2822473591e Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 25 Nov 2016 20:01:43 +0100 Subject: [PATCH 218/230] Ansify Paranoia, because I was getting annoyed by all the compiler warnings on every build. --- examples/paranoia.c | 141 ++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/examples/paranoia.c b/examples/paranoia.c index f7020f71e..8a25800d9 100644 --- a/examples/paranoia.c +++ b/examples/paranoia.c @@ -15,6 +15,7 @@ This is a public domain adventure and may not be sold for profit */ +#include #include #define MOXIE 13 @@ -32,7 +33,9 @@ int plato_clone=3; int blast_door=0; int killer_count=0; -char get_char() +void character(void); + +char get_char(void) { char c; fflush(stdout); @@ -41,7 +44,7 @@ char get_char() return c; } -more() +void more(void) { printf("---------- More ----------"); #ifdef DEBUG @@ -55,8 +58,7 @@ more() }; } -new_clone(resume) -int resume; +int new_clone(int resume) { printf("\nClone %d just died.\n",clone); if (++clone>6) @@ -75,15 +77,14 @@ int resume; } } -dice_roll(number,faces) -int number, faces; +int dice_roll(int number, int faces) { int i,total=0; for(i=number;i>0;i--) total+= rand()%faces+1; return total; } -instructions() +void instructions(void) { printf("\n\n\n\nWelcome to Paranoia!\n\n"); printf("HOW TO PLAY:\n\n"); @@ -104,7 +105,7 @@ instructions() printf(" If not, you can try again later.\n"); } -character() +void character(void) { printf("===============================================================================\n"); printf("The Character : Philo-R-DMD %d\n", clone); @@ -130,9 +131,7 @@ character() printf("===============================================================================\n"); } -choose(a,aptr,b,bptr) -int a,b; -char *aptr, *bptr; +int choose(int a, char* aptr, int b, char* bptr) { printf("\nSelect \'a\' or \'b\' :\n"); printf(" a - %s.\n b - %s.\n", aptr, bptr); @@ -140,7 +139,7 @@ char *aptr, *bptr; else return b; } -page1() +int page1(void) { printf(" You wake up face down on the red and pink checked E-Z-Kleen linoleum floor.\n"); printf(" You recognise the pattern, it\'s the type preferred in the internal security\nbriefing cells. When you finally look around you, you see that you are alone\n"); @@ -148,7 +147,7 @@ page1() return 57; } -page2() +int page2(void) { printf("\"Greetings,\" says the kindly Internal Security self incrimination expert who\n"); printf("meets you at the door, \"How are we doing today?\" He offers you a doughnut\n"); @@ -166,7 +165,7 @@ page2() else return new_clone(32); } -page3() +int page3(void) { printf("You walk to the nearest Computer terminal and request more information about\n"); printf("Christmas. The Computer says, \"That is an A-1 ULTRAVIOLET ONLY IMMEDIATE\n"); @@ -174,7 +173,7 @@ page3() return choose(4,"You give your correct clearance",5,"You lie and claim Ultraviolet clearance"); } -page4() +int page4(void) { printf("\"That is classified information, Troubleshooter, thank you for your inquiry.\n"); printf(" Please report to an Internal Security self incrimination station as soon as\n"); @@ -182,7 +181,7 @@ page4() return 9; } -page5() +int page5(void) { printf("The computer says, \"Troubleshooter, you are not wearing the correct colour\n"); printf("uniform. You must put on an Ultraviolet uniform immediately. I have seen to\n"); @@ -193,7 +192,7 @@ page5() return choose(6, "You open the package and put on the uniform", 7, "You finally come to your senses and run for it"); } -page6() +int page6(void) { printf("The uniform definitely makes you look snappy and pert. It really looks\n"); printf("impressive, and even has the new lopsided lapel fashion that you admire so\n"); @@ -205,7 +204,7 @@ page6() return 8; } -page7() +int page7(void) { printf("The corridor lights dim and are replaced by red battle lamps as the Security\n"); printf("Breach alarms howl all around you. You run headlong down the corridor and\n"); @@ -232,7 +231,7 @@ page7() return 8; } -page8() +int page8(void) { printf("\"Now, about your question, citizen. Christmas was an old world marketing ploy\n"); printf("to induce lower clearance citizens to purchase vast quantities of goods, thus\n"); @@ -249,7 +248,7 @@ page8() return 10; } -page9() +int page9(void) { int choice; printf("As you walk toward the tubecar that will take you to GDH7-beta, you pass one\n"); @@ -262,7 +261,7 @@ page9() return choice; } -page10() +int page10(void) { int choice; printf("You stroll briskly down the corridor, up a ladder, across an unrailed catwalk,\n"); @@ -290,7 +289,7 @@ page10() } } -page11() +int page11(void) { printf("The printing on the folder says \"Experimental Self Briefing.\"\n"); printf("You open it and begin to read the following:\n"); @@ -321,7 +320,7 @@ page11() return choose(3,"You wish to ask The Computer for more information about Christmas",10,"You have decided to go directly to Goods Distribution Hall 7-beta"); } -page12() +int page12(void) { printf("You walk up to the door and push the button labelled \"push to exit.\"\n"); printf("Within seconds a surly looking guard shoves his face into the small plexiglass\n"); @@ -333,7 +332,7 @@ page12() return choose(11,"You sit down at the table and read the Orange packet",57,"You stare around the room some more"); } -page13() +int page13(void) { printf("You step into the shiny plasteel tubecar, wondering why the shape has always\n"); printf("reminded you of bullets. The car shoots forward the instant your feet touch\n"); @@ -346,7 +345,7 @@ page13() return 14; } -page14() +int page14(void) { printf("You manage to pull yourself out of the tubecar and look around. Before you is\n"); printf("one of the most confusing things you have ever seen, a hallway that is\n"); @@ -360,7 +359,7 @@ page14() return 22; } -page15() +int page15(void) { printf("You are set upon by a runty robot with a queer looking face and two pointy\n"); printf("rubber ears poking from beneath a tattered cap. \"Hey mister,\" it says,\n"); @@ -384,7 +383,7 @@ page15() } } -page16() +int page16(void) { printf("The doll is a good buy for fifty credits; it will make a fine Christmas present\n"); printf("for one of your friends. After the sale the robot rolls away. You can use\n"); @@ -395,7 +394,7 @@ page16() return 22; } -page17() +int page17(void) { int i, robot_hp=15; printf("You whip out your laser and shoot the robot, but not before it squeezes the\n"); @@ -432,7 +431,7 @@ page17() return 22; } -page18() +int page18(void) { printf("You walk to the centre of the hall, ogling like an infrared fresh from the\n"); printf("clone vats. Towering before you is the most unearthly thing you have ever\n"); @@ -448,7 +447,7 @@ page18() else return 20; } -page19() +int page19(void) { printf("Quickly you regain your balance, whirl and fire your laser into the Ultraviolet\n"); printf("citizen behind you. For a moment your heart leaps to your throat, then you\n"); @@ -461,7 +460,7 @@ page19() return choose(34,"You search the body, keeping an eye open for Internal Security",22,"You run away like the cowardly dog you are"); } -page20() +int page20(void) { printf("Oh no! you can\'t keep your balance. You\'re falling, falling head first into\n"); printf("the Christmas beast\'s gaping maw. It\'s a valiant struggle; you think you are\n"); @@ -473,7 +472,7 @@ page20() return 22; } -page21() +int page21(void) { printf("You have been wasting the leading citizens of Alpha Complex at a prodigious\n"); printf("rate. This has not gone unnoticed by the Internal Security squad at GDH7-beta.\n"); @@ -482,7 +481,7 @@ page21() return new_clone(45); } -page22() +int page22(void) { printf("You are searching Goods Distribution Hall 7-beta.\n"); switch(dice_roll(1,4)) @@ -494,7 +493,7 @@ page22() } } -page23() +int page23(void) { printf("You go to the nearest computer terminal and declare yourself a mutant.\n"); printf("\"A mutant, he\'s a mutant,\" yells a previously unnoticed infrared who had\n"); @@ -503,7 +502,7 @@ page23() return choose(28,"You tell them that it was really only a bad joke",24,"You want to fight it out, one against twelve"); } -page24() +int page24(void) { printf("Golly, I never expected someone to pick this. I haven\'t even designed\n"); printf("the 12 citizens who are going to make a sponge out of you. Tell you what,\n"); @@ -511,7 +510,7 @@ page24() return choose(28,"You change your mind and say it was only a bad joke",25,"You REALLY want to shoot it out"); } -page25() +int page25(void) { printf("Boy, you really can\'t take a hint!\n"); printf("They\'re closing in. Their trigger fingers are twitching, they\'re about to\n"); @@ -519,7 +518,7 @@ page25() return choose(28,"You tell them it was all just a bad joke",26,"You are going to shoot"); } -page26() +int page26(void) { printf("You can read the cold, sober hatred in their eyes (They really didn\'t think\n"); printf("it was funny), as they tighten the circle around you. One of them shoves a\n"); @@ -529,19 +528,19 @@ page26() return new_clone(32); } -page27() +int page27(void) { /* doesn't exist. Can't happen with computer version. designed to catch dice cheats */ } -page28() +int page28(void) { printf("They don\'t think it\'s funny.\n"); return 26; } -page29() +int page29(void) { printf("\"Psst, hey citizen, come here. Pssfft,\" you hear. When you peer around\n"); printf("you can see someone\'s dim outline in the shadows. \"I got some information\n"); @@ -559,7 +558,7 @@ page29() } } -page30() +int page30(void) { printf("You step into the shadows and offer the man a thirty credit bill. \"Just drop\n"); printf("it on the floor,\" he says. \"So you\'re looking for the Master Retailer, pssfft?\n"); @@ -586,7 +585,7 @@ page30() } } -page31() +int page31(void) { printf("Like any good troubleshooter you make the least expensive decision and threaten\n"); printf("him for information. With lightning like reflexes you whip out your laser and\n"); @@ -599,7 +598,7 @@ page31() return choose(30,"You pay the 30 credits",22,"You pssfft go away stupid"); } -page32() +int page32(void) { printf("Finally it\'s your big chance to prove that you\'re as good a troubleshooter\n"); printf("as your previous clone. You walk briskly to mission briefing and pick up your\n"); @@ -609,7 +608,7 @@ page32() return 22; } -page33() +int page33(void) { blast_door=1; printf("You release the megabolts on the blast door, then strain against it with your\n"); @@ -622,7 +621,7 @@ page33() else return 36; } -page34() +int page34(void) { printf("You have found a sealed envelope on the body. You open it and read:\n"); printf("\"WARNING: Ultraviolet Clearance ONLY. DO NOT READ.\n"); @@ -650,7 +649,7 @@ page34() return choose(46,"You rush off to the nearest computer terminal to expose the commies",22,"You wander off to look for more evidence"); } -page35() +int page35(void) { printf("\"Oh master,\" you hear through the gun barrel, \"where have you been? It is\n"); printf("time for the great Christmas gifting ceremony. You had better hurry and get\n"); @@ -669,7 +668,7 @@ page35() return new_clone(32); } -page36() +int page36(void) { printf("\"Congratulations, troubleshooter, you have successfully found the lair of the\n"); printf("Master Retailer and completed the Troubleshooter Training Course test mission,\"\n"); @@ -692,7 +691,7 @@ page36() } } -page37() +int page37(void) { printf("\"Come with me please, Troubleshooter,\" says the Green clearance technician\n"); printf("after he has dislodged your head from the cannon. \"You have been participating\n"); @@ -708,7 +707,7 @@ page37() return 38; } -page38() +int page38(void) { printf("\"I am Plato-B-PHI%d, head of mutant propaganda here at the training course.\n",plato_clone); printf("If you have any questions about mutants please come to me. Today I will be\n"); @@ -725,7 +724,7 @@ page38() return choose(39,"You volunteer for the test",40,"You duck behind a chair and hope the instructor doesn\'t notice you"); } -page39() +int page39(void) { printf("You bravely volunteer to test the mutant detection gun. You stand up and walk\n"); printf("down the steps to the podium, passing a very relieved Troubleshooter along the\n"); @@ -743,7 +742,7 @@ page39() return 41; } -page40() +int page40(void) { printf("You breathe a sigh of relief as Plato-B-PHI picks on the other Troubleshooter.\n"); printf("\"You down here in the front,\" says the instructor pointing at the other\n"); @@ -775,7 +774,7 @@ page40() } } -page41() +int page41(void) { printf("You stumble down the hallway of the Troubleshooter Training Course looking for\n"); printf("your next class. Up ahead you see one of the instructors waving to you. When\n"); @@ -789,7 +788,7 @@ page41() return choose(42,"You respond with the proper Illuminati code phrase, \"Ewige Blumenkraft\"",43,"You ignore this secret society contact"); } -page42() +int page42(void) { printf("\"Aha, so you are a member of the elitist Illuminati secret society,\" he says\n"); printf("loudly, \"that is most interesting.\" He turns to the large class already\n"); @@ -799,7 +798,7 @@ page42() return choose(51,"You run for it",52,"You wait for the guard"); } -page43() +int page43(void) { printf("You sit through a long lecture on how to recognise and infiltrate secret\n"); printf("societies, with an emphasis on mimicking secret handshakes. The basic theory,\n"); @@ -815,7 +814,7 @@ page43() return choose(44,"You go looking for a computer terminal",55,"You go to the graduation ceremony immediately"); } -page44() +int page44(void) { printf("You walk down to a semi-secluded part of the training course complex and\n"); printf("activate a computer terminal. \"AT YOUR SERVICE\" reads the computer screen.\n"); @@ -833,7 +832,7 @@ page44() } } -page45() +int page45(void) { printf("\"Hrank Hrank,\" snorts the alarm in your living quarters. Something is up.\n"); printf("You look at the monitor above the bathroom mirror and see the message you have\n"); @@ -847,7 +846,7 @@ page45() return 10; } -page46() +int page46(void) { printf("\"Why do you ask about the communists, Troubleshooter? It is not in the\n"); printf("interest of your continued survival to be asking about such topics,\" says\n"); @@ -855,7 +854,7 @@ page46() return choose(53,"You insist on talking about the communists",54,"You change the subject"); } -page47() +int page47(void) { printf("The Computer orders the entire Vulture squadron to terminate the Troubleshooter\n"); printf("Training Course. Unfortunately you too are terminated for possessing\n"); @@ -867,7 +866,7 @@ page47() return 0; } -page48() +int page48(void) { printf("The tubecar shoots forward as you enter, slamming you back into a pile of\n"); printf("garbage. The front end rotates upward and you, the garbage and the garbage\n"); @@ -877,14 +876,14 @@ page48() return new_clone(45); } -page49() +int page49(void) { printf("The instructor drags your inert body into a specimen detainment cage.\n"); printf("\"He\'ll make a good subject for tomorrow\'s mutant dissection class,\" you hear.\n"); return new_clone(32); } -page50() +int page50(void) { printf("You put down the other Troubleshooter, and then wisely decide to drill a few\n"); printf("holes in the instructor as well; the only good witness is a dead witness.\n"); @@ -893,27 +892,27 @@ page50() return 41; } -page51() +int page51(void) { printf("You run for it, but you don\'t run far. Three hundred strange and exotic\n"); printf("weapons turn you into a freeze dried cloud of soot.\n"); return new_clone(32); } -page52() +int page52(void) { printf("You wisely wait until the instructor returns with a Blue Internal Security\n"); printf("guard. The guard leads you to an Internal Security self incrimination station.\n"); return 2; } -page53() +int page53(void) { printf("You tell The Computer about:\n"); return choose(47,"The commies who have infiltrated the Troubleshooter Training Course\n and the impending People\'s Revolution",54,"Something less dangerous"); } -page54() +int page54(void) { printf("\"Do not try to change the subject, Troubleshooter,\" says The Computer.\n"); printf("\"It is a serious crime to ask about the communists. You will be terminated\n"); @@ -927,7 +926,7 @@ page54() else return new_clone(32); } -page55() +int page55(void) { printf("You and 300 other excited graduates are marched from the lecture hall and into\n"); printf("a large auditorium for the graduation exercise. The auditorium is\n"); @@ -955,7 +954,7 @@ page55() return 0; } -page56() +int page56(void) { printf("That familiar strange feeling of deja\'vu envelops you again. It is hard to\n"); printf("say, but whatever is on the other side of the door does not seem to be intended\n"); @@ -963,15 +962,14 @@ page56() return choose(33,"You open the door and step through",22,"You go looking for more information"); } -page57() +int page57(void) { printf("In the centre of the room is a table and a single chair. There is an Orange\n"); printf("folder on the table top, but you can\'t make out the lettering on it.\n"); return choose(11,"You sit down and read the folder",12,"You leave the room"); } -next_page(this_page) -int this_page; +int next_page(int this_page) { printf("\n"); switch (this_page) @@ -1038,10 +1036,11 @@ int this_page; } } -main() +int main(int argc, const char* argv[]) { /* srand(time(0)); */ instructions(); more(); character(); more(); while((page=next_page(page))!=0) more(); + return 0; } From bfa8e501a3c37b4b0cb8a9cda9390ba12e6c86fe Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 25 Nov 2016 20:28:41 +0100 Subject: [PATCH 219/230] Make pc86 echo console output to the serial port, so qemu can pipe it to stdout. --- plat/pc86/README | 3 +++ plat/pc86/libsys/_sys_rawwrite.s | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/plat/pc86/README b/plat/pc86/README index 689c70844..dcbe0ba27 100644 --- a/plat/pc86/README +++ b/plat/pc86/README @@ -23,6 +23,9 @@ are stubs required to make the demo apps link. File descriptors 0, 1 and 2 represent the console. All reads block. There's enough TTY emulation to allow \n conversion and local echo (but it can't be turned off). +Console output is echoed to the serial port (without any setup). This is used +by qemu for running tests. + Example command line ==================== diff --git a/plat/pc86/libsys/_sys_rawwrite.s b/plat/pc86/libsys/_sys_rawwrite.s index 75f75aae1..ae477c6d2 100644 --- a/plat/pc86/libsys/_sys_rawwrite.s +++ b/plat/pc86/libsys/_sys_rawwrite.s @@ -21,9 +21,18 @@ __sys_rawwrite: push bp mov bp, sp + ! Write to the BIOS console. + movb al, 4(bp) movb ah, 0x0E mov bx, 0x0007 int 0x10 + + ! Also write to the serial port (used by the test suite). + + movb ah, 0x01 + xor dx, dx + int 0x14 + jmp .cret \ No newline at end of file From 5f66f06dc69ee8b89fc3dfce8a7d0ec6f7c8753d Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 25 Nov 2016 21:02:51 +0100 Subject: [PATCH 220/230] Refactored the tests to make the generic across different plats. --- plat/qemuppc/tests/build.lua | 54 ++---------------- {plat/qemuppc/tests => tests/plat}/_dummy.c | 0 {plat/qemuppc/tests => tests/plat}/brk_c.c | 0 tests/plat/build.lua | 57 +++++++++++++++++++ {plat/qemuppc/tests => tests/plat}/calloc_c.c | 0 {plat/qemuppc/tests => tests/plat}/csa_e.c | 0 {plat/qemuppc/tests => tests/plat}/csb_e.c | 0 .../tests => tests/plat}/doublecmp_e.c | 0 .../tests => tests/plat}/from_d_to_si_e.c | 0 .../tests => tests/plat}/from_d_to_ui_e.c | 0 .../tests => tests/plat}/from_si_to_d_e.c | 0 .../tests => tests/plat}/from_ui_to_d_e.c | 0 {plat/qemuppc/tests => tests/plat}/inn_e.e | 0 {plat/qemuppc/tests => tests/plat}/intadd_e.c | 0 {plat/qemuppc/tests => tests/plat}/intcmp_e.c | 0 {plat/qemuppc/tests => tests/plat}/intdiv_e.c | 0 {plat/qemuppc/tests => tests/plat}/intrem_e.c | 0 .../qemuppc/tests => tests/plat}/intshift_e.c | 0 {plat/qemuppc/tests => tests/plat}/intsub_e.c | 0 .../tests => tests/plat}/lib/build.lua | 0 {plat/qemuppc/tests => tests/plat}/lib/test.c | 0 {plat/qemuppc/tests => tests/plat}/lib/test.h | 0 .../tests => tests/plat}/newdispose_p.p | 0 .../tests => tests/plat}/testdriver.sh | 0 24 files changed, 63 insertions(+), 48 deletions(-) rename {plat/qemuppc/tests => tests/plat}/_dummy.c (100%) rename {plat/qemuppc/tests => tests/plat}/brk_c.c (100%) create mode 100644 tests/plat/build.lua rename {plat/qemuppc/tests => tests/plat}/calloc_c.c (100%) rename {plat/qemuppc/tests => tests/plat}/csa_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/csb_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/doublecmp_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/from_d_to_si_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/from_d_to_ui_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/from_si_to_d_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/from_ui_to_d_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/inn_e.e (100%) rename {plat/qemuppc/tests => tests/plat}/intadd_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/intcmp_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/intdiv_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/intrem_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/intshift_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/intsub_e.c (100%) rename {plat/qemuppc/tests => tests/plat}/lib/build.lua (100%) rename {plat/qemuppc/tests => tests/plat}/lib/test.c (100%) rename {plat/qemuppc/tests => tests/plat}/lib/test.h (100%) rename {plat/qemuppc/tests => tests/plat}/newdispose_p.p (100%) rename {plat/qemuppc/tests => tests/plat}/testdriver.sh (100%) diff --git a/plat/qemuppc/tests/build.lua b/plat/qemuppc/tests/build.lua index f0c2993c4..6581d93ef 100644 --- a/plat/qemuppc/tests/build.lua +++ b/plat/qemuppc/tests/build.lua @@ -1,49 +1,7 @@ -include("plat/build.lua") +include("tests/plat/build.lua") -local qemu = "qemu-system-ppc" -local tests = {} - -if os.execute("which "..qemu.." > /dev/null") ~= 0 then - print("warning: skipping tests which require ", qemu) -else - local testcases = filenamesof("./*.c", "./*.s", "./*.e", "./*.p") - - for _, f in ipairs(testcases) do - local fs = replace(basename(f), "%..$", "") - local _, _, lang = fs:find("_(.)$") - if not lang then - lang = "e" - end - - local bin = ackprogram { - name = fs.."_bin", - srcs = { f }, - deps = { "plat/qemuppc/tests/lib+lib" }, - vars = { - plat = "qemuppc", - lang = lang, - ackcflags = "-O0" - } - } - - tests[#tests+1] = normalrule { - name = fs, - outleaves = { "stamp" }, - ins = { - bin, - "./testdriver.sh" - }, - commands = { - "%{ins[2]} "..qemu.." %{ins[1]} 5", - "touch %{outs}" - } - } - end -end - -normalrule { - name = "tests", - outleaves = { "stamp" }, - ins = tests, - commands = { "touch %{outs}" } -} \ No newline at end of file +plat_testsuite { + name = "tests", + plat = "qemuppc", + method = "qemu-system-ppc" +} diff --git a/plat/qemuppc/tests/_dummy.c b/tests/plat/_dummy.c similarity index 100% rename from plat/qemuppc/tests/_dummy.c rename to tests/plat/_dummy.c diff --git a/plat/qemuppc/tests/brk_c.c b/tests/plat/brk_c.c similarity index 100% rename from plat/qemuppc/tests/brk_c.c rename to tests/plat/brk_c.c diff --git a/tests/plat/build.lua b/tests/plat/build.lua new file mode 100644 index 000000000..23685ba40 --- /dev/null +++ b/tests/plat/build.lua @@ -0,0 +1,57 @@ +include("plat/build.lua") + +definerule("plat_testsuite", + { + plat = { type="string" }, + method = { type="string" }, + }, + function(e) + -- Remember this is executed from the caller's directory; local + -- target names will resolve there. + local testfiles = filenamesof( + "tests/plat/*.c", + "tests/plat/*.e", + "tests/plat/*.p" + ) + + local tests = {} + for _, f in ipairs(testfiles) do + local fs = replace(basename(f), "%..$", "") + local _, _, lang = fs:find("_(.)$") + if not lang then + lang = "e" + end + + local bin = ackprogram { + name = fs.."_bin", + srcs = { f }, + deps = { "tests/plat/lib+lib" }, + vars = { + plat = e.plat, + lang = lang, + ackcflags = "-O0" + } + } + + tests[#tests+1] = normalrule { + name = fs, + outleaves = { "stamp" }, + ins = { + bin, + "tests/plat/testdriver.sh" + }, + commands = { + "%{ins[2]} "..e.method.." %{ins[1]} 5", + "touch %{outs}" + } + } + end + + return normalrule { + name = e.name, + outleaves = { "stamp" }, + ins = tests, + commands = { "touch %{outs}" } + } + end +) \ No newline at end of file diff --git a/plat/qemuppc/tests/calloc_c.c b/tests/plat/calloc_c.c similarity index 100% rename from plat/qemuppc/tests/calloc_c.c rename to tests/plat/calloc_c.c diff --git a/plat/qemuppc/tests/csa_e.c b/tests/plat/csa_e.c similarity index 100% rename from plat/qemuppc/tests/csa_e.c rename to tests/plat/csa_e.c diff --git a/plat/qemuppc/tests/csb_e.c b/tests/plat/csb_e.c similarity index 100% rename from plat/qemuppc/tests/csb_e.c rename to tests/plat/csb_e.c diff --git a/plat/qemuppc/tests/doublecmp_e.c b/tests/plat/doublecmp_e.c similarity index 100% rename from plat/qemuppc/tests/doublecmp_e.c rename to tests/plat/doublecmp_e.c diff --git a/plat/qemuppc/tests/from_d_to_si_e.c b/tests/plat/from_d_to_si_e.c similarity index 100% rename from plat/qemuppc/tests/from_d_to_si_e.c rename to tests/plat/from_d_to_si_e.c diff --git a/plat/qemuppc/tests/from_d_to_ui_e.c b/tests/plat/from_d_to_ui_e.c similarity index 100% rename from plat/qemuppc/tests/from_d_to_ui_e.c rename to tests/plat/from_d_to_ui_e.c diff --git a/plat/qemuppc/tests/from_si_to_d_e.c b/tests/plat/from_si_to_d_e.c similarity index 100% rename from plat/qemuppc/tests/from_si_to_d_e.c rename to tests/plat/from_si_to_d_e.c diff --git a/plat/qemuppc/tests/from_ui_to_d_e.c b/tests/plat/from_ui_to_d_e.c similarity index 100% rename from plat/qemuppc/tests/from_ui_to_d_e.c rename to tests/plat/from_ui_to_d_e.c diff --git a/plat/qemuppc/tests/inn_e.e b/tests/plat/inn_e.e similarity index 100% rename from plat/qemuppc/tests/inn_e.e rename to tests/plat/inn_e.e diff --git a/plat/qemuppc/tests/intadd_e.c b/tests/plat/intadd_e.c similarity index 100% rename from plat/qemuppc/tests/intadd_e.c rename to tests/plat/intadd_e.c diff --git a/plat/qemuppc/tests/intcmp_e.c b/tests/plat/intcmp_e.c similarity index 100% rename from plat/qemuppc/tests/intcmp_e.c rename to tests/plat/intcmp_e.c diff --git a/plat/qemuppc/tests/intdiv_e.c b/tests/plat/intdiv_e.c similarity index 100% rename from plat/qemuppc/tests/intdiv_e.c rename to tests/plat/intdiv_e.c diff --git a/plat/qemuppc/tests/intrem_e.c b/tests/plat/intrem_e.c similarity index 100% rename from plat/qemuppc/tests/intrem_e.c rename to tests/plat/intrem_e.c diff --git a/plat/qemuppc/tests/intshift_e.c b/tests/plat/intshift_e.c similarity index 100% rename from plat/qemuppc/tests/intshift_e.c rename to tests/plat/intshift_e.c diff --git a/plat/qemuppc/tests/intsub_e.c b/tests/plat/intsub_e.c similarity index 100% rename from plat/qemuppc/tests/intsub_e.c rename to tests/plat/intsub_e.c diff --git a/plat/qemuppc/tests/lib/build.lua b/tests/plat/lib/build.lua similarity index 100% rename from plat/qemuppc/tests/lib/build.lua rename to tests/plat/lib/build.lua diff --git a/plat/qemuppc/tests/lib/test.c b/tests/plat/lib/test.c similarity index 100% rename from plat/qemuppc/tests/lib/test.c rename to tests/plat/lib/test.c diff --git a/plat/qemuppc/tests/lib/test.h b/tests/plat/lib/test.h similarity index 100% rename from plat/qemuppc/tests/lib/test.h rename to tests/plat/lib/test.h diff --git a/plat/qemuppc/tests/newdispose_p.p b/tests/plat/newdispose_p.p similarity index 100% rename from plat/qemuppc/tests/newdispose_p.p rename to tests/plat/newdispose_p.p diff --git a/plat/qemuppc/tests/testdriver.sh b/tests/plat/testdriver.sh similarity index 100% rename from plat/qemuppc/tests/testdriver.sh rename to tests/plat/testdriver.sh From 8a58614aefa70c0805186d3c08a80876173c57a2 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 11:23:25 +0100 Subject: [PATCH 221/230] Rework the tests to run on pc86; lots of test fixes for the brk() test, which was nearly useless; lots of fixes to qemuppc and pc86 sbrk(), which was broken; change the pc86 console to echo output to the serial port (needed for running tests on qemu). --- .travis.yml | 1 + build.lua | 1 + plat/pc86/boot.s | 11 +++++++---- plat/pc86/include/unistd.h | 1 + plat/pc86/libsys/brk.c | 22 +++++++++++++++++++--- plat/pc86/tests/build.lua | 7 +++++++ plat/qemuppc/libsys/brk.c | 17 +++++++++++++++-- tests/plat/_dummy.c | 1 + tests/plat/brk_c.c | 32 +++++++++++++++++++++++++++----- tests/plat/build.lua | 9 ++++++++- tests/plat/from_d_to_si_e.c | 9 +++++---- tests/plat/from_d_to_ui_e.c | 5 +++-- tests/plat/from_si_to_d_e.c | 9 +++++---- tests/plat/from_ui_to_d_e.c | 5 +++-- tests/plat/inn_e.e | 34 +++++++++++++++++++++------------- tests/plat/intshift_e.c | 9 +++++---- tests/plat/intsub_e.c | 7 ++++--- tests/plat/lib/build.lua | 1 - tests/plat/lib/test.c | 2 +- tests/plat/lib/test.h | 2 +- tests/plat/testdriver.sh | 25 ++++++++++++++++++++----- 21 files changed, 155 insertions(+), 55 deletions(-) create mode 100644 plat/pc86/tests/build.lua diff --git a/.travis.yml b/.travis.yml index c6e2f5913..9db308dea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ addons: packages: - ed - openbios-ppc + - qemu-system-i386 git: depth: 10 diff --git a/build.lua b/build.lua index cc550cb9e..584449834 100644 --- a/build.lua +++ b/build.lua @@ -15,6 +15,7 @@ vars.plats = { } vars.plats_with_tests = { "qemuppc", + "pc86", } local plat_packages = {} diff --git a/plat/pc86/boot.s b/plat/pc86/boot.s index 534809697..51b288e75 100644 --- a/plat/pc86/boot.s +++ b/plat/pc86/boot.s @@ -23,7 +23,7 @@ ! If you ever need to change the boot code, this needs adjusting. I recommend ! a hex editor. -PADDING = 0xB7 +PADDING = 0xB3 ! Some definitions. @@ -271,9 +271,12 @@ finished: ! Push standard parameters onto the stack and go. - push envp ! envp - push argv ! argv - push 1 ! argc + mov ax, envp + push ax + mov ax, argv + push ax + mov ax, 1 + push ax call __m_a_i_n ! fall through into the exit routine. diff --git a/plat/pc86/include/unistd.h b/plat/pc86/include/unistd.h index ea4f51c0f..174c43ad0 100644 --- a/plat/pc86/include/unistd.h +++ b/plat/pc86/include/unistd.h @@ -37,6 +37,7 @@ extern char** environ; extern void _exit(int); extern pid_t getpid(void); +extern int brk(void* addr); extern void* sbrk(int increment); extern int isatty(int d); extern off_t lseek(int fildes, off_t offset, int whence); diff --git a/plat/pc86/libsys/brk.c b/plat/pc86/libsys/brk.c index 952a9c747..293703234 100644 --- a/plat/pc86/libsys/brk.c +++ b/plat/pc86/libsys/brk.c @@ -22,7 +22,10 @@ int brk(void* newend) if ((p > (&dummy - STACK_BUFFER)) || (p < _end)) + { + errno = ENOMEM; return -1; + } current = p; return 0; @@ -31,13 +34,26 @@ int brk(void* newend) void* sbrk(int increment) { char* old; - + char* new; + if (increment == 0) return current; old = current; - if (brk(old + increment) < 0) - return OUT_OF_MEMORY; + + new = old + increment; + + if ((increment > 0) && (new <= old)) + goto out_of_memory; + else if ((increment < 0) && (new >= old)) + goto out_of_memory; + + if (brk(new) < 0) + goto out_of_memory; return old; + +out_of_memory: + errno = ENOMEM; + return OUT_OF_MEMORY; } diff --git a/plat/pc86/tests/build.lua b/plat/pc86/tests/build.lua new file mode 100644 index 000000000..fe871e450 --- /dev/null +++ b/plat/pc86/tests/build.lua @@ -0,0 +1,7 @@ +include("tests/plat/build.lua") + +plat_testsuite { + name = "tests", + plat = "pc86", + method = "qemu-system-i386" +} diff --git a/plat/qemuppc/libsys/brk.c b/plat/qemuppc/libsys/brk.c index 118bda3cf..7d49fa960 100644 --- a/plat/qemuppc/libsys/brk.c +++ b/plat/qemuppc/libsys/brk.c @@ -34,13 +34,26 @@ int brk(void* newend) void* sbrk(int increment) { char* old; + char* new; if (increment == 0) return current; old = current; - if (brk(old + increment) < 0) - return OUT_OF_MEMORY; + + new = old + increment; + + if ((increment > 0) && (new <= old)) + goto out_of_memory; + else if ((increment < 0) && (new >= old)) + goto out_of_memory; + + if (brk(new) < 0) + goto out_of_memory; return old; + +out_of_memory: + errno = ENOMEM; + return OUT_OF_MEMORY; } diff --git a/tests/plat/_dummy.c b/tests/plat/_dummy.c index 48104b5aa..a4693300f 100644 --- a/tests/plat/_dummy.c +++ b/tests/plat/_dummy.c @@ -6,3 +6,4 @@ void _m_a_i_n(void) ASSERT(0 == 0); finished(); } + diff --git a/tests/plat/brk_c.c b/tests/plat/brk_c.c index aa0f7ef99..9a07c7d3b 100644 --- a/tests/plat/brk_c.c +++ b/tests/plat/brk_c.c @@ -7,9 +7,11 @@ int main(int argc, const char* argv[]) { - void* p; + char* o; + char* p; - ASSERT(-1 == (intptr_t)brk((void*)0xffffffff)); + errno = 0; + ASSERT(-1 == brk((void*)-1)); ASSERT(ENOMEM == errno); p = sbrk(0); @@ -19,9 +21,29 @@ int main(int argc, const char* argv[]) ASSERT(p != sbrk(-8)); ASSERT(p == sbrk(0)); - /* We assume the test environment has less than 2GB of RAM. */ - ASSERT(-1 == (intptr_t)sbrk(INT_MAX)); - ASSERT(-1 == (intptr_t)sbrk(INT_MIN)); + errno = 0; + o = sbrk(INT_MAX); + if (o == (char*)-1) + ASSERT(ENOMEM == errno); + else + { + ASSERT(0 == errno); + p = sbrk(0); + ASSERT(p > o); + brk(o); + } + + errno = 0; + o = sbrk(INT_MIN); + if (o == (char*)-1) + ASSERT(ENOMEM == errno); + else + { + ASSERT(0 == errno); + p = sbrk(0); + ASSERT(p < o); + brk(o); + } finished(); } diff --git a/tests/plat/build.lua b/tests/plat/build.lua index 23685ba40..3873ed9a5 100644 --- a/tests/plat/build.lua +++ b/tests/plat/build.lua @@ -14,6 +14,13 @@ definerule("plat_testsuite", "tests/plat/*.p" ) + acklibrary { + name = "lib", + srcs = { "tests/plat/lib/test.c" }, + hdrs = { "tests/plat/lib/test.h" }, + vars = { plat = e.plat }, + } + local tests = {} for _, f in ipairs(testfiles) do local fs = replace(basename(f), "%..$", "") @@ -25,7 +32,7 @@ definerule("plat_testsuite", local bin = ackprogram { name = fs.."_bin", srcs = { f }, - deps = { "tests/plat/lib+lib" }, + deps = { "+lib" }, vars = { plat = e.plat, lang = lang, diff --git a/tests/plat/from_d_to_si_e.c b/tests/plat/from_d_to_si_e.c index 8c7e31c3e..7f51e6c5b 100644 --- a/tests/plat/from_d_to_si_e.c +++ b/tests/plat/from_d_to_si_e.c @@ -1,11 +1,12 @@ +#include #include "test.h" /* Constants in globals to defeat constant folding. */ double one = 1.0; double zero = 0.0; double minusone = -1.0; -double big = 2147483647.0; -double minusbig = -2147483648.0; +double big = (double)INT_MAX; +double minusbig = (double)INT_MIN; /* Bypasses the CRT, so there's no stdio or BSS initialisation. */ void _m_a_i_n(void) @@ -13,8 +14,8 @@ void _m_a_i_n(void) ASSERT((int)zero == 0); ASSERT((int)one == 1); ASSERT((int)minusone == -1); - ASSERT((int)big == 2147483647); - ASSERT((int)minusbig == -2147483648); + ASSERT((int)big == INT_MAX); + ASSERT((int)minusbig == INT_MIN); finished(); } \ No newline at end of file diff --git a/tests/plat/from_d_to_ui_e.c b/tests/plat/from_d_to_ui_e.c index b16667502..811780b87 100644 --- a/tests/plat/from_d_to_ui_e.c +++ b/tests/plat/from_d_to_ui_e.c @@ -1,16 +1,17 @@ +#include #include "test.h" /* Constants in globals to defeat constant folding. */ double one = 1.0; double zero = 0.0; -double big = 4294967295.0; +double big = (double)UINT_MAX; /* Bypasses the CRT, so there's no stdio or BSS initialisation. */ void _m_a_i_n(void) { ASSERT((unsigned int)zero == 0); ASSERT((unsigned int)one == 1); - ASSERT((unsigned int)big == 4294967295); + ASSERT((unsigned int)big == UINT_MAX); finished(); } \ No newline at end of file diff --git a/tests/plat/from_si_to_d_e.c b/tests/plat/from_si_to_d_e.c index e81c2f7c2..b6c7a25ba 100644 --- a/tests/plat/from_si_to_d_e.c +++ b/tests/plat/from_si_to_d_e.c @@ -1,11 +1,12 @@ +#include #include "test.h" /* Constants in globals to defeat constant folding. */ int one = 1; int zero = 0; int minusone = -1; -int big = 0x7fffffff; -int minusbig = -0x8000000; +int big = INT_MAX; +int minusbig = INT_MIN; /* Bypasses the CRT, so there's no stdio or BSS initialisation. */ void _m_a_i_n(void) @@ -13,8 +14,8 @@ void _m_a_i_n(void) ASSERT((double)zero == 0.0); ASSERT((double)one == 1.0); ASSERT((double)minusone == -1.0); - ASSERT((double)big == 2147483647.0); - /* ASSERT((double)minusbig == -2147483648.0); FIXME: fails for now */ + ASSERT((double)big == (double)INT_MAX); + /* ASSERT((double)minusbig == (double)INT_MIN); FIXME: fails for now */ finished(); } \ No newline at end of file diff --git a/tests/plat/from_ui_to_d_e.c b/tests/plat/from_ui_to_d_e.c index a3517b24c..b8e017c99 100644 --- a/tests/plat/from_ui_to_d_e.c +++ b/tests/plat/from_ui_to_d_e.c @@ -1,16 +1,17 @@ +#include #include "test.h" /* Constants in globals to defeat constant folding. */ unsigned int one_u = 1; unsigned int zero_u = 0; -unsigned int big_u = 0xffffffff; +unsigned int big_u = UINT_MAX; /* Bypasses the CRT, so there's no stdio or BSS initialisation. */ void _m_a_i_n(void) { ASSERT((double)zero_u == 0.0); ASSERT((double)one_u == 1.0); - ASSERT((double)big_u == 4294967295.0); + ASSERT((double)big_u == (double)UINT_MAX); finished(); } \ No newline at end of file diff --git a/tests/plat/inn_e.e b/tests/plat/inn_e.e index 4e53b35c5..7d27abf42 100644 --- a/tests/plat/inn_e.e +++ b/tests/plat/inn_e.e @@ -1,5 +1,5 @@ # - mes 2, 4, 4 + mes 2, EM_WSIZE, EM_PSIZE exp $_m_a_i_n pro $_m_a_i_n, 0 @@ -10,12 +10,12 @@ rom 0I1, 0I1, 0I1, 0I1 loe .1 loc 1 /* bit number */ - inn 4 + inn EM_WSIZE zeq *1 loc __LINE__ cal $fail - ass 4 + ass EM_WSIZE 1 /* Test existent bit */ @@ -24,12 +24,12 @@ rom 2I1, 0I1, 0I1, 0I1 loe .2 loc 1 /* bit number */ - inn 4 + inn EM_WSIZE zne *2 loc __LINE__ cal $fail - ass 4 + ass EM_WSIZE 2 /* Test non-existent high bit */ @@ -38,36 +38,44 @@ rom 0I1, 0I1, 0I1, 0I1 rom 0I1, 0I1, 0I1, 0I1 .31 - rom 33 /* to defeat constant folding */ + rom (EM_WSIZE*8)+1 /* to defeat constant folding */ lae .3 - loi 8 + loi EM_WSIZE*2 loe .31 /* bit number */ - inn 8 + inn EM_WSIZE*2 zeq *3 loc __LINE__ cal $fail - ass 4 + ass EM_WSIZE 3 /* Test existent high bit */ .4 +#if EM_WSIZE == 2 + rom 0I1, 0I1 + rom 2I1, 0I1 +#elif EM_WSIZE == 4 rom 0I1, 0I1, 0I1, 0I1 rom 2I1, 0I1, 0I1, 0I1 +#else + #error Unknown word size +#endif + .41 - rom 33 /* to defeat constant folding */ + rom (EM_WSIZE*8)+1 /* to defeat constant folding */ lae .4 - loi 8 + loi EM_WSIZE*2 loe .41 /* bit number */ - inn 8 + inn EM_WSIZE*2 zne *4 loc __LINE__ cal $fail - ass 4 + ass EM_WSIZE 4 cal $finished diff --git a/tests/plat/intshift_e.c b/tests/plat/intshift_e.c index dd280142c..3cc6d52f9 100644 --- a/tests/plat/intshift_e.c +++ b/tests/plat/intshift_e.c @@ -1,3 +1,4 @@ +#include #include "test.h" /* Constants in globals to defeat constant folding. */ @@ -25,8 +26,8 @@ void _m_a_i_n(void) ASSERT(((unsigned int)one >>(unsigned int)zero) == 1); ASSERT(((unsigned int)one >>(unsigned int)one) == 0); - ASSERT(((unsigned int)minusone>>(unsigned int)zero) == 0xffffffff); - ASSERT(((unsigned int)minusone>>(unsigned int)one) == 0x7fffffff); + ASSERT(((unsigned int)minusone>>(unsigned int)zero) == UINT_MAX); + ASSERT(((unsigned int)minusone>>(unsigned int)one) == (UINT_MAX>>1)); ASSERT((one <<0) == 1); ASSERT((one <<1) == 2); @@ -45,8 +46,8 @@ void _m_a_i_n(void) ASSERT(((unsigned int)one >>(unsigned int)0) == 1); ASSERT(((unsigned int)one >>(unsigned int)1) == 0); - ASSERT(((unsigned int)minusone>>(unsigned int)0) == 0xffffffff); - ASSERT(((unsigned int)minusone>>(unsigned int)1) == 0x7fffffff); + ASSERT(((unsigned int)minusone>>(unsigned int)0) == UINT_MAX); + ASSERT(((unsigned int)minusone>>(unsigned int)1) == (UINT_MAX>>1)); finished(); } \ No newline at end of file diff --git a/tests/plat/intsub_e.c b/tests/plat/intsub_e.c index 72ba0ff08..d8f67d3a3 100644 --- a/tests/plat/intsub_e.c +++ b/tests/plat/intsub_e.c @@ -1,3 +1,4 @@ +#include #include "test.h" /* Constants in globals to defeat constant folding. */ @@ -19,13 +20,13 @@ void _m_a_i_n(void) ASSERT((1 - two) == -1); ASSERT(((unsigned int)two - (unsigned int)one) == 1); - ASSERT(((unsigned int)one - (unsigned int)two) == 0xffffffff); + ASSERT(((unsigned int)one - (unsigned int)two) == UINT_MAX); ASSERT(((unsigned int)two - (unsigned int)1) == 1); - ASSERT(((unsigned int)one - (unsigned int)2) == 0xffffffff); + ASSERT(((unsigned int)one - (unsigned int)2) == UINT_MAX); ASSERT(((unsigned int)2 - (unsigned int)one) == 1); - ASSERT(((unsigned int)1 - (unsigned int)two) == 0xffffffff); + ASSERT(((unsigned int)1 - (unsigned int)two) == UINT_MAX); finished(); } \ No newline at end of file diff --git a/tests/plat/lib/build.lua b/tests/plat/lib/build.lua index cb6b5cbea..be9928c84 100644 --- a/tests/plat/lib/build.lua +++ b/tests/plat/lib/build.lua @@ -4,5 +4,4 @@ acklibrary { name = "lib", srcs = { "./test.c" }, hdrs = { "./test.h" }, - vars = { plat = "qemuppc" } } diff --git a/tests/plat/lib/test.c b/tests/plat/lib/test.c index 33d72f3ce..d05417326 100644 --- a/tests/plat/lib/test.c +++ b/tests/plat/lib/test.c @@ -25,7 +25,7 @@ void writehex(uint32_t code) void fail(uint32_t code) { - write(1, "@@FAIL on line 0x", 7); + write(1, "@@FAIL 0x", 10); writehex(code); write(1, "\n", 1); } diff --git a/tests/plat/lib/test.h b/tests/plat/lib/test.h index 96537a2cb..db16506f9 100644 --- a/tests/plat/lib/test.h +++ b/tests/plat/lib/test.h @@ -9,6 +9,6 @@ extern void writehex(uint32_t code); extern void fail(uint32_t code); #define ASSERT(condition) \ - if (!(condition)) fail(__LINE__) + do { if (!(condition)) fail(__LINE__); } while(0) #endif diff --git a/tests/plat/testdriver.sh b/tests/plat/testdriver.sh index 3424e9626..29d9063eb 100755 --- a/tests/plat/testdriver.sh +++ b/tests/plat/testdriver.sh @@ -1,5 +1,5 @@ #!/bin/sh -qemu=$1 +method=$1 img=$2 timeout=$3 @@ -13,10 +13,25 @@ trap "rm -f $result" EXIT pidfile=/tmp/$$.testdriver.pid trap "rm -f $pidfile" EXIT -( $qemu -nographic -kernel $img 2>&1 & echo $! > $pidfile ) \ - | tee $result \ - | ( timeout $timeout grep -l -q @@FINISHED ; echo ) \ - | ( read dummy && kill $(cat $pidfile) ) +case $method in + qemu-system-*) + if ! hash $method 2>/dev/null; then + echo "Warning: $method not installed, skipping test" + exit 0 + fi + + case $method in + qemu-system-i386) img="-drive file=$img,if=floppy,format=raw" ;; + qemu-system-ppc) img="-kernel $img" ;; + esac + + ( $method -nographic $img 2>&1 & echo $! > $pidfile ) \ + | tee $result \ + | ( timeout $timeout grep -l -q @@FINISHED ; echo ) \ + | ( read dummy && kill $(cat $pidfile) ) + + ;; +esac ( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1 exit 0 \ No newline at end of file From 90e3d45c696130a99a82a889030079db84edd12b Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 11:29:57 +0100 Subject: [PATCH 222/230] Travis only whitelists the -x86 version of qemu. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9db308dea..a73c139d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ addons: packages: - ed - openbios-ppc - - qemu-system-i386 + - qemu-system-x86 git: depth: 10 From cf33bd6cc46adf0abd6004898305fb87a4e3ed1d Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 11:56:17 +0100 Subject: [PATCH 223/230] Enable tests for linuxppc via qemu-ppc. --- build.lua | 1 + plat/linux/libsys/sbrk.c | 21 +++++++++++++-------- plat/linuxppc/tests/build.lua | 7 +++++++ tests/plat/brk_c.c | 4 ---- tests/plat/lib/test.c | 1 + tests/plat/testdriver.sh | 14 ++++++++++++++ 6 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 plat/linuxppc/tests/build.lua diff --git a/build.lua b/build.lua index 584449834..2b5ec62a0 100644 --- a/build.lua +++ b/build.lua @@ -14,6 +14,7 @@ vars.plats = { "rpi", } vars.plats_with_tests = { + "linuxppc", "qemuppc", "pc86", } diff --git a/plat/linux/libsys/sbrk.c b/plat/linux/libsys/sbrk.c index 7aeeecb86..f790a17cb 100644 --- a/plat/linux/libsys/sbrk.c +++ b/plat/linux/libsys/sbrk.c @@ -26,7 +26,6 @@ void* sbrk(int increment) { char* old; char* new; - char* actual; if (!current) current = (char*) _syscall(__NR_brk, 0, 0, 0); @@ -35,15 +34,21 @@ void* sbrk(int increment) return current; old = current; + new = old + increment; - actual = (char*) _syscall(__NR_brk, (quad) new, 0, 0); - if (actual < new) - { - errno = ENOMEM; - return OUT_OF_MEMORY; - } + if ((increment > 0) && (new <= old)) + goto out_of_memory; + else if ((increment < 0) && (new >= old)) + goto out_of_memory; + + if (brk(new) < 0) + goto out_of_memory; - current = actual; return old; + +out_of_memory: + errno = ENOMEM; + return OUT_OF_MEMORY; } + diff --git a/plat/linuxppc/tests/build.lua b/plat/linuxppc/tests/build.lua new file mode 100644 index 000000000..7601ab0be --- /dev/null +++ b/plat/linuxppc/tests/build.lua @@ -0,0 +1,7 @@ +include("tests/plat/build.lua") + +plat_testsuite { + name = "tests", + plat = "linuxppc", + method = "qemu-ppc" +} diff --git a/tests/plat/brk_c.c b/tests/plat/brk_c.c index 9a07c7d3b..434cec50b 100644 --- a/tests/plat/brk_c.c +++ b/tests/plat/brk_c.c @@ -10,10 +10,6 @@ int main(int argc, const char* argv[]) char* o; char* p; - errno = 0; - ASSERT(-1 == brk((void*)-1)); - ASSERT(ENOMEM == errno); - p = sbrk(0); ASSERT(p == sbrk(0)); ASSERT(p == sbrk(8)); diff --git a/tests/plat/lib/test.c b/tests/plat/lib/test.c index d05417326..df00e1089 100644 --- a/tests/plat/lib/test.c +++ b/tests/plat/lib/test.c @@ -6,6 +6,7 @@ void finished(void) { static const char s[] = "@@FINISHED\n"; write(1, s, sizeof(s)); + _exit(0); } void writehex(uint32_t code) diff --git a/tests/plat/testdriver.sh b/tests/plat/testdriver.sh index 29d9063eb..f5ca187a3 100755 --- a/tests/plat/testdriver.sh +++ b/tests/plat/testdriver.sh @@ -31,6 +31,20 @@ case $method in | ( read dummy && kill $(cat $pidfile) ) ;; + + qemu-*) + if ! hash $method 2>/dev/null; then + echo "Warning: $method not installed, skipping test" + exit 0 + fi + + $method $img > $result + ;; + + *) + echo "Error: $method not known by testdriver" + exit 1 + ;; esac ( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1 From 98c761d5c03ef07aa9fd2611fba090ce50fcb6e3 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 11:58:02 +0100 Subject: [PATCH 224/230] Enable tests for linux386 via qemu-i386. --- build.lua | 1 + plat/linux386/tests/build.lua | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 plat/linux386/tests/build.lua diff --git a/build.lua b/build.lua index 2b5ec62a0..607a83a3b 100644 --- a/build.lua +++ b/build.lua @@ -14,6 +14,7 @@ vars.plats = { "rpi", } vars.plats_with_tests = { + "linux386", "linuxppc", "qemuppc", "pc86", diff --git a/plat/linux386/tests/build.lua b/plat/linux386/tests/build.lua new file mode 100644 index 000000000..afd12fdce --- /dev/null +++ b/plat/linux386/tests/build.lua @@ -0,0 +1,7 @@ +include("tests/plat/build.lua") + +plat_testsuite { + name = "tests", + plat = "linux386", + method = "qemu-i386" +} From dff67447fed9ae242a60207940921dd3abc1e784 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 12:00:59 +0100 Subject: [PATCH 225/230] qmu-system-x86 isn't in Travis' repository? Let's try qemu-user. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a73c139d8..6f2e25efd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ addons: packages: - ed - openbios-ppc - - qemu-system-x86 + - qemu-user git: depth: 10 From a9a0b37b1491ad9691206c01f0c359aeb2751c57 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 12:07:08 +0100 Subject: [PATCH 226/230] Plats which use aelflod need to depend on it. --- plat/linux386/build-tools.lua | 1 + plat/linux68k/build-tools.lua | 1 + plat/linuxppc/build-tools.lua | 1 + 3 files changed, 3 insertions(+) diff --git a/plat/linux386/build-tools.lua b/plat/linux386/build-tools.lua index d711f85fd..31b8a7388 100644 --- a/plat/linux386/build-tools.lua +++ b/plat/linux386/build-tools.lua @@ -16,6 +16,7 @@ return installable { ["$(PLATDEP)/linux386/as"] = "+as", ["$(PLATDEP)/linux386/ncg"] = "+ncg", ["$(PLATIND)/descr/linux386"] = "./descr", + "util/amisc+aelflod-pkg", "util/opt+pkg", } } diff --git a/plat/linux68k/build-tools.lua b/plat/linux68k/build-tools.lua index 944e57f47..03d659a15 100644 --- a/plat/linux68k/build-tools.lua +++ b/plat/linux68k/build-tools.lua @@ -16,6 +16,7 @@ return installable { ["$(PLATDEP)/linux68k/as"] = "+as", ["$(PLATDEP)/linux68k/ncg"] = "+ncg", ["$(PLATIND)/descr/linux68k"] = "./descr", + "util/amisc+aelflod-pkg", "util/opt+pkg", } } diff --git a/plat/linuxppc/build-tools.lua b/plat/linuxppc/build-tools.lua index ce1a163d8..e48524cc9 100644 --- a/plat/linuxppc/build-tools.lua +++ b/plat/linuxppc/build-tools.lua @@ -28,6 +28,7 @@ return installable { ["$(PLATDEP)/linuxppc/mcg"] = "+mcg", ["$(PLATDEP)/linuxppc/top"] = "+top", ["$(PLATIND)/descr/linuxppc"] = "./descr", + "util/amisc+aelflod-pkg", "util/opt+pkg", } } From a596973f283ae7abba642ec4e246410fbe6d3442 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 12:52:09 +0100 Subject: [PATCH 227/230] OSX doesn't work; let's not bother building it. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6f2e25efd..765b5cea1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ matrix: include: - os: linux - - os: osx addons: apt: From 2dc083f436cf611f743440982cd45c3080868ba5 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 12:53:36 +0100 Subject: [PATCH 228/230] Use command -v rather than hash to detect commands (command is Posix and works on OpenBSD). --- tests/plat/testdriver.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/plat/testdriver.sh b/tests/plat/testdriver.sh index f5ca187a3..1c57ee163 100755 --- a/tests/plat/testdriver.sh +++ b/tests/plat/testdriver.sh @@ -15,7 +15,7 @@ trap "rm -f $pidfile" EXIT case $method in qemu-system-*) - if ! hash $method 2>/dev/null; then + if ! command -v $method 2>/dev/null; then echo "Warning: $method not installed, skipping test" exit 0 fi @@ -33,7 +33,7 @@ case $method in ;; qemu-*) - if ! hash $method 2>/dev/null; then + if ! command -v $method 2>/dev/null; then echo "Warning: $method not installed, skipping test" exit 0 fi @@ -48,4 +48,4 @@ case $method in esac ( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1 -exit 0 \ No newline at end of file +exit 0 From 4633ca0886abd770879b50d22b746cd85f0d5ae2 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 19:25:02 +0100 Subject: [PATCH 229/230] Updated the README. --- README | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/README b/README index 701581f17..830c86cfc 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ =================================== © 1987-2005 Vrije Universiteit, Amsterdam - 2016-08-02 + 2016-11-26 INTRODUCTION @@ -19,6 +19,7 @@ probably broken. However, what's there should be sufficient to get things done and to evaluate how the full 6.1 release should work. + SUPPORT ======= @@ -31,10 +32,12 @@ Platforms: pc86 produces bootable floppy disk images for 8086 PCs linux386 produces ELF executables for PC Linux systems linux68k produces ELF executables for m68020 Linux systems +linuxppc produces ELF executables for PowerPC Linux systems cpm produces i80 CP/M .COM files rpi produces Raspberry Pi GPU binaries + INSTALLATION ============ @@ -55,6 +58,11 @@ Requirements: - (optionally) ninja; if you've got this, this will be autodetected and give you faster builds. +- (optionally) the qemu suite: if you have this installed, the build system + will detect it automatically and run the test suites for the supported + architectures. Get both the qemu-system-* platform emulators and the qemu-* + userland emulators (only works on Linux). + - about 40MB free in /tmp (or some other temporary directory). - about 6MB in the target directory. @@ -89,6 +97,7 @@ Instructions: The ACK should now be ready to use. + USAGE ===== @@ -155,6 +164,8 @@ There are some things you should be aware of. interpreter and the assembler-linkers. Only some of it builds. Look for build.lua files. + + DISCLAIMER ========== @@ -177,6 +188,6 @@ You can find the mailing list on the project's web site: Please enjoy. -David Given (dtrg on Sourceforge) +David Given (davidgiven on Github) dg@cowlark.com -2016-08-02 +2016-11-26 From 4f446467c867e25a50a340a89dbc59cb8b8063f2 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 26 Nov 2016 21:50:56 +0100 Subject: [PATCH 230/230] Suppress spurious message when testdriver probes for a testing method. --- tests/plat/testdriver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/plat/testdriver.sh b/tests/plat/testdriver.sh index 1c57ee163..272c6b2b7 100755 --- a/tests/plat/testdriver.sh +++ b/tests/plat/testdriver.sh @@ -15,7 +15,7 @@ trap "rm -f $pidfile" EXIT case $method in qemu-system-*) - if ! command -v $method 2>/dev/null; then + if ! command -v $method >/dev/null 2>&1 ; then echo "Warning: $method not installed, skipping test" exit 0 fi @@ -33,7 +33,7 @@ case $method in ;; qemu-*) - if ! command -v $method 2>/dev/null; then + if ! command -v $method >/dev/null 2>&1 ; then echo "Warning: $method not installed, skipping test" exit 0 fi