mirror of https://git.wuffs.org/MWCC
402 lines
12 KiB
C
402 lines
12 KiB
C
#include "compiler/IrOptimizer.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/InlineAsmPPC.h"
|
|
#include "compiler/IroCSE.h"
|
|
#include "compiler/IroDump.h"
|
|
#include "compiler/IroEval.h"
|
|
#include "compiler/IroFlowgraph.h"
|
|
#include "compiler/IroLinearForm.h"
|
|
#include "compiler/IroSubable.h"
|
|
#include "compiler/IroTransform.h"
|
|
#include "compiler/IROUseDef.h"
|
|
#include "compiler/IroUtil.h"
|
|
#include "compiler/IroVars.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/IroPropagate.h"
|
|
#include "compiler/IroPointerAnalysis.h"
|
|
#include "compiler/IroJump.h"
|
|
#include "compiler/IroRangePropagation.h"
|
|
#include "compiler/IroEmptyLoop.h"
|
|
#include "compiler/IroUnrollLoop.h"
|
|
#include "compiler/IroLoop.h"
|
|
#include "compiler/IroExprRegeneration.h"
|
|
|
|
Boolean DoScalarize;
|
|
Boolean DoLinearize;
|
|
Boolean EarlyReturn;
|
|
Boolean IRO_CPFirstTime;
|
|
Boolean VectorPhaseCalledFromUnroll;
|
|
Boolean IRO_Log;
|
|
static Boolean stIsSetup;
|
|
|
|
static void CountRefToObject(Object *object, int depth) {
|
|
static unsigned short LoopUsage[] = {1, 4, 16, 64};
|
|
|
|
if (depth > 3)
|
|
depth = 3;
|
|
|
|
object->u.var.info->usage += LoopUsage[depth];
|
|
object->u.var.info->used = 1;
|
|
}
|
|
|
|
static void CountARef(IROLinear *node, int depth) {
|
|
Object *object;
|
|
|
|
object = node->u.node->data.objref;
|
|
CError_ASSERT(78, object->datatype != DALIAS);
|
|
|
|
if (object->datatype == DLOCAL && object->u.var.info) {
|
|
CountRefToObject(object, depth);
|
|
if ((node->flags & IROLF_Used) && (node->flags & IROLF_Assigned))
|
|
CountRefToObject(object, depth);
|
|
|
|
if (!(node->flags & IROLF_Immind) && !object->u.var.info->noregister)
|
|
object->u.var.info->noregister = 2;
|
|
}
|
|
}
|
|
|
|
static void CountDoubleInd(IROLinear *node, int depth) {
|
|
if (IRO_IsVariable(node)) {
|
|
CountARef(node->u.monadic, depth);
|
|
} else if (node->type == IROLinearOp2Arg) {
|
|
if (node->nodetype == EADD) {
|
|
CountDoubleInd(node->u.diadic.left, depth);
|
|
CountDoubleInd(node->u.diadic.right, depth);
|
|
} else if (IRO_IsAddressMultiply(node)) {
|
|
if (IRO_IsVariable(node->u.diadic.left))
|
|
CountARef(node->u.diadic.left->u.monadic, depth);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CountUsage(void) {
|
|
IRONode *fnode = IRO_FirstNode;
|
|
IROLinear *node;
|
|
|
|
if (IRO_FirstNode) {
|
|
for (; fnode; fnode = fnode->nextnode) {
|
|
for (node = fnode->first; node; node = node->next) {
|
|
if (IS_LINEAR_ENODE(node, EOBJREF))
|
|
CountARef(node, fnode->loopdepth);
|
|
else if (IS_LINEAR_MONADIC(node, EINDIRECT))
|
|
CountDoubleInd(node->u.monadic, fnode->loopdepth);
|
|
|
|
if (node->type == IROLinearAsm) {
|
|
IAEffects effects;
|
|
int i;
|
|
|
|
CodeGen_GetAsmEffects(node->u.asm_stmt, &effects);
|
|
for (i = 0; i < effects.numoperands; i++) {
|
|
Object *object = effects.operands[i].object;
|
|
if (object->datatype == DLOCAL && object->u.var.info) {
|
|
CountRefToObject(object, fnode->loopdepth);
|
|
if (effects.operands[i].type == IAOpnd_3 && !object->u.var.info->noregister)
|
|
object->u.var.info->noregister = 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (node == fnode->last)
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for (node = IRO_FirstLinear; node; node = node->next) {
|
|
if (IS_LINEAR_ENODE(node, EOBJREF))
|
|
CountARef(node, 0);
|
|
else if (IS_LINEAR_MONADIC(node, EINDIRECT))
|
|
CountDoubleInd(node->u.monadic, 0);
|
|
}
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
}
|
|
|
|
Statement *IRO_Optimizer(Object *func, Statement *statements) {
|
|
Boolean changed;
|
|
Boolean changed2;
|
|
int pass;
|
|
int passCount;
|
|
|
|
CError_ASSERT(234, stIsSetup);
|
|
|
|
#ifdef CW_PATCH_DEBUG
|
|
if (copts.debuglisting)
|
|
IRO_Log = 1;
|
|
#endif
|
|
|
|
DisableDueToAsm = 0;
|
|
FunctionName = func;
|
|
DoScalarize = 1;
|
|
DoLinearize = 1;
|
|
EarlyReturn = 0;
|
|
IRO_Depends = NULL;
|
|
LoopOptimizerRun = 0;
|
|
IRO_IsLeafFunction = 1;
|
|
IRO_FunctionHasReturn = 0;
|
|
|
|
IRO_SetupForUserBreakChecking();
|
|
|
|
IRO_Dump("Starting function %s\n", func ? func->name->name : "Init-code");
|
|
IRO_Dump("--------------------------------------------------------------------------------\n");
|
|
|
|
if (DoLinearize)
|
|
IRO_PreLinearize(statements);
|
|
if (copts.optimizationlevel > 0)
|
|
IRO_TransformTree(statements);
|
|
|
|
VectorPhaseCalledFromUnroll = 0;
|
|
|
|
IRO_Linearize(statements);
|
|
|
|
CurStat = NULL;
|
|
|
|
IRO_FirstExpr = NULL;
|
|
IRO_LastExpr = NULL;
|
|
IRO_FirstAssign = NULL;
|
|
IRO_LastAssign = NULL;
|
|
IRO_FirstVarUse = NULL;
|
|
IRO_LastVarUse = NULL;
|
|
IRO_FirstNode = NULL;
|
|
IRO_LastNode = NULL;
|
|
|
|
if (copts.optimizationlevel > 0)
|
|
IRO_DoTransformations();
|
|
|
|
IRO_BuildFlowgraph(IRO_FirstLinear);
|
|
IRO_DumpAfterPhase("IRO_BuildflowGraph", 0);
|
|
|
|
IRO_FindAllVars();
|
|
IRO_CheckInit();
|
|
|
|
if (!DisableDueToAsm && copts.optimizationlevel > 0 && copts.opt_pointer_analysis && func) {
|
|
IRO_AnalyzePointers(func);
|
|
if (copts.opt_propagation && IRO_EvaluateDefinitePointers(func)) {
|
|
IRO_UpdateFlagsOnInts();
|
|
IRO_UpdateVars();
|
|
IRO_DumpAfterPhase("IRO_EvaluateDefinitePointers", 0);
|
|
}
|
|
}
|
|
|
|
if (copts.optimizationlevel > 0) {
|
|
changed = IRO_EvaluateConditionals();
|
|
|
|
if (!DisableDueToAsm) {
|
|
changed |= IRO_RemoveUnreachable();
|
|
IRO_DumpAfterPhase("IRO_RemoveUnreachable", 0);
|
|
}
|
|
|
|
changed |= IRO_RemoveRedundantJumps();
|
|
IRO_DumpAfterPhase("IRO_RemoveRedundantJumps", 0);
|
|
|
|
if (!DisableDueToAsm) {
|
|
changed |= IRO_RemoveLabels();
|
|
IRO_DumpAfterPhase("IRO_RemoveLabels()", 0);
|
|
}
|
|
|
|
if (changed) {
|
|
IRO_BuildFlowgraph(IRO_FirstLinear);
|
|
IRO_DumpAfterPhase("IRO_BuildflowGraph--1", 0);
|
|
}
|
|
}
|
|
|
|
if (!DisableDueToAsm && copts.optimizationlevel > 0) {
|
|
passCount = copts._B4 ? 2 : 1;
|
|
IRO_CPFirstTime = 1;
|
|
for (pass = 0; pass < passCount; pass++) {
|
|
IRO_Dump("*****************\n");
|
|
IRO_Dump("Dumps for pass=%d\n", pass);
|
|
IRO_Dump("*****************\n");
|
|
|
|
if (DoScalarize)
|
|
IRO_ScalarizeClassDataMembers();
|
|
IRO_DumpAfterPhase("IRO_ScalarizeClassDataMembers", 0);
|
|
|
|
if (copts.opt_propagation) {
|
|
IRO_CopyAndConstantPropagation();
|
|
IRO_CPFirstTime = 0;
|
|
IRO_ExpressionPropagation();
|
|
IRO_DumpAfterPhase("Copy and constant propagation", 0);
|
|
|
|
IRO_RangePropagateInFNode();
|
|
IRO_DumpAfterPhase("IRO_RangePropagateInFNode", 0);
|
|
IRO_UpdateFlagsOnInts();
|
|
}
|
|
|
|
IRO_DumpAfterPhase("IRO_ExpressionPropagation", 0);
|
|
|
|
if (copts.opt_dead_assignments || copts.opt_propagation)
|
|
IRO_UseDef(copts.opt_dead_assignments, copts.opt_propagation);
|
|
IRO_DumpAfterPhase("after IRO_UseDef", 0);
|
|
|
|
IRO_UpdateVars();
|
|
IRO_ConstantFolding();
|
|
IRO_DumpAfterPhase("IRO_ConstantFolding", 0);
|
|
|
|
IRO_EvaluateConditionals();
|
|
IRO_RemoveUnreachable();
|
|
IRO_SimplifyConditionals();
|
|
|
|
if (pass == 1 && copts.optimizationlevel > 2) {
|
|
IRO_RenumberInts();
|
|
IRO_DumpAfterPhase("Before IRO_FindEmptyLoops", 0);
|
|
IRO_FindEmptyLoops();
|
|
IRO_DumpAfterPhase("After IRO_FindEmptyLoops", 0);
|
|
IRO_RenumberInts();
|
|
}
|
|
|
|
if (copts.opt_unroll_loops && !copts.optimize_for_size && pass == 0) {
|
|
IRO_DumpAfterPhase("Before IRO_LoopUnroller", 0);
|
|
IRO_LoopUnroller();
|
|
IRO_DumpAfterPhase("After IRO_LoopUnroller", 0);
|
|
IRO_RenumberInts();
|
|
}
|
|
|
|
VectorPhaseCalledFromUnroll = 0;
|
|
|
|
if (pass == 0 && (copts.opt_loop_invariants || copts.opt_strength_reduction)) {
|
|
IRO_DumpAfterPhase("Before IRO_FindLoops", 0);
|
|
IRO_FindLoops();
|
|
LoopOptimizerRun = 1;
|
|
IRO_SetLoopDepth();
|
|
}
|
|
IRO_DumpAfterPhase("After IRO_FindLoops", 0);
|
|
|
|
if (copts.opt_propagation) {
|
|
IRO_CopyAndConstantPropagation();
|
|
IRO_ConstantFolding();
|
|
IRO_EvaluateConditionals();
|
|
}
|
|
|
|
IRO_DumpAfterPhase("Second pass:IRO_CopyAndConstantPropagation, IRO_ConstantFolding, IRO_EvaluateConditionals", 0);
|
|
|
|
if (copts.opt_common_subs)
|
|
IRO_FindExpressions(NULL, 0);
|
|
|
|
if (copts.opt_common_subs) {
|
|
IRO_ComputeAvail();
|
|
IRO_CommonSubs();
|
|
}
|
|
IRO_DumpAfterPhase("IRO_CommonSubs", 0);
|
|
|
|
IRO_UpdateFlagsOnInts();
|
|
IRO_UpdateVars();
|
|
IRO_DoTransformations();
|
|
IRO_ConstantFolding();
|
|
|
|
do {
|
|
IRO_UpdateFlagsOnInts();
|
|
|
|
if (copts.opt_dead_code)
|
|
IRO_RemoveUnreachable();
|
|
IRO_DumpAfterPhase("IRO_RemoveUnreachable", 0);
|
|
|
|
changed2 = IRO_RemoveRedundantJumps();
|
|
IRO_DumpAfterPhase("IRO_RemoveRedundantJumps", 0);
|
|
|
|
changed2 |= IRO_RemoveLabels();
|
|
IRO_DumpAfterPhase("IRO_RemoveLabels", 0);
|
|
|
|
changed2 |= IRO_DoJumpChaining();
|
|
IRO_DumpAfterPhase("IRO_DoJumpChaining", 0);
|
|
|
|
if (copts.opt_propagation) {
|
|
IRO_RenumberInts();
|
|
IRO_DumpAfterPhase("Before IRO_CopyAndConstantPropagation", 0);
|
|
changed2 |= IRO_CopyAndConstantPropagation();
|
|
IRO_DumpAfterPhase("After IRO_CopyAndConstantPropagation", 0);
|
|
IRO_ConstantFolding();
|
|
}
|
|
|
|
if (copts.opt_dead_assignments || copts.opt_propagation)
|
|
changed2 |= IRO_UseDef(copts.opt_dead_assignments, copts.opt_propagation);
|
|
IRO_DumpAfterPhase("IRO_UseDef", 0);
|
|
|
|
changed2 |= IRO_EvaluateConditionals();
|
|
IRO_DumpAfterPhase("IRO_EvaluateConditionals", 0);
|
|
} while (changed2);
|
|
}
|
|
|
|
if (copts.opt_lifetimes) {
|
|
IRO_UseDef(0, 0);
|
|
IRO_SplitLifetimes();
|
|
}
|
|
|
|
IRO_DoTransformations();
|
|
IRO_DumpAfterPhase("Before RebuildCondExpressions", 0);
|
|
}
|
|
|
|
IRO_RenumberInts();
|
|
IRO_DumpAfterPhase("before IRO_RewriteBitFieldTemps", 0);
|
|
IRO_RewriteBitFieldTemps();
|
|
IRO_DumpAfterPhase("After IRO_RewriteBitFieldTemps", 0);
|
|
|
|
CountUsage();
|
|
|
|
if (!DisableDueToAsm) {
|
|
IRO_RegenerateExpressions();
|
|
IRO_DumpAfterPhase("IRO_RegenerateExpressions", 0);
|
|
}
|
|
|
|
IRO_DumpAfterPhase("After IRO_Optimizer", 0);
|
|
|
|
statements = IRO_Delinearize(IRO_FirstNode, NULL);
|
|
|
|
IRO_ZapVarPtrs();
|
|
freeoheap();
|
|
return statements;
|
|
}
|
|
|
|
void IRO_Setup(void) {
|
|
static Boolean ENodeArraysHaveBeenInitialized;
|
|
|
|
if (!stIsSetup) {
|
|
IRO_Log = 0;
|
|
IRO_SetupDump();
|
|
if (!ENodeArraysHaveBeenInitialized) {
|
|
IRO_InitializeNodeNamesArray();
|
|
IRO_InitializeIsAssociativeENodeTypeArray();
|
|
IRO_InitializeIsSubableOpArray();
|
|
IRO_InitializeAssignmentOpArray();
|
|
IRO_InitializeComplementaryOpArray();
|
|
IRO_InitializeComplementaryOpLogicalArray();
|
|
IRO_InitializeNonAssignmentOpArray();
|
|
IRO_InitializeAssignmentFoldingFunctionArray();
|
|
IRO_InitializeIRO_IsModifyOpArray();
|
|
IRO_InitializeIRO_IsAssignOpArray();
|
|
ENodeArraysHaveBeenInitialized = 1;
|
|
}
|
|
stIsSetup = 1;
|
|
}
|
|
}
|
|
|
|
void IRO_Cleanup(void) {
|
|
if (stIsSetup) {
|
|
IRO_CleanupDump();
|
|
stIsSetup = 0;
|
|
}
|
|
}
|
|
|
|
void CodeGen_UpdateOptimizerOptions(void) {
|
|
Boolean flag;
|
|
|
|
flag = copts.optimizationlevel >= 1;
|
|
copts.opt_dead_code = flag;
|
|
|
|
flag = copts.optimizationlevel >= 2;
|
|
copts.opt_propagation = flag;
|
|
copts.opt_common_subs = flag;
|
|
|
|
flag = copts.optimizationlevel >= 3;
|
|
copts.opt_vectorize_loops = flag;
|
|
copts.opt_unroll_loops = flag;
|
|
copts.opt_dead_assignments = flag;
|
|
copts.opt_lifetimes = flag;
|
|
copts.opt_strength_reduction = flag;
|
|
copts.opt_loop_invariants = flag;
|
|
|
|
flag = copts.optimizationlevel >= 4;
|
|
copts._B4 = flag;
|
|
}
|