mirror of https://git.wuffs.org/MWCC
1449 lines
50 KiB
C
1449 lines
50 KiB
C
#include "compiler/IROUseDef.h"
|
|
#include "compiler/IRODump.h"
|
|
#include "compiler/IROVars.h"
|
|
#include "compiler/IroFlowgraph.h"
|
|
#include "compiler/IroLinearForm.h"
|
|
#include "compiler/IroMalloc.h"
|
|
#include "compiler/IroPointerAnalysis.h"
|
|
#include "compiler/IroTransform.h"
|
|
#include "compiler/IroUtil.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/types.h"
|
|
#include "compiler/InlineAsm.h"
|
|
#include "compiler/InlineAsmPPC.h"
|
|
|
|
ENodeType IRO_NonAssignmentOp[MAXEXPR];
|
|
typedef CInt64 (*AssignmentFoldingFunc)(CInt64, CInt64);
|
|
static AssignmentFoldingFunc AssignmentFoldingFunction[MAXEXPR];
|
|
static SInt32 NumDefs;
|
|
static IRODef *FirstDef;
|
|
static IRODef *LastDef;
|
|
static SInt32 NumUses;
|
|
static BitVector *Reaches;
|
|
static BitVector *MightReachAnyUse;
|
|
static BitVector *alldefs;
|
|
static BitVector *alluses;
|
|
static BitVector *defset;
|
|
static BitVector *useset;
|
|
IROUse *IRO_FirstVarUse;
|
|
IROUse *IRO_LastVarUse;
|
|
|
|
// forward decls
|
|
static void AddDefToRange(IRODef *def);
|
|
|
|
static void MakeDef(VarRecord *var, IROLinear *linear, IRONode *node, Boolean flag) {
|
|
IRODef *def = oalloc(sizeof(IRODef));
|
|
|
|
def->index = NumDefs++;
|
|
def->node = node;
|
|
def->linear = linear;
|
|
def->var = var;
|
|
def->globalnext = NULL;
|
|
def->x18 = 0;
|
|
def->x1A = Inline_IsObjectData(var->object);
|
|
def->x1B = var->xB;
|
|
def->x1C = flag;
|
|
def->x1D = 0;
|
|
|
|
if (FirstDef)
|
|
LastDef->globalnext = def;
|
|
else
|
|
FirstDef = def;
|
|
LastDef = def;
|
|
|
|
def->varnext = var->defs;
|
|
var->defs = def;
|
|
}
|
|
|
|
static void MakeUse(VarRecord *var, IROLinear *linear, IRONode *node) {
|
|
IROUse *use = oalloc(sizeof(IROUse));
|
|
|
|
use->index = NumUses++;
|
|
use->node = node;
|
|
use->linear = linear;
|
|
use->var = var;
|
|
use->globalnext = NULL;
|
|
use->x1C = 0;
|
|
|
|
if (IRO_FirstVarUse)
|
|
IRO_LastVarUse->globalnext = use;
|
|
else
|
|
IRO_FirstVarUse = use;
|
|
IRO_LastVarUse = use;
|
|
|
|
use->varnext = var->uses;
|
|
var->uses = use;
|
|
}
|
|
|
|
static void FindDefsAndUses(void) {
|
|
VarRecord *var;
|
|
IROLinear *linear;
|
|
IRONode *node;
|
|
|
|
NumDefs = 0;
|
|
NumUses = 0;
|
|
IRO_FirstVarUse = NULL;
|
|
FirstDef = NULL;
|
|
|
|
for (var = IRO_FirstVar; var; var = var->next) {
|
|
var->defs = NULL;
|
|
var->uses = NULL;
|
|
var->xC = 0;
|
|
}
|
|
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
for (linear = node->first; linear; linear = linear->next) {
|
|
if (IS_LINEAR_ENODE(linear, EOBJREF)) {
|
|
Object *obj = linear->u.node->data.objref;
|
|
if ((linear->flags & IROLF_Ind) && (!(linear->flags & IROLF_Assigned) || (linear->flags & IROLF_Used))) {
|
|
if ((var = IRO_FindVar(obj, 0, 1)))
|
|
MakeUse(var, linear, node);
|
|
}
|
|
}
|
|
|
|
if (IRO_IsAssignment(linear) && (var = IRO_FindAssigned(linear))) {
|
|
MakeDef(
|
|
var,
|
|
linear,
|
|
node,
|
|
(linear->rtype->size == var->object->type->size) && !IRO_IsBitField
|
|
);
|
|
}
|
|
|
|
if (linear->type == IROLinearAsm) {
|
|
IAEffects effects;
|
|
int i;
|
|
CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
|
|
|
|
for (i = 0; i < effects.numoperands; i++) {
|
|
var = IRO_FindVar(effects.operands[i].object, 0, 1);
|
|
switch (effects.operands[i].type) {
|
|
case IAEffect_0:
|
|
MakeUse(var, linear, node);
|
|
break;
|
|
case IAEffect_1:
|
|
MakeDef(
|
|
var,
|
|
linear,
|
|
node,
|
|
(effects.operands[i].offset == 0) && (effects.operands[i].size == var->object->type->size)
|
|
);
|
|
break;
|
|
case IAEffect_2:
|
|
MakeDef(var, linear, node, 0);
|
|
break;
|
|
case IAEffect_4:
|
|
MakeUse(var, linear, node);
|
|
MakeDef(
|
|
var,
|
|
linear,
|
|
node,
|
|
(effects.operands[i].offset == 0) && (effects.operands[i].size == var->object->type->size)
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (linear == node->last)
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (var = IRO_FirstVar; var; var = var->next)
|
|
MakeDef(var, NULL, NULL, 1);
|
|
}
|
|
|
|
static void MarkUses(Object *obj) {
|
|
VarRecord *var;
|
|
IRODef *def;
|
|
|
|
if ((var = IRO_FindVar(obj, 0, 1))) {
|
|
for (def = var->defs; def; def = def->varnext) {
|
|
if (Bv_IsBitSet(def->index, Reaches)) {
|
|
Bv_SetBit(def->index, MightReachAnyUse);
|
|
def->x18++;
|
|
}
|
|
}
|
|
|
|
var->xC = 1;
|
|
}
|
|
}
|
|
|
|
static Boolean IsIncOrDec(IROLinear *linear) {
|
|
switch (linear->type) {
|
|
case IROLinearOp1Arg:
|
|
if (linear->nodetype == EPOSTINC || linear->nodetype == EPOSTDEC || linear->nodetype == EPREINC || linear->nodetype == EPREDEC) {
|
|
if (!(linear->u.monadic->flags & IROLF_BitfieldIndirect))
|
|
return 1;
|
|
}
|
|
break;
|
|
case IROLinearOp2Arg:
|
|
if (linear->nodetype == EADDASS || linear->nodetype == ESUBASS) {
|
|
if (IRO_IsIntConstant(linear->u.diadic.right) && !(linear->u.diadic.left->flags & IROLF_BitfieldIndirect))
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Boolean IsOtherSelfAssignment(IROLinear *linear) {
|
|
switch (linear->type) {
|
|
case IROLinearOp2Arg:
|
|
switch (linear->nodetype) {
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
if (IRO_IsIntConstant(linear->u.diadic.right))
|
|
return 1;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
CInt64 IRO_GetSelfAssignmentVal(IROLinear *linear) {
|
|
CInt64 result;
|
|
|
|
if (linear->type == IROLinearOp1Arg) {
|
|
switch (linear->nodetype) {
|
|
case EPOSTINC:
|
|
case EPREINC:
|
|
CInt64_SetLong(&result, 1);
|
|
break;
|
|
case EPOSTDEC:
|
|
case EPREDEC:
|
|
CInt64_SetLong(&result, -1);
|
|
break;
|
|
default:
|
|
#line 445
|
|
CError_FATAL();
|
|
}
|
|
|
|
if (IS_TYPE_POINTER_ONLY(linear->rtype)) {
|
|
CInt64 mul;
|
|
CInt64_SetLong(&mul, TPTR_TARGET(linear->rtype)->size);
|
|
result = CInt64_Mul(result, mul);
|
|
}
|
|
} else if (linear->type == IROLinearOp2Arg) {
|
|
switch (linear->nodetype) {
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
result = linear->u.diadic.right->u.node->data.intval;
|
|
break;
|
|
case ESUBASS:
|
|
result = linear->u.diadic.right->u.node->data.intval;
|
|
result = CInt64_Neg(result);
|
|
break;
|
|
default:
|
|
#line 491
|
|
CError_FATAL();
|
|
}
|
|
} else {
|
|
#line 496
|
|
CError_FATAL();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void UpdateUse(IROLinear *linear, CInt64 val, Type *type) {
|
|
IROLinear *father;
|
|
IROLinear *repl;
|
|
IROLinear *newdiadic;
|
|
|
|
if ((father = IRO_LocateFather(linear))) {
|
|
switch (father->type) {
|
|
case IROLinearOp1Arg:
|
|
switch (father->nodetype) {
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
val = CInt64_Add(val, IRO_GetSelfAssignmentVal(father));
|
|
father->nodetype = EADDASS;
|
|
father->type = IROLinearOp2Arg;
|
|
repl = IRO_NewIntConst(val, type);
|
|
father->u.diadic.right = repl;
|
|
IRO_PasteAfter(repl, repl, linear);
|
|
return;
|
|
}
|
|
break;
|
|
case IROLinearOp2Arg:
|
|
if (IRO_IsIntConstant(father->u.diadic.right)) {
|
|
switch (father->nodetype) {
|
|
case EADD:
|
|
case EADDASS:
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Add(
|
|
father->u.diadic.right->u.node->data.intval, val);
|
|
return;
|
|
case ESUB:
|
|
case ESUBASS:
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Sub(
|
|
father->u.diadic.right->u.node->data.intval, val);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
repl = IRO_NewIntConst(val, type);
|
|
newdiadic = IRO_NewLinear(IROLinearOp2Arg);
|
|
newdiadic->index = ++IRO_NumLinear;
|
|
newdiadic->nodetype = EADD;
|
|
newdiadic->u.diadic.left = linear;
|
|
newdiadic->u.diadic.right = repl;
|
|
newdiadic->rtype = linear->rtype;
|
|
repl->next = newdiadic;
|
|
IRO_LocateFather_Cut_And_Paste_Without_Nopping(linear, newdiadic);
|
|
IRO_PasteAfter(repl, newdiadic, linear);
|
|
}
|
|
|
|
void IRO_InitializeNonAssignmentOpArray(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < MAXEXPR; i++)
|
|
IRO_NonAssignmentOp[i] = MAXEXPR;
|
|
|
|
IRO_NonAssignmentOp[EPOSTINC] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EPOSTDEC] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EPREINC] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EPREDEC] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EINDIRECT] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EMONMIN] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EBINNOT] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ELOGNOT] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EFORCELOAD] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EMUL] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EMULV] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EDIV] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EMODULO] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EADDV] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ESUBV] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EADD] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ESUB] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ESHL] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ESHR] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ELESS] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EGREATER] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ELESSEQU] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EGREATEREQU] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EEQU] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ENOTEQU] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EAND] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EXOR] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EOR] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ELAND] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ELOR] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EASS] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EMULASS] = EMUL;
|
|
IRO_NonAssignmentOp[EDIVASS] = EDIV;
|
|
IRO_NonAssignmentOp[EMODASS] = EMODULO;
|
|
IRO_NonAssignmentOp[EADDASS] = EADD;
|
|
IRO_NonAssignmentOp[ESUBASS] = ESUB;
|
|
IRO_NonAssignmentOp[ESHLASS] = ESHL;
|
|
IRO_NonAssignmentOp[ESHRASS] = ESHR;
|
|
IRO_NonAssignmentOp[EANDASS] = EAND;
|
|
IRO_NonAssignmentOp[EXORASS] = EXOR;
|
|
IRO_NonAssignmentOp[EORASS] = EOR;
|
|
IRO_NonAssignmentOp[ECOMMA] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EPMODULO] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EROTL] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EROTR] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EBCLR] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EBTST] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EBSET] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ETYPCON] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EBITFIELD] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EINTCONST] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EFLOATCONST] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ESTRINGCONST] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ECOND] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EFUNCCALL] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EFUNCCALLP] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EOBJREF] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EMFPOINTER] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ENULLCHECK] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EPRECOMP] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ETEMP] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EARGOBJ] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ELOCOBJ] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ELABEL] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ESETCONST] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ENEWEXCEPTION] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ENEWEXCEPTIONARRAY] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EOBJLIST] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EMEMBER] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ETEMPLDEP] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EINSTRUCTION] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EDEFINE] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EREUSE] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EASSBLK] = MAXEXPR;
|
|
IRO_NonAssignmentOp[EVECTOR128CONST] = MAXEXPR;
|
|
IRO_NonAssignmentOp[ECONDASS] = MAXEXPR;
|
|
}
|
|
|
|
void IRO_InitializeAssignmentFoldingFunctionArray(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < MAXEXPR; i++)
|
|
AssignmentFoldingFunction[i] = NULL;
|
|
|
|
AssignmentFoldingFunction[EPOSTINC] = NULL;
|
|
AssignmentFoldingFunction[EPOSTDEC] = NULL;
|
|
AssignmentFoldingFunction[EPREINC] = NULL;
|
|
AssignmentFoldingFunction[EPREDEC] = NULL;
|
|
AssignmentFoldingFunction[EINDIRECT] = NULL;
|
|
AssignmentFoldingFunction[EMONMIN] = NULL;
|
|
AssignmentFoldingFunction[EBINNOT] = NULL;
|
|
AssignmentFoldingFunction[ELOGNOT] = NULL;
|
|
AssignmentFoldingFunction[EFORCELOAD] = NULL;
|
|
AssignmentFoldingFunction[EMUL] = NULL;
|
|
AssignmentFoldingFunction[EMULV] = NULL;
|
|
AssignmentFoldingFunction[EDIV] = NULL;
|
|
AssignmentFoldingFunction[EMODULO] = NULL;
|
|
AssignmentFoldingFunction[EADDV] = NULL;
|
|
AssignmentFoldingFunction[ESUBV] = NULL;
|
|
AssignmentFoldingFunction[EADD] = NULL;
|
|
AssignmentFoldingFunction[ESUB] = NULL;
|
|
AssignmentFoldingFunction[ESHL] = NULL;
|
|
AssignmentFoldingFunction[ESHR] = NULL;
|
|
AssignmentFoldingFunction[ELESS] = NULL;
|
|
AssignmentFoldingFunction[EGREATER] = NULL;
|
|
AssignmentFoldingFunction[ELESSEQU] = NULL;
|
|
AssignmentFoldingFunction[EGREATEREQU] = NULL;
|
|
AssignmentFoldingFunction[EEQU] = NULL;
|
|
AssignmentFoldingFunction[ENOTEQU] = NULL;
|
|
AssignmentFoldingFunction[EAND] = NULL;
|
|
AssignmentFoldingFunction[EXOR] = NULL;
|
|
AssignmentFoldingFunction[EOR] = NULL;
|
|
AssignmentFoldingFunction[ELAND] = NULL;
|
|
AssignmentFoldingFunction[ELOR] = NULL;
|
|
AssignmentFoldingFunction[EASS] = NULL;
|
|
AssignmentFoldingFunction[EMULASS] = CInt64_Mul;
|
|
AssignmentFoldingFunction[EDIVASS] = CInt64_Mul;
|
|
AssignmentFoldingFunction[EMODASS] = NULL;
|
|
AssignmentFoldingFunction[EADDASS] = CInt64_Add;
|
|
AssignmentFoldingFunction[ESUBASS] = CInt64_Add;
|
|
AssignmentFoldingFunction[ESHLASS] = CInt64_Add;
|
|
AssignmentFoldingFunction[ESHRASS] = CInt64_Add;
|
|
AssignmentFoldingFunction[EANDASS] = CInt64_And;
|
|
AssignmentFoldingFunction[EXORASS] = CInt64_Xor;
|
|
AssignmentFoldingFunction[EORASS] = CInt64_Or;
|
|
AssignmentFoldingFunction[ECOMMA] = NULL;
|
|
AssignmentFoldingFunction[EPMODULO] = NULL;
|
|
AssignmentFoldingFunction[EROTL] = NULL;
|
|
AssignmentFoldingFunction[EROTR] = NULL;
|
|
AssignmentFoldingFunction[EBCLR] = NULL;
|
|
AssignmentFoldingFunction[EBTST] = NULL;
|
|
AssignmentFoldingFunction[EBSET] = NULL;
|
|
AssignmentFoldingFunction[ETYPCON] = NULL;
|
|
AssignmentFoldingFunction[EBITFIELD] = NULL;
|
|
AssignmentFoldingFunction[EINTCONST] = NULL;
|
|
AssignmentFoldingFunction[EFLOATCONST] = NULL;
|
|
AssignmentFoldingFunction[ESTRINGCONST] = NULL;
|
|
AssignmentFoldingFunction[ECOND] = NULL;
|
|
AssignmentFoldingFunction[EFUNCCALL] = NULL;
|
|
AssignmentFoldingFunction[EFUNCCALLP] = NULL;
|
|
AssignmentFoldingFunction[EOBJREF] = NULL;
|
|
AssignmentFoldingFunction[EMFPOINTER] = NULL;
|
|
AssignmentFoldingFunction[ENULLCHECK] = NULL;
|
|
AssignmentFoldingFunction[EPRECOMP] = NULL;
|
|
AssignmentFoldingFunction[ETEMP] = NULL;
|
|
AssignmentFoldingFunction[EARGOBJ] = NULL;
|
|
AssignmentFoldingFunction[ELOCOBJ] = NULL;
|
|
AssignmentFoldingFunction[ELABEL] = NULL;
|
|
AssignmentFoldingFunction[ESETCONST] = NULL;
|
|
AssignmentFoldingFunction[ENEWEXCEPTION] = NULL;
|
|
AssignmentFoldingFunction[ENEWEXCEPTIONARRAY] = NULL;
|
|
AssignmentFoldingFunction[EOBJLIST] = NULL;
|
|
AssignmentFoldingFunction[EMEMBER] = NULL;
|
|
AssignmentFoldingFunction[ETEMPLDEP] = NULL;
|
|
AssignmentFoldingFunction[EINSTRUCTION] = NULL;
|
|
AssignmentFoldingFunction[EDEFINE] = NULL;
|
|
AssignmentFoldingFunction[EREUSE] = NULL;
|
|
AssignmentFoldingFunction[EASSBLK] = NULL;
|
|
AssignmentFoldingFunction[EVECTOR128CONST] = NULL;
|
|
AssignmentFoldingFunction[ECONDASS] = NULL;
|
|
}
|
|
|
|
static void UpdateUseForOtherSelfAssignment(IROLinear *a, IROLinear *b, Type *type) {
|
|
CInt64 val;
|
|
IROLinear *father;
|
|
IROLinear *repl;
|
|
IROLinear *newdiadic;
|
|
|
|
val = IRO_GetSelfAssignmentVal(b);
|
|
if ((father = IRO_LocateFather(a)) && father->type == IROLinearOp2Arg && IRO_IsIntConstant(father->u.diadic.right)) {
|
|
CInt64 var_30 = father->u.diadic.right->u.node->data.intval;
|
|
if (AssignmentFoldingFunction[b->nodetype] && ((father->nodetype == b->nodetype) || (father->nodetype == IRO_NonAssignmentOp[b->nodetype]))) {
|
|
CInt64 v;
|
|
CInt64 folded;
|
|
CInt64_SetLong(&v, b->rtype->size * 8);
|
|
folded = AssignmentFoldingFunction[b->nodetype](var_30, val);
|
|
if (b->nodetype == ESHRASS && !is_unsigned(b->rtype)) {
|
|
if (CInt64_LessU(var_30, v) && CInt64_LessU(val, v)) {
|
|
if (CInt64_GreaterEqualU(folded, v))
|
|
folded = CInt64_Sub(v, cint64_one);
|
|
father->u.diadic.right->u.node->data.intval = folded;
|
|
return;
|
|
}
|
|
} else {
|
|
father->u.diadic.right->u.node->data.intval = folded;
|
|
return;
|
|
}
|
|
} else {
|
|
switch (b->nodetype) {
|
|
case EMULASS:
|
|
if (father->nodetype == ESHL || father->nodetype == ESHLASS) {
|
|
SInt32 powvalue;
|
|
if (IRO_IsPow2(b->u.diadic.right, &powvalue)) {
|
|
if (powvalue > 0) {
|
|
CInt64 v;
|
|
CInt64_SetLong(&v, powvalue);
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Add(v, var_30);
|
|
}
|
|
} else {
|
|
father->nodetype = (father->nodetype == ESHL) ? EMUL : EMULASS;
|
|
var_30 = CInt64_Shl(cint64_one, var_30);
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
case EDIVASS:
|
|
if ((father->nodetype == ESHR || father->nodetype == ESHRASS) && is_unsigned(father->rtype)) {
|
|
SInt32 powvalue;
|
|
if (IRO_IsPow2(b->u.diadic.right, &powvalue)) {
|
|
if (powvalue > 0) {
|
|
CInt64 v;
|
|
CInt64_SetLong(&v, powvalue);
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Add(v, var_30);
|
|
}
|
|
} else {
|
|
father->nodetype = (father->nodetype == ESHR) ? EDIV : EDIVASS;
|
|
var_30 = CInt64_Shl(cint64_one, var_30);
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
case ESHLASS:
|
|
if (father->nodetype == EMUL || father->nodetype == EMULASS) {
|
|
SInt32 powvalue;
|
|
if (IRO_IsPow2(father->u.diadic.right, &powvalue)) {
|
|
if (powvalue > 0) {
|
|
CInt64 v;
|
|
father->nodetype = (father->nodetype == EMUL) ? ESHL : ESHLASS;
|
|
CInt64_SetLong(&v, powvalue);
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Add(v, val);
|
|
}
|
|
} else {
|
|
val = CInt64_Shl(cint64_one, val);
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val);
|
|
}
|
|
return;
|
|
} else if (father->nodetype == ESHR || father->nodetype == ESHRASS) {
|
|
if (CInt64_Equal(var_30, val) && is_unsigned(father->rtype)) {
|
|
father->nodetype = (father->nodetype == ESHR) ? EAND : EANDASS;
|
|
if (father->rtype->size < 8) {
|
|
CInt64 v;
|
|
CInt64_SetLong(&v, 64 - (father->rtype->size * 8));
|
|
val = CInt64_Add(val, v);
|
|
}
|
|
father->u.diadic.right->u.node->data.intval = CInt64_ShrU(cint64_negone, val);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case ESHRASS:
|
|
if ((father->nodetype == EDIV || father->nodetype == EDIVASS) && is_unsigned(father->rtype)) {
|
|
SInt32 powvalue;
|
|
if (IRO_IsPow2(father->u.diadic.right, &powvalue)) {
|
|
if (powvalue > 0) {
|
|
CInt64 v;
|
|
father->nodetype = (father->nodetype == EDIV) ? ESHR : ESHRASS;
|
|
CInt64_SetLong(&v, powvalue);
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Add(v, val);
|
|
}
|
|
} else {
|
|
val = CInt64_Shl(cint64_one, val);
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val);
|
|
}
|
|
return;
|
|
} else if (father->nodetype == ESHL || father->nodetype == ESHLASS) {
|
|
if (CInt64_Equal(var_30, val)) {
|
|
father->nodetype = (father->nodetype == ESHL) ? EAND : EANDASS;
|
|
father->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_negone, val);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
repl = IRO_NewIntConst(val, type);
|
|
newdiadic = IRO_NewLinear(IROLinearOp2Arg);
|
|
newdiadic->index = ++IRO_NumLinear;
|
|
newdiadic->nodetype = IRO_NonAssignmentOp[b->nodetype];
|
|
newdiadic->u.diadic.left = a;
|
|
newdiadic->u.diadic.right = repl;
|
|
newdiadic->rtype = a->rtype;
|
|
repl->next = newdiadic;
|
|
IRO_LocateFather_Cut_And_Paste_Without_Nopping(a, newdiadic);
|
|
IRO_PasteAfter(repl, newdiadic, a);
|
|
}
|
|
|
|
static Boolean PropagateIncsAndDecs(void) {
|
|
IRODef *def;
|
|
Boolean result;
|
|
|
|
result = 0;
|
|
def = FirstDef;
|
|
while (def) {
|
|
if (
|
|
def->linear &&
|
|
def->x1C &&
|
|
IsIncOrDec(def->linear) &&
|
|
!(def->linear->flags & IROLF_Reffed) &&
|
|
(IS_TYPE_INT_OR_ENUM(def->linear->rtype) || IS_TYPE_POINTER_ONLY(def->linear->rtype)) &&
|
|
IRO_TypesEqual(def->linear->rtype, def->var->object->type) &&
|
|
!is_volatile_object(def->var->object)
|
|
) {
|
|
IROUse *use;
|
|
IROUse *use2;
|
|
IROLinear *father;
|
|
CInt64 val;
|
|
SInt32 i;
|
|
Type *type;
|
|
|
|
for (use = def->var->uses, i = 0; use; use = use->varnext) {
|
|
if (Bv_IsBitSet(def->index, use->x18)) {
|
|
if (
|
|
use->x1C == 1 &&
|
|
use->linear->type == IROLinearOperand &&
|
|
(father = IRO_LocateFather(use->linear)) &&
|
|
IRO_IsVariable(father) &&
|
|
IRO_TypesEqual(def->linear->rtype, father->rtype)
|
|
) {
|
|
if (use->linear->flags & IROLF_Assigned) {
|
|
if (!((father = IRO_LocateFather(father)) && IsIncOrDec(father) && !(father->flags & IROLF_Reffed)))
|
|
goto nextDef;
|
|
}
|
|
i++;
|
|
} else {
|
|
goto nextDef;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i == def->x18) {
|
|
for (use = def->var->uses; use; use = use->varnext) {
|
|
if (Bv_IsBitSet(def->index, use->x18)) {
|
|
IRO_Dump("Propagating inc/dec from %d to %d\n", def->linear->index, use->linear->index);
|
|
father = IRO_LocateFather(use->linear);
|
|
val = IRO_GetSelfAssignmentVal(def->linear);
|
|
type = def->linear->rtype;
|
|
if (IS_TYPE_POINTER_ONLY(def->linear->rtype))
|
|
type = TYPE(&stunsignedlong);
|
|
UpdateUse(father, val, type);
|
|
|
|
result = 1;
|
|
for (use2 = def->var->uses; use2; use2 = use2->varnext) {
|
|
if (use2->linear == def->linear->u.monadic->u.diadic.left) {
|
|
use->x1C = use2->x1C;
|
|
Bv_Copy(use2->x18, use->x18);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
def->x18 = 0;
|
|
IRO_NopNonSideEffects(def->linear, -1);
|
|
def->linear->type = IROLinearNop;
|
|
IRO_Dump("Removing deadddd assignment %d\n", def->linear->index);
|
|
}
|
|
}
|
|
nextDef:
|
|
def = def->globalnext;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static Boolean PropagateOtherSelfAssignments(void) {
|
|
IRODef *def;
|
|
Boolean result;
|
|
|
|
result = 0;
|
|
|
|
def = FirstDef;
|
|
while (def) {
|
|
if (
|
|
def->linear &&
|
|
def->x1C &&
|
|
IsOtherSelfAssignment(def->linear) &&
|
|
!(def->linear->flags & IROLF_Reffed) &&
|
|
IS_TYPE_INT_OR_ENUM(def->linear->rtype) &&
|
|
IRO_TypesEqual(def->linear->rtype, def->var->object->type) &&
|
|
!is_volatile_object(def->var->object)
|
|
)
|
|
{
|
|
IROUse *use;
|
|
IROUse *use2;
|
|
IROLinear *father;
|
|
SInt32 i;
|
|
Type *type;
|
|
|
|
for (use = def->var->uses, i = 0; use; use = use->varnext) {
|
|
if (Bv_IsBitSet(def->index, use->x18)) {
|
|
if (
|
|
use->x1C == 1 &&
|
|
use->linear->type == IROLinearOperand &&
|
|
(father = IRO_LocateFather(use->linear)) &&
|
|
IRO_IsVariable(father) &&
|
|
IRO_TypesEqual(def->linear->rtype, father->rtype)
|
|
) {
|
|
if (use->linear->flags & IROLF_Assigned) {
|
|
if (!((father = IRO_LocateFather(father)) && IsOtherSelfAssignment(father) && (father->nodetype == def->linear->nodetype) && !(father->flags & IROLF_Reffed)))
|
|
goto nextDef;
|
|
}
|
|
i++;
|
|
} else {
|
|
goto nextDef;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i == def->x18) {
|
|
for (use = def->var->uses; use; use = use->varnext) {
|
|
if (Bv_IsBitSet(def->index, use->x18)) {
|
|
IRO_Dump("Propagating self assignment from %d to %d\n", def->linear->index, use->linear->index);
|
|
father = IRO_LocateFather(use->linear);
|
|
UpdateUseForOtherSelfAssignment(father, def->linear, def->linear->rtype);
|
|
|
|
result = 1;
|
|
for (use2 = def->var->uses; use2; use2 = use2->varnext) {
|
|
if (use2->linear == def->linear->u.monadic->u.diadic.left) {
|
|
use->x1C = use2->x1C;
|
|
Bv_Copy(use2->x18, use->x18);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
def->x18 = 0;
|
|
IRO_NopNonSideEffects(def->linear, -1);
|
|
def->linear->type = IROLinearNop;
|
|
IRO_Dump("Removing deadddd assignment %d\n", def->linear->index);
|
|
}
|
|
}
|
|
nextDef:
|
|
def = def->globalnext;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void MarkUsesByIndirect(IROLinear *linear, BitVector *a, BitVector *b) {
|
|
IROListNode *list;
|
|
IROLinear *nd;
|
|
Object *obj;
|
|
VarRecord *var;
|
|
Boolean foundObjRef;
|
|
IROListNode *scan;
|
|
IRODef *def;
|
|
Boolean found;
|
|
|
|
found = 0;
|
|
|
|
if (linear && copts.opt_pointer_analysis && linear->pointsToFunction && FunctionName) {
|
|
IROListNode *resultList;
|
|
resultList = NULL;
|
|
PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, linear, &resultList);
|
|
if ((list = resultList)) {
|
|
for (scan = list; scan; scan = scan->nextList) {
|
|
if (!scan->list.head || !scan->list.tail) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
|
|
foundObjRef = 0;
|
|
for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
|
|
if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
|
|
foundObjRef = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundObjRef) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
while (list) {
|
|
for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) {
|
|
if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
|
|
obj = nd->u.node->data.objref;
|
|
#line 1422
|
|
CError_ASSERT(obj != NULL);
|
|
var = IRO_FindVar(obj, 1, 1);
|
|
#line 1424
|
|
CError_ASSERT(var != NULL);
|
|
|
|
for (def = var->defs; def; def = def->varnext) {
|
|
if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) {
|
|
def->x18++;
|
|
Bv_SetBit(def->index, MightReachAnyUse);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
list = list->nextList;
|
|
}
|
|
}
|
|
|
|
while (resultList) {
|
|
IROListNode *next = resultList->nextList;
|
|
IRO_free(resultList);
|
|
resultList = next;
|
|
}
|
|
} else {
|
|
found = 1;
|
|
}
|
|
} else {
|
|
found = 1;
|
|
}
|
|
|
|
if (found) {
|
|
Bv_Copy(Reaches, a);
|
|
Bv_And(b, a);
|
|
Bv_Or(a, MightReachAnyUse);
|
|
for (def = FirstDef; def; def = def->globalnext) {
|
|
if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches)))
|
|
def->x18++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void MarkUsesByFunctionCall(IROLinear *linear, BitVector *a, BitVector *b) {
|
|
ObjectList *olist;
|
|
IROLinear *funcnd;
|
|
IROListNode *list;
|
|
IROLinear *nd;
|
|
Object *obj;
|
|
VarRecord *var;
|
|
Boolean foundObjRef;
|
|
IROListNode *scan;
|
|
IRODef *def;
|
|
Boolean found;
|
|
|
|
found = 0;
|
|
|
|
if ((funcnd = linear->u.funccall.linear8) && copts.opt_pointer_analysis && funcnd->pointsToFunction && FunctionName) {
|
|
IROListNode *resultList;
|
|
ObjectList *depsList;
|
|
|
|
resultList = NULL;
|
|
PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, funcnd, &resultList);
|
|
if (resultList) {
|
|
for (scan = resultList; scan; scan = scan->nextList) {
|
|
if (!scan->list.head || !scan->list.tail) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
|
|
foundObjRef = 0;
|
|
for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
|
|
if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
|
|
foundObjRef = 1;
|
|
obj = nd->u.node->data.objref;
|
|
#line 1522
|
|
CError_ASSERT(obj != NULL);
|
|
|
|
depsList = NULL;
|
|
PointerAnalysis_GetFunctionDependencies(obj, linear, &depsList);
|
|
for (olist = depsList; olist; olist = olist->next) {
|
|
if (!olist->object) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (depsList) {
|
|
olist = depsList->next;
|
|
IRO_free(depsList);
|
|
depsList = olist;
|
|
}
|
|
|
|
if (found)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundObjRef)
|
|
found = 1;
|
|
if (found)
|
|
break;
|
|
}
|
|
|
|
if (!found) {
|
|
for (list = resultList; list; list = list->nextList) {
|
|
for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) {
|
|
if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
|
|
obj = nd->u.node->data.objref;
|
|
depsList = NULL;
|
|
PointerAnalysis_GetFunctionDependencies(obj, linear, &depsList);
|
|
|
|
for (olist = depsList; olist; olist = olist->next) {
|
|
var = IRO_FindVar(olist->object, 1, 1);
|
|
#line 1573
|
|
CError_ASSERT(var != NULL);
|
|
|
|
for (def = var->defs; def; def = def->varnext) {
|
|
if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) {
|
|
def->x18++;
|
|
Bv_SetBit(def->index, MightReachAnyUse);
|
|
}
|
|
}
|
|
}
|
|
|
|
while (depsList) {
|
|
olist = depsList->next;
|
|
IRO_free(depsList);
|
|
depsList = olist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
while (resultList) {
|
|
IROListNode *next = resultList->nextList;
|
|
IRO_free(resultList);
|
|
resultList = next;
|
|
}
|
|
} else {
|
|
found = 1;
|
|
}
|
|
} else {
|
|
found = 1;
|
|
}
|
|
|
|
if (found) {
|
|
Bv_Copy(Reaches, a);
|
|
Bv_And(b, a);
|
|
Bv_Or(a, MightReachAnyUse);
|
|
for (def = FirstDef; def; def = def->globalnext) {
|
|
if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches)))
|
|
def->x18++;
|
|
}
|
|
}
|
|
|
|
if (linear->stmt && IRO_FunctionCallMightThrowException(linear))
|
|
IRO_WalkExcActions(linear->stmt->dobjstack, MarkUses);
|
|
}
|
|
|
|
static Boolean UseOfVarIsInsideASimpleDefOfVar(IROUse *use) {
|
|
VarRecord *var;
|
|
VarRecord *varAss;
|
|
IROLinear *nd;
|
|
IROLinear *nd2;
|
|
|
|
if ((var = use->var)) {
|
|
if ((nd = use->linear) && (nd->flags & IROLF_4000))
|
|
return 0;
|
|
|
|
while (nd && (nd->flags & IROLF_Reffed))
|
|
nd = nd->next;
|
|
|
|
if (
|
|
nd &&
|
|
IRO_IsAssignment(nd) &&
|
|
(varAss = IRO_FindAssigned(nd)) &&
|
|
varAss == var &&
|
|
!IRO_HasSideEffect((nd->type == IROLinearOp1Arg) ? nd->u.monadic : nd->u.diadic.left) &&
|
|
(!(nd2 = (nd->type == IROLinearOp1Arg) ? NULL : nd->u.diadic.right) || !IRO_HasSideEffect(nd2))
|
|
) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Boolean AllLoopDefUsesAreInSimpleLoopDefs(IRODef *def) {
|
|
VarRecord *var;
|
|
IRODef *scan;
|
|
IROUse *use;
|
|
|
|
if ((var = def->var)) {
|
|
for (scan = var->defs; scan; scan = scan->varnext) {
|
|
if (scan->node && scan->node->loopdepth) {
|
|
for (use = var->uses; use; use = use->varnext) {
|
|
if (Bv_IsBitSet(scan->index, use->x18)) {
|
|
if (!use->node || !use->node->loopdepth || !UseOfVarIsInsideASimpleDefOfVar(use))
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void MarkRemovableLoopDefs(void) {
|
|
IRODef *def;
|
|
IRODef *scan;
|
|
|
|
for (def = FirstDef; def; def = def->globalnext) {
|
|
if (!def->x1A && !def->x1B && def->node && def->node->loopdepth && !def->x1D &&
|
|
AllLoopDefUsesAreInSimpleLoopDefs(def) && def->var) {
|
|
for (scan = def->var->defs; scan; scan = scan->varnext) {
|
|
if (scan->node && scan->node->loopdepth)
|
|
scan->x1D = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static Boolean EliminateReffedDeadStore(IRODef *def) {
|
|
Boolean isPostIncOrDec;
|
|
IROLinear *nd;
|
|
Boolean result;
|
|
|
|
nd = def->linear;
|
|
isPostIncOrDec = (nd->type == IROLinearOp1Arg) && (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC);
|
|
|
|
result = IRO_LocateFather(nd) != NULL;
|
|
if (result && IRO_IsAssignment(nd) && IRO_IsModifyOp[nd->nodetype])
|
|
result = IRO_TransformSelfAssignmentToAssignment(nd);
|
|
result = result && (nd->type == IROLinearOp2Arg) && (nd->nodetype == EASS);
|
|
|
|
if (result) {
|
|
def->x18 = 0;
|
|
IRO_Dump("Removing referenced dead assignment %d\n", nd->index);
|
|
|
|
if (isPostIncOrDec) {
|
|
IRO_NopNonSideEffects(nd->u.diadic.right, 0);
|
|
nd->type = IROLinearNop;
|
|
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, nd->u.diadic.left);
|
|
} else {
|
|
IRO_NopNonSideEffects(nd->u.diadic.left, 0);
|
|
nd->type = IROLinearNop;
|
|
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, nd->u.diadic.right);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Boolean IRO_UseDef(Boolean optDeadAssignments, Boolean optPropagation) {
|
|
Boolean result;
|
|
IRODef *gdef;
|
|
IROUse *guse;
|
|
IRODef *def;
|
|
IROUse *use;
|
|
IRONode *node;
|
|
IROLinear *nd;
|
|
VarRecord *var;
|
|
Boolean flag;
|
|
BitVector *bv3;
|
|
BitVector *bv2;
|
|
BitVector *bv;
|
|
int i;
|
|
|
|
FindDefsAndUses();
|
|
|
|
IRO_CheckForUserBreak();
|
|
|
|
for (use = IRO_FirstVarUse; use; use = use->globalnext)
|
|
Bv_AllocVector(&use->x18, NumDefs);
|
|
Bv_AllocVector(&MightReachAnyUse, NumDefs);
|
|
Bv_AllocVector(&bv, NumDefs);
|
|
|
|
IRO_CheckForUserBreak();
|
|
|
|
for (def = FirstDef; def; def = def->globalnext) {
|
|
if (def->x1A || def->x1B)
|
|
Bv_SetBit(def->index, bv);
|
|
}
|
|
|
|
Bv_AllocVector(&bv2, NumDefs);
|
|
gdef = FirstDef;
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
Bv_AllocVector(&node->x16, NumDefs);
|
|
Bv_AllocVector(&node->x1E, NumDefs);
|
|
Bv_AllocVector(&node->x22, NumDefs);
|
|
Bv_AllocVector(&node->x1A, NumDefs);
|
|
|
|
for (nd = node->first; nd; nd = nd->next) {
|
|
while (gdef && gdef->linear == nd) {
|
|
Bv_SetBit(gdef->index, node->x1E);
|
|
if (gdef->x1C) {
|
|
for (def = gdef->var->defs; def; def = def->varnext) {
|
|
if (def != gdef) {
|
|
Bv_SetBit(def->index, node->x22);
|
|
Bv_ClearBit(def->index, node->x1E);
|
|
}
|
|
}
|
|
}
|
|
gdef = gdef->globalnext;
|
|
}
|
|
if (nd == node->last)
|
|
break;
|
|
}
|
|
|
|
if (node->numpred)
|
|
Bv_Set(node->x16);
|
|
Bv_Copy(node->x1E, node->x1A);
|
|
IRO_CheckForUserBreak();
|
|
}
|
|
|
|
Bv_AllocVector(&bv3, NumDefs);
|
|
|
|
do {
|
|
flag = 0;
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
Bv_Clear(node->x16);
|
|
if (node->numpred) {
|
|
for (i = 0; i < node->numpred; i++)
|
|
Bv_Or(IRO_NodeTable[node->pred[i]]->x1A, node->x16);
|
|
} else if (node == IRO_FirstNode) {
|
|
for (var = IRO_FirstVar; var; var = var->next)
|
|
Bv_SetBit(var->defs->index, node->x16);
|
|
}
|
|
Bv_Copy(node->x16, bv3);
|
|
Bv_Minus(node->x22, bv3);
|
|
Bv_Or(node->x1E, bv3);
|
|
if (!Bv_Compare(bv3, node->x1A)) {
|
|
Bv_Copy(bv3, node->x1A);
|
|
flag = 1;
|
|
}
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
} while (flag);
|
|
|
|
gdef = FirstDef;
|
|
guse = IRO_FirstVarUse;
|
|
Bv_AllocVector(&Reaches, NumDefs);
|
|
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
Bv_Copy(node->x16, Reaches);
|
|
nd = node->first;
|
|
while (1) {
|
|
while (guse && guse->linear == nd) {
|
|
for (def = guse->var->defs; def; def = def->varnext) {
|
|
if (Bv_IsBitSet(def->index, Reaches)) {
|
|
Bv_SetBit(def->index, guse->x18);
|
|
Bv_SetBit(def->index, MightReachAnyUse);
|
|
def->x18++;
|
|
guse->x1C++;
|
|
}
|
|
}
|
|
guse = guse->globalnext;
|
|
}
|
|
|
|
if (nd->type == IROLinearFunccall) {
|
|
MarkUsesByFunctionCall(nd, bv2, bv);
|
|
} else if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT && !IRO_IsVariable(nd)) {
|
|
MarkUsesByIndirect(nd, bv2, bv);
|
|
} else if ((nd->type == IROLinearFunccall) ||
|
|
(nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT && !IRO_IsVariable(nd))) {
|
|
Bv_Copy(Reaches, bv2);
|
|
Bv_And(bv, bv2);
|
|
Bv_Or(bv2, MightReachAnyUse);
|
|
for (def = FirstDef; def; def = def->globalnext) {
|
|
if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches)))
|
|
def->x18++;
|
|
}
|
|
if (nd->type == IROLinearFunccall && nd->stmt && IRO_FunctionCallMightThrowException(nd))
|
|
IRO_WalkExcActions(nd->stmt->dobjstack, MarkUses);
|
|
}
|
|
|
|
if (nd->type == IROLinearAsm) {
|
|
IAEffects effects;
|
|
CodeGen_GetAsmEffects(nd->u.asm_stmt, &effects);
|
|
if (effects.x2) {
|
|
Bv_Copy(Reaches, bv2);
|
|
Bv_And(bv, bv2);
|
|
Bv_Or(bv2, MightReachAnyUse);
|
|
}
|
|
}
|
|
|
|
if (nd->type == IROLinearReturn || nd->type == IROLinearEnd) {
|
|
for (def = FirstDef; def; def = def->globalnext) {
|
|
if (def->x1A && Bv_IsBitSet(def->index, Reaches)) {
|
|
Bv_SetBit(def->index, MightReachAnyUse);
|
|
def->x18++;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (gdef && gdef->linear == nd) {
|
|
if (gdef->x1C) {
|
|
for (def = gdef->var->defs; def; def = def->varnext)
|
|
Bv_ClearBit(def->index, Reaches);
|
|
}
|
|
Bv_SetBit(gdef->index, Reaches);
|
|
gdef = gdef->globalnext;
|
|
}
|
|
|
|
if (nd == node->last)
|
|
break;
|
|
nd = nd->next;
|
|
}
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
|
|
result = 0;
|
|
|
|
if (optDeadAssignments) {
|
|
MarkRemovableLoopDefs();
|
|
for (def = FirstDef; def; def = def->globalnext) {
|
|
if (def->linear &&
|
|
(!Bv_IsBitSet(def->index, MightReachAnyUse) || def->x1D) &&
|
|
(copts.opt_pointer_analysis || !def->x1B) &&
|
|
def->linear->type != IROLinearAsm &&
|
|
(!def->linear->rtype || !CParser_IsVolatile(def->linear->rtype, def->linear->nodeflags & ENODE_FLAG_QUALS)) &&
|
|
!is_volatile_object(def->var->object)
|
|
) {
|
|
if (!(def->linear->flags & IROLF_Reffed)) {
|
|
def->x18 = 0;
|
|
IRO_NopNonSideEffects(def->linear, -1);
|
|
def->linear->type = IROLinearNop;
|
|
IRO_Dump("Removing dead assignment %d\n", def->linear->index);
|
|
result = 1;
|
|
} else {
|
|
result = EliminateReffedDeadStore(def);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
|
|
if (optPropagation) {
|
|
while (1) {
|
|
if (PropagateIncsAndDecs() || PropagateOtherSelfAssignments())
|
|
result = 1;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
|
|
return result;
|
|
}
|
|
|
|
static IROLinear *GetOperand(IROLinear *nd) {
|
|
IROLinear *inner;
|
|
|
|
if (nd->type == IROLinearOperand)
|
|
return nd;
|
|
|
|
if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD) {
|
|
inner = GetOperand(nd->u.diadic.left);
|
|
if (!inner)
|
|
inner = GetOperand(nd->u.diadic.right);
|
|
return inner;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static IROLinear *GetAssigned(IROLinear *nd) {
|
|
if (!nd)
|
|
return NULL;
|
|
|
|
if (nd->type == IROLinearOp2Arg) {
|
|
nd = nd->u.diadic.left;
|
|
} else if (nd->type == IROLinearOp1Arg) {
|
|
nd = nd->u.monadic;
|
|
} else {
|
|
#line 2338
|
|
CError_FATAL();
|
|
}
|
|
|
|
if (nd->type != IROLinearOp1Arg || nd->nodetype != EINDIRECT) {
|
|
#line 2351
|
|
CError_FATAL();
|
|
}
|
|
|
|
nd = nd->u.monadic;
|
|
|
|
if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD)
|
|
nd = GetOperand(nd);
|
|
|
|
return nd;
|
|
}
|
|
|
|
static void AddUseToRange(IROUse *use) {
|
|
IRODef *def;
|
|
|
|
Bv_SetBit(use->index, useset);
|
|
Bv_ClearBit(use->index, alluses);
|
|
|
|
for (def = use->var->defs; def; def = def->varnext) {
|
|
if (Bv_IsBitSet(def->index, alldefs) && (Bv_IsBitSet(def->index, use->x18) || GetAssigned(def->linear) == use->linear))
|
|
AddDefToRange(def);
|
|
}
|
|
}
|
|
|
|
static void AddDefToRange(IRODef *def) {
|
|
IROUse *use;
|
|
IROLinear *assigned;
|
|
|
|
Bv_SetBit(def->index, defset);
|
|
Bv_ClearBit(def->index, alldefs);
|
|
|
|
for (use = def->var->uses, assigned = GetAssigned(def->linear); use; use = use->varnext) {
|
|
if (Bv_IsBitSet(use->index, alluses) && (Bv_IsBitSet(def->index, use->x18) || assigned == use->linear))
|
|
AddUseToRange(use);
|
|
}
|
|
}
|
|
|
|
static void ReplaceAssigned(IROLinear *nd, Object *from, Object *to) {
|
|
IROLinear *assigned;
|
|
|
|
if (
|
|
!(assigned = GetAssigned(nd)) ||
|
|
assigned->type != IROLinearOperand ||
|
|
assigned->u.node->type != EOBJREF ||
|
|
assigned->u.node->data.objref != from
|
|
) {
|
|
#line 2459
|
|
CError_FATAL();
|
|
}
|
|
|
|
assigned->u.node->data.objref = to;
|
|
}
|
|
|
|
static void ReplaceUsed(IROLinear *nd, Object *from, Object *to) {
|
|
#line 2482
|
|
CError_ASSERT(nd->type == IROLinearOperand && nd->u.node->type == EOBJREF);
|
|
|
|
if (nd->u.node->data.objref == from) {
|
|
nd->u.node->data.objref = to;
|
|
} else if (nd->u.node->data.objref != to) {
|
|
#line 2494
|
|
CError_FATAL();
|
|
}
|
|
}
|
|
|
|
static void SplitOffRange(VarRecord *var) {
|
|
Object *newObj;
|
|
IRODef *def;
|
|
IROUse *use;
|
|
|
|
IRO_Dump("Splitting range for variable: %d\n", var->index);
|
|
IRO_DumpBits("Def set: ", defset);
|
|
IRO_DumpBits("Use set: ", useset);
|
|
IRO_DumpBits("All defs: ", alldefs);
|
|
IRO_DumpBits("All uses: ", alluses);
|
|
|
|
newObj = create_temp_object(var->object->type);
|
|
IRO_FindVar(newObj, 1, 1);
|
|
|
|
for (def = var->defs; def; def = def->varnext) {
|
|
if (Bv_IsBitSet(def->index, defset) && def->linear)
|
|
ReplaceAssigned(def->linear, var->object, newObj);
|
|
}
|
|
|
|
for (use = var->uses; use; use = use->varnext) {
|
|
if (Bv_IsBitSet(use->index, useset))
|
|
ReplaceUsed(use->linear, var->object, newObj);
|
|
}
|
|
}
|
|
|
|
void IRO_SplitLifetimes(void) {
|
|
VarRecord *var;
|
|
SInt32 numVars;
|
|
IRODef *def;
|
|
IROUse *use;
|
|
Boolean flag;
|
|
|
|
Bv_AllocVector(&alldefs, NumDefs);
|
|
Bv_AllocVector(&alluses, NumUses);
|
|
Bv_AllocVector(&defset, NumDefs);
|
|
Bv_AllocVector(&useset, NumUses);
|
|
|
|
var = IRO_FirstVar;
|
|
numVars = IRO_NumVars;
|
|
|
|
while (var && var->index <= numVars) {
|
|
if (var->object->datatype == DLOCAL && !is_volatile_object(var->object) && !var->xC && !var->xB && !var->x1E) {
|
|
Bv_Clear(alldefs);
|
|
Bv_Clear(alluses);
|
|
|
|
for (def = var->defs; def; def = def->varnext) {
|
|
if (def->linear && def->linear->type == IROLinearAsm)
|
|
goto skipThisVar;
|
|
Bv_SetBit(def->index, alldefs);
|
|
}
|
|
|
|
for (use = var->uses; use; use = use->varnext) {
|
|
if (use->linear && use->linear->type == IROLinearAsm)
|
|
goto skipThisVar;
|
|
Bv_SetBit(use->index, alluses);
|
|
}
|
|
|
|
flag = 1;
|
|
while (1) {
|
|
Bv_Clear(defset);
|
|
Bv_Clear(useset);
|
|
|
|
def = var->defs;
|
|
while (def && !Bv_IsBitSet(def->index, alldefs))
|
|
def = def->varnext;
|
|
|
|
if (!def)
|
|
break;
|
|
|
|
AddDefToRange(def);
|
|
if (Bv_IsEmpty(alldefs))
|
|
break;
|
|
|
|
if (!flag)
|
|
SplitOffRange(var);
|
|
flag = 0;
|
|
}
|
|
}
|
|
|
|
skipThisVar:
|
|
var = var->next;
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
}
|