Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions backends/asm/outasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ ValidateAbortFuncs(void)
}
}

static Operand *pushregs_, *popregs_, *count_, *gosub_;
static Operand *pushregs_, *popregs_, *count_, *retaddr_, *gosub_;

static void
ValidatePushregs(void)
Expand All @@ -397,6 +397,7 @@ ValidatePushregs(void)
pushregs_ = NewOperand(IMM_COG_LABEL, "pushregs_", 0);
popregs_ = NewOperand(IMM_COG_LABEL, "popregs_", 0);
count_ = NewOperand(REG_REG, "COUNT_", 0);
retaddr_ = NewOperand(REG_REG, "RETADDR_", 0);
if (gl_p2) {
frameptr = NewOperand(REG_REG, "fp", 0);
}
Expand Down Expand Up @@ -1967,7 +1968,27 @@ static void EmitFunctionHeader(IRList *irl, Function *func)
FuncData(func)->numsavedregs = n;
if (needFrame) {
ValidateFrameptr();
if (HUB_CODE) {
if (HUB_CODE && gl_p2 && !InCog(func) && (func->optimize_flags & OPT_INLINE_PUSHREGS)) {
// inline copy of pushregs_, building the same frame, so that
// a function in hub memory does not leave it for cog memory
// and come back, which reloads the instruction FIFO
IR *ir;
ValidatePushregs();
EmitMove(irl, count_, NewImmediate(n), linenum);
EmitOp1(irl, OPC_POP, retaddr_);
if (n > 0) {
if (n > 1) {
EmitOp1(irl, OPC_SETQ, NewImmediate(n-1));
}
ir = EmitOp2(irl, OPC_WRLONG, GetLocalReg(0, 0), stackptr);
ir->srceffect = OPEFFECT_POSTINC;
}
// COUNT_, RETADDR_ and fp are consecutive registers
EmitOp1(irl, OPC_SETQ, NewImmediate(2));
ir = EmitOp2(irl, OPC_WRLONG, count_, stackptr);
ir->srceffect = OPEFFECT_POSTINC;
EmitMove(irl, frameptr, stackptr, linenum);
} else if (HUB_CODE) {
ValidatePushregs();
EmitMove(irl, count_, NewImmediate(n), linenum);
EmitOp1(irl, OPC_CALL, pushregs_);
Expand Down Expand Up @@ -2014,7 +2035,22 @@ static void EmitFunctionFooter(IRList *irl, Function *func)
if (!func->closure) {
EmitMove(irl, stackptr, frameptr, linenum);
}
if (HUB_CODE) {
if (HUB_CODE && gl_p2 && !InCog(func) && (func->optimize_flags & OPT_INLINE_PUSHREGS)) {
// inline copy of popregs_ (see EmitFunctionHeader)
IR *ir;
ValidatePushregs();
EmitOp1(irl, OPC_SETQ, NewImmediate(2));
ir = EmitOp2(irl, OPC_RDLONG, count_, stackptr);
ir->srceffect = OPEFFECT_PREDEC;
if (n > 0) {
if (n > 1) {
EmitOp1(irl, OPC_SETQ, NewImmediate(n-1));
}
ir = EmitOp2(irl, OPC_RDLONG, GetLocalReg(0, 0), stackptr);
ir->srceffect = OPEFFECT_PREDEC;
}
EmitOp1(irl, OPC_PUSH, retaddr_);
} else if (HUB_CODE) {
// pop registers off stack
ValidatePushregs();
EmitOp1(irl, OPC_CALL, popregs_);
Expand Down
1 change: 1 addition & 0 deletions cmdline.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ static FlagTable optflag[] = {
{ "spin-relax-memory", OPT_SPIN_RELAXMEM},
{ "fast-inline-asm", OPT_FASTASM },
{ "peek-args", OPT_PEEK_ARGS },
{ "inline-pushregs", OPT_INLINE_PUSHREGS },
{ "experimental", OPT_EXPERIMENTAL },
{ "all", OPT_FLAGS_ALL },
};
Expand Down
11 changes: 11 additions & 0 deletions doc/general.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,17 @@ used there. By default it is assumed that all argument registers may be
changed within a function, but with this optimization we check for some special
cases to save having to copy arguments to other registers.

### Inline register save and restore (-O2, -Oinline-pushregs)

On the P2, a function in hub memory that needs a stack frame normally calls the
`pushregs_` and `popregs_` routines in COG memory to save and restore its
registers. With this optimization the same `setq`/`wrlong` and `setq`/`rdlong`
sequences are generated inline in the function's entry and exit code instead,
building the same stack frame. This saves about 32 cycles per call, mostly the
two trips into COG memory and back, at a cost of 5 to 9 more instructions in
each function that has a frame. Functions placed in COG or LUT memory are not
affected.

### Common Subexpression Elimination (-O2, -Ocse)

Code like:
Expand Down
3 changes: 2 additions & 1 deletion frontends/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ extern int gl_optimize_flags; /* flags for optimization */
#define OPT_SPIN_RELAXMEM 0x01000000 /* relax strict memory semantics for Spin */
#define OPT_FASTASM 0x02000000 /* optimize inline assembly invocation */
#define OPT_PEEK_ARGS 0x04000000 /* peek into functions to see if arg registers can be reused */
#define OPT_INLINE_PUSHREGS 0x08000000 /* save/restore registers inline in hub functions (P2) */
#define OPT_EXPERIMENTAL 0x80000000 /* gate new or experimental optimizations */
#define OPT_FLAGS_ALL 0xffffffff

Expand All @@ -208,7 +209,7 @@ extern int gl_optimize_flags; /* flags for optimization */
// default optimization (-O1) for ASM output
#define DEFAULT_ASM_OPTS (OPT_ASM_BASIC|OPT_DEADCODE|OPT_REMOVE_UNUSED_FUNCS|OPT_INLINE_SMALLFUNCS|OPT_AUTO_FCACHE|OPT_LOOP_BASIC|OPT_TAIL_CALLS|OPT_SPECIAL_FUNCS|OPT_CORDIC_REORDER|OPT_LOCAL_REUSE|OPT_LOOP_BASIC)
// extras added with -O2
#define EXTRA_ASM_OPTS (OPT_INLINE_SINGLEUSE|OPT_PERFORM_CSE|OPT_PERFORM_LOOPREDUCE|OPT_REMOVE_HUB_BSS|OPT_EXPERIMENTAL|OPT_AGGRESSIVE_MEM|OPT_MERGE_DUPLICATES|OPT_PEEK_ARGS)
#define EXTRA_ASM_OPTS (OPT_INLINE_SINGLEUSE|OPT_PERFORM_CSE|OPT_PERFORM_LOOPREDUCE|OPT_REMOVE_HUB_BSS|OPT_EXPERIMENTAL|OPT_AGGRESSIVE_MEM|OPT_MERGE_DUPLICATES|OPT_PEEK_ARGS|OPT_INLINE_PUSHREGS)

// default optimization (-O1) for bytecode output; defaults to much less optimization than asm
#define DEFAULT_BYTECODE_OPTS (OPT_REMOVE_UNUSED_FUNCS|OPT_REMOVE_FEATURES|OPT_DEADCODE|OPT_MAKE_MACROS|OPT_SPECIAL_FUNCS|OPT_PEEPHOLE|OPT_LOOP_BASIC)
Expand Down
Loading