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
90 changes: 74 additions & 16 deletions backends/asm/optimize_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,28 @@ DoReorderBlock(IRList *irl,IR *after,IR *top,IR *bottom) {
after->next = top;
}

// Return true for "normal" ALU ops
static bool
IsSafeALUOp(IROpcode opc) {
switch(opc) {
case OPC_MOV:
case OPC_ADD:
case OPC_SUB:
case OPC_AND:
case OPC_OR:
case OPC_XOR:
case OPC_TEST:
case OPC_TESTN:
case OPC_SHL:
case OPC_SHR:
case OPC_NEG:
case OPC_ABS:
return true;
default:
return false;
}
}

/*
* return TRUE if the operand's value does not need to be preserved
* after instruction instr
Expand Down Expand Up @@ -1113,18 +1135,10 @@ doIsDeadAfter(IR *instr, Operand *op, int level, IR **stack)
if (InstrSetsAnyFlags(ir)) {
return false; // flag setting matters, we are not dead
}
switch(ir->opc) {
// be very cautious about whether op is dead if
// any "unusal" opcodes (like waitpeq) are used
// so just accept
case OPC_ADD:
case OPC_SUB:
case OPC_AND:
case OPC_OR:
case OPC_XOR:
// not definitely alive or dead yet
break;
default:
// so just accept a safe subset
if (!IsSafeALUOp(ir->opc)) {
// assume live
return false;
}
Expand Down Expand Up @@ -1938,6 +1952,15 @@ TransformConstDst(IR *ir, Operand *imm)
// Z is set if bit is SET
val1 = ~val1 & (1<<(val2&31));
break;
case OPC_BITH:
val1 |= EvalP2BitMask(val2);
break;
case OPC_BITL:
val1 &= ~EvalP2BitMask(val2);
break;
case OPC_BITNOT:
val1 ^= EvalP2BitMask(val2);
break;
default:
return 0;
}
Expand Down Expand Up @@ -5221,17 +5244,22 @@ NeverInline(Function *f)

//
// check a function to see if it should be inlined
// and return true if new inlining opportunites were unlocked
//
#define INLINE_THRESHOLD_P1 2
#define INLINE_THRESHOLD_P2 4

bool
ShouldBeInlined(Function *f)
AnalyzeInlineEligibility(Function *f)
{
IR *ir;
int n = 0;
int paramfactor;
int threshold;
bool pure = true;

unsigned prev_flags = FuncData(f)->inliningFlags;
FuncData(f)->inliningFlags = 0;

if (f->prefer_inline) {
threshold = 100;
Expand Down Expand Up @@ -5269,15 +5297,25 @@ ShouldBeInlined(Function *f)
}
}

// Check for impurity here. This check is very conservative.
if (!IsLabel(ir) && !IsSafeALUOp(ir->opc)) pure = false;
if (ir->dst && !(IsLocalOrArg(ir->dst) || isResult(ir->dst))) pure = false;
if (ir->src && !(IsImmediate(ir->src) || IsLocalOrArg(ir->src) || isResult(ir->src))) pure = false;

n++;
}

if (pure) {
FuncData(f)->inliningFlags |= ASM_INLINE_PURE_FLAG;
}

// a function called from only 1 place should be inlined
// if it means that the function definition can be eliminated
if (RemoveIfInlined(f) && (gl_optimize_flags & OPT_INLINE_SINGLEUSE)) {
if (f->callSites == 1) {
return true;
} else if (f->callSites == 2) {
return (n <= 2*threshold);
FuncData(f)->inliningFlags |= ASM_INLINE_SINGLE_FLAG;
} else if (f->callSites == 2 && (n <= 2*threshold)) {
FuncData(f)->inliningFlags |= ASM_INLINE_SINGLE_FLAG;
}
}

Expand All @@ -5292,13 +5330,33 @@ ShouldBeInlined(Function *f)
} else {
paramfactor = f->numparams;
}
return n <= (threshold + paramfactor);
if (n <= (threshold + paramfactor)) {
FuncData(f)->inliningFlags |= ASM_INLINE_SMALL_FLAG;
}

return FuncData(f)->inliningFlags & ~prev_flags;
}

static inline void updateMax(int *dst, int src) {
if (*dst < src) *dst = src;
}

static bool
ShouldExpandPureFunction(IR *ir) {
Function *f = (Function *)ir->aux;
if (!(FuncData(f)->inliningFlags & ASM_INLINE_PURE_FLAG)) return false;
if (!(gl_optimize_flags & OPT_EXPERIMENTAL)) return false;
if (f->numparams <= 0) return false;

// Make sure all args are constants
for (int i = 0; i < f->numparams; i++) {
IR *prev_ir = FindPrevSetterForReplace(ir,GetArgReg(i));
if (!prev_ir || !isConstMove(prev_ir,NULL)) return false;
}

return true;
}

//
// expand function calls inline if appropriate
// returns 1 if anything was expanded
Expand All @@ -5315,7 +5373,7 @@ ExpandInlines(IRList *irl)
ir_next = ir->next;
if (ir->opc == OPC_CALL) {
f = (Function *)ir->aux;
if (f && FuncData(f)->isInline) {
if (f && ((FuncData(f)->inliningFlags & (ASM_INLINE_SMALL_FLAG|ASM_INLINE_SINGLE_FLAG)) || ShouldExpandPureFunction(ir))) {
ReplaceIRWithInline(irl, ir, f);
FuncData(f)->actual_callsites--;
updateMax(&FuncData(curfunc)->maxInlineArg,f->numparams);
Expand Down
13 changes: 4 additions & 9 deletions backends/asm/outasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -5605,7 +5605,7 @@ RemoveIfInlined(Function *f)
static bool
ActuallyInlined(Function *f)
{
if (!FuncData(f)->isInline) {
if (FuncData(f)->inliningFlags == 0) {
return false;
}
if (FuncData(f)->actual_callsites > 0) {
Expand Down Expand Up @@ -5754,7 +5754,7 @@ CompileFunc_internal(void *vptr, Module *P)
continue;
curfunc = f;
CompileFunctionBody(f);
FuncData(f)->isInline = ShouldBeInlined(f);
AnalyzeInlineEligibility(f);
}
curfunc = savecurf;
return 0;
Expand All @@ -5766,7 +5766,6 @@ ExpandInline_internal(void *vptr, Module *P)
Function *f;
int change;
int newInlines;
int inlineStatus;
int anyChange = 0;

do {
Expand All @@ -5783,12 +5782,8 @@ ExpandInline_internal(void *vptr, Module *P)
OptimizeIRLocal(firl, f);
// revisit the question of whether it should be inlined, given that
// we've perhaps changed its size
if (!FuncData(f)->isInline) {
inlineStatus = ShouldBeInlined(f);
if (inlineStatus) {
newInlines++;
FuncData(f)->isInline = true;
}
if (AnalyzeInlineEligibility(f)) {
newInlines++;
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions backends/asm/outasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ IR *EmitLabel(IRList *list, Operand *op);
void OptimizeIRLocal(IRList *irl, Function *f);
void OptimizeIRGlobal(IRList *irl);
void OptimizeFcache(IRList *irl);
bool ShouldBeInlined(Function *f);
bool AnalyzeInlineEligibility(Function *f);
bool RemoveIfInlined(Function *f);
int ExpandInlines(IRList *irl);

Expand Down Expand Up @@ -121,8 +121,11 @@ typedef struct ir_bedata {
/* number of local registers that need to be pushed */
int numsavedregs;

/* flag for whether we should inline the function */
bool isInline;
/* flags for whether we should inline the function */
unsigned inliningFlags;
#define ASM_INLINE_SMALL_FLAG 0x01
#define ASM_INLINE_SINGLE_FLAG 0x02
#define ASM_INLINE_PURE_FLAG 0x04

/* set after inlining if the function has no external calls left */
bool effectivelyLeaf;
Expand Down