diff --git a/Test/Expect/stest121.pasm b/Test/Expect/stest121.pasm index c23eec73c..3b470b76e 100644 --- a/Test/Expect/stest121.pasm +++ b/Test/Expect/stest121.pasm @@ -14,12 +14,6 @@ result1 COG_BSS_START fit 496 org COG_BSS_START -_var01 - res 1 -_var02 - res 1 -_var03 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest155.pasm b/Test/Expect/stest155.pasm index f0de34c9c..f9a0b8d3a 100644 --- a/Test/Expect/stest155.pasm +++ b/Test/Expect/stest155.pasm @@ -32,10 +32,6 @@ COG_BSS_START _dat_ byte $00, $00, $00, $00, $00, $00, $00, $00 org COG_BSS_START -_var01 - res 1 -_var02 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest191.pasm b/Test/Expect/stest191.pasm index 324117b0b..b6a88ab1e 100644 --- a/Test/Expect/stest191.pasm +++ b/Test/Expect/stest191.pasm @@ -48,10 +48,6 @@ _var01 res 1 _var02 res 1 -_var03 - res 1 -_var04 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest229.pasm b/Test/Expect/stest229.pasm index 9d7736543..59a722a88 100644 --- a/Test/Expect/stest229.pasm +++ b/Test/Expect/stest229.pasm @@ -13,12 +13,6 @@ _show_ret COG_BSS_START fit 496 org COG_BSS_START -_var01 - res 1 -_var02 - res 1 -_var03 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest230.pasm b/Test/Expect/stest230.pasm index f15021e80..da182fdb1 100644 --- a/Test/Expect/stest230.pasm +++ b/Test/Expect/stest230.pasm @@ -12,13 +12,9 @@ _show_ret ret _main - mov _main_s__0001, #1 - mov _main_s__0001_01, #2 - mov _main_s__0001_02, #3 - mov arg01, _main_s__0001 - mov arg02, _main_s__0001_01 - mov arg03, _main_s__0001_02 - call #_show + mov outa, #1 + mov outb, #2 + mov ina, #3 mov result1, #0 _main_ret ret @@ -28,18 +24,6 @@ result1 COG_BSS_START fit 496 org COG_BSS_START -_main_s__0001 - res 1 -_main_s__0001_01 - res 1 -_main_s__0001_02 - res 1 -_var01 - res 1 -_var02 - res 1 -_var03 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest233.pasm b/Test/Expect/stest233.pasm index 5e082b43b..30f292fbb 100644 --- a/Test/Expect/stest233.pasm +++ b/Test/Expect/stest233.pasm @@ -14,10 +14,6 @@ result1 COG_BSS_START fit 496 org COG_BSS_START -_var01 - res 1 -_var02 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest249.pasm b/Test/Expect/stest249.pasm index 63defe364..7bcb5838b 100644 --- a/Test/Expect/stest249.pasm +++ b/Test/Expect/stest249.pasm @@ -5,23 +5,19 @@ dat entry _insertstr + add arg01, arg03 mov result1, arg01 - add result1, arg03 mov result2, arg02 _insertstr_ret ret _main - mov _main_p_0007, #1 - mov _main_p_0007_01, #2 - mov arg02, _main_p_0007_01 - mov arg01, _main_p_0007 + mov arg01, #1 + mov arg02, #2 mov arg03, #99 call #_insertstr - mov _main_q_0008, result1 - mov _main_q_0008_01, result2 - mov outa, _main_p_0007 - mov outb, _main_q_0008 + mov outa, #1 + mov outb, result1 _main_ret ret @@ -32,18 +28,6 @@ result2 COG_BSS_START fit 496 org COG_BSS_START -_main_p_0007 - res 1 -_main_p_0007_01 - res 1 -_main_q_0008 - res 1 -_main_q_0008_01 - res 1 -_var01 - res 1 -_var02 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest258.pasm b/Test/Expect/stest258.pasm index a69872bb6..d4e3e9ea9 100644 --- a/Test/Expect/stest258.pasm +++ b/Test/Expect/stest258.pasm @@ -27,10 +27,6 @@ result2 COG_BSS_START fit 496 org COG_BSS_START -_var01 - res 1 -_var02 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest275.pasm b/Test/Expect/stest275.pasm index 10ca82389..c5d79cc9b 100644 --- a/Test/Expect/stest275.pasm +++ b/Test/Expect/stest275.pasm @@ -21,13 +21,13 @@ _getit2_ret _getitA - rdlong _var05, arg01 - rdlong result1, _var05 - add _var05, #4 - rdlong result2, _var05 - rdlong _var06, arg01 - add _var06, #8 - wrlong _var06, arg01 + rdlong result2, arg01 + rdlong result1, result2 + add result2, #4 + rdlong result2, result2 + rdlong _var01, arg01 + add _var01, #8 + wrlong _var01, arg01 _getitA_ret ret @@ -40,16 +40,6 @@ COG_BSS_START org COG_BSS_START _var01 res 1 -_var02 - res 1 -_var03 - res 1 -_var04 - res 1 -_var05 - res 1 -_var06 - res 1 arg01 res 1 fit 496 diff --git a/Test/Expect/stest278.pasm b/Test/Expect/stest278.pasm index b4db2bba8..a8604693f 100644 --- a/Test/Expect/stest278.pasm +++ b/Test/Expect/stest278.pasm @@ -5,25 +5,11 @@ dat entry _bump1 - rdlong arg04, ptr__dat__ - add ptr__dat__, #4 - rdlong arg03, ptr__dat__ - mov result1, arg04 - mov result2, arg03 - sub ptr__dat__, #4 - add arg04, #1 wc - addx arg03, #0 - wrlong arg04, ptr__dat__ - add ptr__dat__, #4 - wrlong arg03, ptr__dat__ - sub ptr__dat__, #4 -_bump1_ret - ret - -_bump2 rdlong result1, ptr__dat__ add ptr__dat__, #4 rdlong result2, ptr__dat__ + mov _var01, result1 + mov _var02, result2 sub ptr__dat__, #4 add result1, #1 wc addx result2, #0 @@ -31,10 +17,13 @@ _bump2 add ptr__dat__, #4 wrlong result2, ptr__dat__ sub ptr__dat__, #4 -_bump2_ret + mov result1, _var01 + mov result2, _var02 +_bump1_ret ret _bump3 +_bump2 rdlong result1, ptr__dat__ add ptr__dat__, #4 rdlong result2, ptr__dat__ @@ -45,9 +34,11 @@ _bump3 add ptr__dat__, #4 wrlong result2, ptr__dat__ sub ptr__dat__, #4 +_bump2_ret _bump3_ret ret + ptr__dat__ long @@@_dat_ result1 @@ -64,10 +55,6 @@ _var01 res 1 _var02 res 1 -_var03 - res 1 -_var04 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest286.pasm b/Test/Expect/stest286.pasm index 46c9b4fa8..bd076b73e 100644 --- a/Test/Expect/stest286.pasm +++ b/Test/Expect/stest286.pasm @@ -22,10 +22,6 @@ result2 COG_BSS_START fit 496 org COG_BSS_START -_var01 - res 1 -_var02 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest315.pasm b/Test/Expect/stest315.pasm index f6eb3aa6d..e41339671 100644 --- a/Test/Expect/stest315.pasm +++ b/Test/Expect/stest315.pasm @@ -4,43 +4,33 @@ dat org 0 entry +_zcheck2 _zcheck1 cmp arg01, #0 wz if_ne mov result1, arg02 - if_ne mov _var06, arg03 + if_ne mov result2, arg03 if_e mov result1, arg04 - if_e mov _var06, arg05 - mov result2, _var06 + if_e mov result2, arg05 _zcheck1_ret - ret - -_zcheck2 - cmp arg01, #0 wz - if_ne mov result1, arg02 - if_ne mov _var06, arg03 - if_e mov result1, arg04 - if_e mov _var06, arg05 - mov result2, _var06 _zcheck2_ret ret + _zcheck3 cmp arg01, #0 wz if_ne mov result1, #0 - if_ne mov _var04, #0 + if_ne mov result2, #0 if_e mov result1, arg04 - if_e mov _var04, arg05 - mov result2, _var04 + if_e mov result2, arg05 _zcheck3_ret ret _zcheck4 cmp arg01, #0 wz if_ne mov result1, arg02 - if_ne mov _var04, arg03 + if_ne mov result2, arg03 if_e mov result1, #0 - if_e mov _var04, #0 - mov result2, _var04 + if_e mov result2, #0 _zcheck4_ret ret @@ -51,20 +41,6 @@ result2 COG_BSS_START fit 496 org COG_BSS_START -_var01 - res 1 -_var02 - res 1 -_var03 - res 1 -_var04 - res 1 -_var05 - res 1 -_var06 - res 1 -_var07 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest317.p2asm b/Test/Expect/stest317.p2asm index 98007b71c..84c382076 100644 --- a/Test/Expect/stest317.p2asm +++ b/Test/Expect/stest317.p2asm @@ -30,12 +30,10 @@ _foo mov objptr, foo_tmp002_ call foo_tmp003_ mov objptr, foo_tmp005_ - mov _foo_y, result1 - mov _foo_y_01, result2 - mov result1, _foo_y_01 add _foo_x, #4 - rdlong result2, _foo_x - add result1, result2 + rdlong foo_tmp002_, _foo_x + add result2, foo_tmp002_ + mov result1, result2 _foo_ret ret builtin_bytefill_ @@ -72,10 +70,6 @@ objmem org COG_BSS_START _foo_x res 1 -_foo_y - res 1 -_foo_y_01 - res 1 arg01 res 1 foo_tmp002_ diff --git a/Test/Expect/stest318.p2asm b/Test/Expect/stest318.p2asm index a3eb904ab..eb3bc1e84 100644 --- a/Test/Expect/stest318.p2asm +++ b/Test/Expect/stest318.p2asm @@ -44,14 +44,6 @@ COG_BSS_START fit 480 orgh org COG_BSS_START -_var01 - res 1 -_var02 - res 1 -_var03 - res 1 -_var04 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest319.p2asm b/Test/Expect/stest319.p2asm index e5637b89e..8f3e79b1d 100644 --- a/Test/Expect/stest319.p2asm +++ b/Test/Expect/stest319.p2asm @@ -64,10 +64,6 @@ _dat_ objmem long 0[0] org COG_BSS_START -_var01 - res 1 -_var02 - res 1 arg01 res 1 arg02 diff --git a/Test/Expect/stest322.pasm b/Test/Expect/stest322.pasm new file mode 100644 index 000000000..99aa66f54 --- /dev/null +++ b/Test/Expect/stest322.pasm @@ -0,0 +1,55 @@ +pub main + coginit(0, @entry, 0) +dat + org 0 +entry + +_use + add arg01, arg02 + add arg01, arg03 + mov result1, arg01 +_use_ret + ret + +_sum + mov sum_tmp002_, arg01 + mov _sum_s_0001, #0 + mov arg01, sum_tmp002_ + mov arg02, #1 + mov arg03, #2 + call #_use + add _sum_s_0001, result1 + mov arg01, sum_tmp002_ + mov arg02, #3 + mov arg03, #4 + call #_use + add _sum_s_0001, result1 + mov arg01, sum_tmp002_ + mov arg02, #5 + mov arg03, #6 + call #_use + add _sum_s_0001, result1 + mov arg01, sum_tmp002_ + mov arg02, #7 + mov arg03, #8 + call #_use + add result1, _sum_s_0001 +_sum_ret + ret + +result1 + long 0 +COG_BSS_START + fit 496 + org COG_BSS_START +_sum_s_0001 + res 1 +arg01 + res 1 +arg02 + res 1 +arg03 + res 1 +sum_tmp002_ + res 1 + fit 496 diff --git a/Test/stest322.c b/Test/stest322.c new file mode 100644 index 000000000..02f36f766 --- /dev/null +++ b/Test/stest322.c @@ -0,0 +1,23 @@ +// +// a struct value passed to a call is built in registers of its own; nothing +// reads them as a block, so they need not stay together, and each call's +// registers may be reused by the next +// +typedef struct triple { + int a, b, c; +} T; + +int use(T t) __attribute__(noinline) +{ + return t.a + t.b + t.c; +} + +int sum(int k) +{ + int s = 0; + s += use((T){k, 1, 2}); + s += use((T){k, 3, 4}); + s += use((T){k, 5, 6}); + s += use((T){k, 7, 8}); + return s; +} diff --git a/backends/asm/outasm.c b/backends/asm/outasm.c index ce167fdda..121d5b8bd 100644 --- a/backends/asm/outasm.c +++ b/backends/asm/outasm.c @@ -1703,6 +1703,151 @@ static void EmitFunctionEpilog(IRList *irl, Function *func) FreeTempRegisters(irl, 0); } +// is op the base register of a local larger than a long, or one of its +// subregisters? +static bool +RefersToBase(Operand *op, Operand *base) +{ + return op && (op == base || (op->kind == REG_SUBREG && (Operand *)op->name == base)); +} + +// is op the address of the base register, or of one of its longs? GetLea +// names the address of a subregister as OffsetName does ("base_01") +static bool +AddressesBase(Operand *op, Operand *base) +{ + size_t n; + const char *s; + + if (!op || op->kind != IMM_COG_LABEL || !op->name) { + return false; + } + n = strlen(base->name); + if (strncmp(op->name, base->name, n) != 0) { + return false; + } + if (op->name[n] == 0) { + return true; + } + if (op->name[n] != '_' || !op->name[n+1]) { + return false; + } + for (s = op->name + n + 1; *s; s++) { + if (!isdigit((unsigned char)*s)) { + return false; + } + } + return true; +} + +// may the longs of the local "base" be kept in registers that are not +// consecutive? not if anything uses them as a block +static bool +CanSplitLocal(IRList *irl, Operand *base) +{ + IR *ir, *prev = NULL; + + for (ir = irl->head; ir; prev = ir, ir = ir->next) { + // its address is taken, as for an index that is not a constant + if (AddressesBase(ir->dst, base) || AddressesBase(ir->src, base)) { + return false; + } + if (RefersToBase(ir->dst, base) || RefersToBase(ir->src, base)) { + // inline assembly may use the longs as a block (s+1, #s) + if (ir->flags & FLAG_USER_INSTR) { + return false; + } + // a SETQ burst reads or writes consecutive registers + if (prev && (prev->opc == OPC_SETQ || prev->opc == OPC_SETQ2)) { + return false; + } + } + } + return true; +} + +// +// A local larger than a long (a struct, or a 64 bit value) held in registers +// is a base register with a subregister for each further long, and +// RenameSubregs keeps its longs in consecutive registers. ReuseLocalRegisters +// does not reuse subregisters, so such a local holds all of its registers +// until the end of the function, and a function passing many struct values to +// calls runs out of registers. Each such local that CanSplitLocal allows is +// split here into one local per long, which the optimizer then treats like any +// other local. +// +static void +SplitLocalStructs(IRList *irl) +{ + struct flexbuf bases; + Operand **list; + size_t nbases, i; + IR *ir; + + // collect the base registers of the locals that have subregisters + flexbuf_init(&bases, 64); + for (ir = irl->head; ir; ir = ir->next) { + Operand *ops[2] = { ir->dst, ir->src }; + for (int k = 0; k < 2; k++) { + Operand *op = ops[k]; + Operand *base; + bool seen = false; + if (!op || op->kind != REG_SUBREG || !IsLocal(op)) { + continue; + } + base = (Operand *)op->name; + list = (Operand **)flexbuf_peek(&bases); + nbases = flexbuf_curlen(&bases) / sizeof(Operand *); + for (i = 0; i < nbases; i++) { + if (list[i] == base) seen = true; + } + if (!seen) { + flexbuf_addmem(&bases, (const char *)&base, sizeof(base)); + } + } + } + list = (Operand **)flexbuf_peek(&bases); + nbases = flexbuf_curlen(&bases) / sizeof(Operand *); + for (i = 0; i < nbases; i++) { + Operand *base = list[i]; + Operand **parts; + int nparts = 1; + if (!CanSplitLocal(irl, base)) { + continue; + } + // count the longs in use + for (ir = irl->head; ir; ir = ir->next) { + if (ir->dst && ir->dst->kind == REG_SUBREG && (Operand *)ir->dst->name == base && ir->dst->val >= nparts) { + nparts = ir->dst->val + 1; + } + if (ir->src && ir->src->kind == REG_SUBREG && (Operand *)ir->src->name == base && ir->src->val >= nparts) { + nparts = ir->src->val + 1; + } + } + // the base register keeps the first long, and each further long gets + // a local of its own + parts = (Operand **)calloc(nparts, sizeof(*parts)); + parts[0] = base; + for (int k = 1; k < nparts; k++) { + char *name = (char *)calloc(1, strlen(base->name) + 16); + sprintf(name, "%s__long%d", base->name, k); + parts[k] = GetOneGlobal(base->kind, name, 0); + parts[k]->used = 1; + } + // replace each subregister by the local of its long + for (ir = irl->head; ir; ir = ir->next) { + if (ir->dst && ir->dst->kind == REG_SUBREG && (Operand *)ir->dst->name == base) { + ir->dst = parts[ir->dst->val]; + } + if (ir->src && ir->src->kind == REG_SUBREG && (Operand *)ir->src->name == base) { + ir->src = parts[ir->src->val]; + } + } + free(parts); + } + flexbuf_delete(&bases); +} + /* * rename one operand locally */ @@ -5665,6 +5810,9 @@ CompileFunctionBody(Function *f) EmitLabel(irl,jumpover); } EmitFunctionEpilog(irl, f); + if (f->optimize_flags & OPT_EXPERIMENTAL) { + SplitLocalStructs(irl); + } OptimizeIRLocal(irl, f); HashFuncIRL(f); }