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
106 changes: 79 additions & 27 deletions backends/asm/optimize_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -882,24 +882,28 @@ AddSubVal(IR *ir)

extern Operand *mulfunc, *unsmulfunc, *divfunc, *unsdivfunc, *muldiva, *muldivb;

static bool FuncUsesArg(Operand *func, Operand *arg)
// Set "actually" if you only care about the call actually using the current value
static bool FuncUsesArgEx(Operand *func, Operand *arg, bool actually)
{
if (arg == muldiva || arg == muldivb) {
return true;
} else if (func == mulfunc || func == unsmulfunc || func == divfunc || func == unsdivfunc) {
return false;
if (func == mulfunc || func == unsmulfunc || func == divfunc || func == unsdivfunc) {
return (arg == muldiva || arg == muldivb);
} else if (arg == muldiva || arg == muldivb) {
return !actually;
} else if (func && func->val) {
Function *funcObj = (Function *)func->val;
if ((/*func->kind == IMM_COG_LABEL ||*/ func->kind == IMM_HUB_LABEL) && (funcObj->is_leaf || FuncData(funcObj)->effectivelyLeaf)) {
if ((/*func->kind == IMM_COG_LABEL ||*/ func->kind == IMM_HUB_LABEL) && (actually || funcObj->is_leaf || FuncData(funcObj)->effectivelyLeaf)) {
if (arg->kind != REG_ARG) return true; // subreg or smth
if (arg->val < funcObj->numparams) return true; // Arg used;
if (arg->val < FuncData(funcObj)->maxInlineArg) return true; // Arg clobbered
if (!actually && arg->val < FuncData(funcObj)->maxInlineArg) return true; // Arg clobbered
if ( ((Function *)func->val)->numparams < 0 ) return true; // varargs
return false; // Arg not used
}
}
return true;
}
static bool FuncUsesArg(Operand *func, Operand *arg) {
return FuncUsesArgEx(func,arg,false);
}


static bool IsCallThatUsesReg(IR *ir,Operand *op) {
Expand All @@ -915,7 +919,7 @@ static bool UsedInRange(IR *start,IR *end,Operand *reg) {
for (IR *ir=start;ir!=end->next;ir=ir->next) {
if (InstrUses(ir,reg)||IsJump(ir)) return true;
if (ir->opc == OPC_CALL) {
if (IsArg(reg) && FuncUsesArg(ir->dst,reg)) return true;
if (IsArg(reg) && FuncUsesArgEx(ir->dst,reg,true)) return true;
if (IsArg(reg)||isResult(reg)) return false; // Becomes dead
if (!IsLocal(reg)) return true;
}
Expand Down Expand Up @@ -1084,6 +1088,8 @@ doIsDeadAfter(IR *instr, Operand *op, int level, IR **stack)
// we know of some special cases where argN is not used
if (IsArg(op) && !FuncUsesArg(ir->dst, op)) {
/* OK to continue */
} else if (IsArg(op) && !FuncUsesArgEx(ir->dst,op,true)) {
return true; // Value not actually used, goes dead.
} else if (isResult(op)) {
if (ir->cond == COND_TRUE) return true; // Results get set by functions
} else {
Expand Down Expand Up @@ -1449,18 +1455,18 @@ ReplaceForward(IR *instr, Operand *orig, Operand *replace, IR *stop_ir)
}

//
// Apply a new condition code based on val being compared to 0
// Apply a new condition code based on cval/zval being compared to 0
//
int
ApplyConditionAfter(IR *instr, int val)
ApplyConditionAfter(IR *instr, int cval, int zval)
{
IR *ir;
unsigned newcond;
int change = 0;
int setz = instr->flags & FLAG_WZ;
int setc = instr->flags & FLAG_WC;
int cval = val < 0 ? 2 : 0;
int zval = val == 0 ? 1 : 0;
cval = cval < 0 ? 2 : 0;
zval = zval == 0 ? 1 : 0;



Expand Down Expand Up @@ -1547,7 +1553,7 @@ SameOperand(Operand *a, Operand *b)
static int
TransformConstDst(IR *ir, Operand *imm)
{
int32_t val1, val2;
int32_t val1, val2, cval;
int setsResult = 1;

if (gl_p2 && (!InstrSetsDst(ir) || (ir->opc == OPC_LOCKREL && IsDeadAfter(ir,ir->dst)))) {
Expand Down Expand Up @@ -1594,23 +1600,21 @@ TransformConstDst(IR *ir, Operand *imm)
}
if (ir->flags & FLAG_WC) {
// we don't know how to set the WC flag for anything other
// than cmps
if (ir->opc != OPC_CMPS && ir->opc != OPC_CMP) {
// than cmps/cmp/sub
if (ir->opc != OPC_CMPS && ir->opc != OPC_CMP && ir->opc != OPC_SUB) {
return 0;
}
}

val1 = imm->val;
val2 = ir->src->val;
cval = 0;

switch (ir->opc)
{
case OPC_ADD:
val1 += val2;
break;
case OPC_SUB:
val1 -= val2;
break;
case OPC_TEST:
setsResult = false;
// fall through
Expand Down Expand Up @@ -1648,17 +1652,20 @@ TransformConstDst(IR *ir, Operand *imm)
break;
case OPC_CMPS:
val1 -= val2;
cval = val1;
setsResult = 0;
break;
case OPC_CMP:
setsResult = 0;
case OPC_SUB:
if ((uint32_t)val1 < (uint32_t)val2) {
val1 = -1;
cval = -1;
} else if (val1 == val2) {
val1 = 0;
cval = 0;
} else {
val1 = 1;
cval = 1;
}
setsResult = 0;
val1 -= val2;
break;
case OPC_TESTBN:
setsResult = false;
Expand All @@ -1674,7 +1681,8 @@ TransformConstDst(IR *ir, Operand *imm)
return 0;
}
if (InstrSetsAnyFlags(ir)) {
ApplyConditionAfter(ir, val1);
ApplyConditionAfter(ir, cval, val1);
ir->flags &= !FLAG_CZSET;
}
if (setsResult) {
if (val1 < 0) {
Expand Down Expand Up @@ -2096,9 +2104,9 @@ OptimizeMoves(IRList *irl)
if (ir->flags == FLAG_WZ && CanTestZero(ir->opc)) {
// because this is a mov immediate, we know how
// WZ will be set
change |= ApplyConditionAfter(ir, cval);
change |= ApplyConditionAfter(ir, cval, cval);
} else if (ir->flags != 0 && ir->opc == OPC_ABS) {
change |= ApplyConditionAfter(ir, ir->src->val);
change |= ApplyConditionAfter(ir, ir->src->val, ir->src->val);
}
change |= (sawchange = PropagateConstForward(irl, ir, ir->dst, ir->src));
if (sawchange && !InstrSetsAnyFlags(ir) && IsDeadAfter(ir, ir->dst)) {
Expand Down Expand Up @@ -2565,7 +2573,7 @@ OptimizeCompares(IRList *irl)
&& ir->src == ir->dst)
{
// this compare always sets Z and clears C
ApplyConditionAfter(ir, 0);
ApplyConditionAfter(ir, 0, 0);
DeleteIR(irl, ir);
change |= 1;
}
Expand All @@ -2576,7 +2584,7 @@ OptimizeCompares(IRList *irl)
)
{
// this compare always clears C
ApplyConditionAfter(ir, 1);
ApplyConditionAfter(ir, 1, 1);
DeleteIR(irl, ir);
change |= 1;
}
Expand Down Expand Up @@ -4580,6 +4588,48 @@ ReuseLocalRegisters(IRList *irl) {
}


// Change calls to builtin_longfill_ on P2 to SETQ+WRLONG
int
OptimizeLongfill(IRList *irl) {
int change = 0;
if (!gl_p2) return 0;
for (IR *ir=irl->head;ir;ir=ir->next) {
IR *prevset;
int32_t setval;
if (IsDummy(ir)) continue;
if (ir->opc == OPC_CALL && !CondIsSubset(COND_C,ir->cond) && !strcmp(ir->dst->name,"builtin_longfill_")
&& (prevset = FindPrevSetterForReplace(ir,GetArgReg(1)))
&& isConstMove(prevset,&setval)) {
NOTE(NULL,"lmaooo");
int addr = ir->addr; // Some opts require addresses to be sorta-correct;
// Since we replace a funccall, we can clobber flags and args
IR *sub = NewIR(OPC_SUB);
sub->dst = GetArgReg(2);
sub->src = NewImmediate(1);
sub->flags = FLAG_WC;
sub->addr = addr;
sub->cond = ir->cond;
IR *setq = NewIR(OPC_SETQ);
setq->cond = COND_NC;
setq->dst = GetArgReg(2);
setq->cond = COND_NC | ir->cond;;
setq->addr = addr;
IR *wrlong = NewIR(OPC_WRLONG);
wrlong->cond = COND_NC | ir->cond;;
wrlong->dst = NewImmediate(setval);
wrlong->src = GetArgReg(0);
wrlong->addr = addr;

InsertAfterIR(irl,ir,wrlong);
InsertAfterIR(irl,ir,setq);
InsertAfterIR(irl,ir,sub);
DeleteIR(irl,ir);
change++;
}
}
return change;
}

// optimize an isolated piece of IRList
// (typically a function)
void
Expand All @@ -4593,6 +4643,8 @@ OptimizeIRLocal(IRList *irl, Function *f)
// multiply divide optimization need only be performed once,
// and should be done before other optimizations confuse things
OptimizeMulDiv(irl);
// Similarily for longfill (opt can only become available from inlining)
OptimizeLongfill(irl);
again:
do {
change = 0;
Expand Down
32 changes: 30 additions & 2 deletions frontends/hloptimize.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ HandleSpecialFunction(AST *ast, const char *spfunc)
// if we get here, convert to _drvw
ast->left = AstIdentifier("_drvw");
return;
}
if (!strcmp(spfunc, "pinr")) {
} else if (!strcmp(spfunc, "pinr")) {
arglist = ast->right;
if (!arglist) {
return;
Expand All @@ -136,6 +135,35 @@ HandleSpecialFunction(AST *ast, const char *spfunc)
ast->left = AstIdentifier("_pinr");
return;
}
} else if (!strcmp(spfunc,"memset")) {
arglist = ast->right;
if (!arglist || !arglist->right || !arglist->right->right) {
return;
}
//AST **setptr = &arglist->left;
AST **setval = &arglist->right->left;
AST **setlen = &arglist->right->right->left;
bool const_val = IsConstExpr(*setval);
bool const_len = IsConstExpr(*setlen);
uint32_t tmp;
// If on P2 and doing a long-sized memset, convert to faster function
if (gl_p2 && const_len && ((tmp = (uint32_t)EvalConstExpr(*setlen)) & 3) == 0) {
ASTReportInfo save;
AstReportAs(ast,&save);
*setlen = AstInteger(tmp>>2);
if (const_val) {
tmp = EvalConstExpr(*setval);
if (tmp!=0) {
tmp &= 255;
*setval = AstInteger((tmp<<24)|(tmp<<16)|(tmp<<8)|(tmp<<0));
}
} else {
*setval = NewAST(AST_FUNCCALL,AstIdentifier("__builtin_movbyts"),NewAST(AST_EXPRLIST,*setval,NewAST(AST_EXPRLIST,AstInteger(0),NULL)));
}
ast->left = AstIdentifier("__builtin_longset"); // Subject to further optimization in ASM backend after inlining
AstReportDone(&save);
return;
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions sys/bytecode_rom.spin
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,9 @@ pri __call_methodptr
'
' memset(): we may want to optimize this to use longfill in special cases?
'
pri __builtin_memset(ptr, val, count) : r
r := ptr
pri {++specialfunc(memset)} __builtin_memset(ptr, val, count) : r
bytefill(ptr, val, count)
return ptr

pri _lockmem(addr) | oldlock, oldmem, lockreg
lockreg := __getlockreg
Expand Down
Loading