mirror of
https://git.wuffs.org/MWCC
synced 2025-07-01 23:53:28 +00:00
haha it's been a while since i last committed, hasn't it
This commit is contained in:
parent
9d2728a560
commit
25bab8b1fb
@ -158,6 +158,7 @@ add_executable(mwcc
|
||||
compiler_and_linker/unsorted/UseDefChains.c
|
||||
compiler_and_linker/unsorted/LoadDeletion.c
|
||||
compiler_and_linker/unsorted/VectorArraysToRegs.c
|
||||
compiler_and_linker/unsorted/LiveInfo.c
|
||||
|
||||
compiler_and_linker/unsorted/InterferenceGraph.c
|
||||
compiler_and_linker/unsorted/SpillCode.c
|
||||
|
@ -0,0 +1,271 @@
|
||||
#include "compiler/AddPropagation.h"
|
||||
#include "compiler/Alias.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/CopyPropagation.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeInfo.h"
|
||||
#include "compiler/StackFrame.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/objects.h"
|
||||
|
||||
int propagatedadds;
|
||||
|
||||
static int is_add(PCode *instr) {
|
||||
return
|
||||
(
|
||||
instr->op == PC_ADD ||
|
||||
(
|
||||
instr->op == PC_ADDI &&
|
||||
(
|
||||
instr->args[2].kind == PCOp_IMMEDIATE ||
|
||||
(instr->args[2].kind == PCOp_MEMORY && (unsigned char) instr->args[2].arg == 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
&&
|
||||
instr->args[0].data.reg.reg >= n_real_registers[(char) instr->args[0].arg];
|
||||
}
|
||||
|
||||
static int addpropagatestouse(int candidateID, int useID) {
|
||||
int reg2;
|
||||
PCode *candidateInstr;
|
||||
PCode *useInstr;
|
||||
int reg1;
|
||||
int reg27;
|
||||
Object *object;
|
||||
SInt32 offset;
|
||||
int i;
|
||||
PCode *instr;
|
||||
PCodeArg *op;
|
||||
|
||||
candidateInstr = Candidates[candidateID].pcode;
|
||||
useInstr = Uses[useID].pcode;
|
||||
reg1 = candidateInstr->args[0].data.reg.reg;
|
||||
reg2 = candidateInstr->args[1].data.reg.reg;
|
||||
reg27 = reg2;
|
||||
|
||||
if (!useInstr->block) {
|
||||
recursive_propagation = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (useInstr->flags & (fPCodeFlag2 | fPCodeFlag4)) {
|
||||
if (PCODE_FLAG_SET_F(useInstr) & fPCodeFlag2000000)
|
||||
return 0;
|
||||
} else if (useInstr->op == PC_ADDI) {
|
||||
if (useInstr->args[2].kind != PCOp_IMMEDIATE)
|
||||
return 0;
|
||||
} else if (useInstr->op != PC_MR) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (candidateInstr->op == PC_ADD) {
|
||||
if (useInstr->argCount < 3) {
|
||||
if (useInstr->op != PC_MR)
|
||||
return 0;
|
||||
} else if (useInstr->args[2].kind == PCOp_IMMEDIATE) {
|
||||
if (useInstr->args[2].data.imm.value != 0)
|
||||
return 0;
|
||||
} else if (useInstr->args[2].kind == PCOp_REGISTER) {
|
||||
if (
|
||||
useInstr->args[1].kind != PCOp_REGISTER ||
|
||||
useInstr->args[2].data.reg.reg != reg1 ||
|
||||
useInstr->args[1].data.reg.reg != 0
|
||||
)
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
object = NULL;
|
||||
offset = 0;
|
||||
if (candidateInstr->alias && candidateInstr->alias->type == AliasType0) {
|
||||
object = candidateInstr->alias->object;
|
||||
offset = candidateInstr->alias->offset;
|
||||
}
|
||||
reg27 = candidateInstr->args[2].data.reg.reg;
|
||||
} else if (candidateInstr->op == PC_ADDI) {
|
||||
if (candidateInstr->alias && candidateInstr->alias->type == AliasType0) {
|
||||
object = candidateInstr->alias->object;
|
||||
offset = candidateInstr->alias->offset;
|
||||
} else if (candidateInstr->args[2].kind == PCOp_MEMORY) {
|
||||
object = candidateInstr->args[2].data.mem.obj;
|
||||
offset = candidateInstr->args[2].data.mem.offset;
|
||||
} else if (candidateInstr->args[2].kind == PCOp_IMMEDIATE) {
|
||||
object = NULL;
|
||||
offset = candidateInstr->args[2].data.imm.value;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (useInstr->argCount < 3) {
|
||||
if (useInstr->op != PC_MR)
|
||||
return 0;
|
||||
} else if (useInstr->args[2].kind == PCOp_IMMEDIATE) {
|
||||
offset += useInstr->args[2].data.imm.value;
|
||||
if (object) {
|
||||
if (object->datatype == DLOCAL) {
|
||||
if (!can_add_displ_to_local(object, offset))
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (!FITS_IN_SHORT(offset)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
#line 225
|
||||
CError_FATAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (
|
||||
(useInstr->flags & fPCodeFlag4) &&
|
||||
useInstr->args[0].kind == PCOp_REGISTER &&
|
||||
useInstr->args[0].arg == RegClass_GPR &&
|
||||
useInstr->args[0].data.reg.reg == reg1
|
||||
)
|
||||
return 0;
|
||||
|
||||
if (useInstr->args[1].data.reg.reg != reg1)
|
||||
return 0;
|
||||
|
||||
if (candidateInstr->block == useInstr->block && precedes(candidateInstr, useInstr)) {
|
||||
for (instr = candidateInstr->nextPCode; instr && instr != useInstr; instr = instr->nextPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
(op->data.reg.reg == reg2 || op->data.reg.reg == reg27)
|
||||
)
|
||||
return 0;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!bitvectorgetbit(candidateID, propinfo[useInstr->block->blockIndex].vec8))
|
||||
return 0;
|
||||
|
||||
for (instr = useInstr->block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
if (instr == useInstr)
|
||||
break;
|
||||
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
(op->data.reg.reg == reg2 || op->data.reg.reg == reg27)
|
||||
)
|
||||
return 0;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((useInstr->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag20000 | fPCodeFlag40000)) && object)
|
||||
useInstr->alias = make_alias(object, offset, nbytes_loaded_or_stored_by(useInstr));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void propagateandremoveadd(int id) {
|
||||
PCode *instr;
|
||||
RegUseOrDef *list;
|
||||
Candidate *candidate;
|
||||
PCode *useInstr;
|
||||
|
||||
candidate = Candidates + id;
|
||||
instr = candidate->pcode;
|
||||
|
||||
if (instr->op == PC_ADDI && instr->args[2].kind == PCOp_MEMORY)
|
||||
instr->alias = make_alias(instr->args[2].data.mem.obj, instr->args[2].data.mem.offset, 1);
|
||||
|
||||
for (list = candidate->list; list; list = list->next) {
|
||||
useInstr = Uses[list->id].pcode;
|
||||
|
||||
if (instr->op == PC_ADD) {
|
||||
if (useInstr->flags & (fPCodeFlag2 | fPCodeFlag4)) {
|
||||
if (useInstr->args[2].kind != PCOp_REGISTER) {
|
||||
useInstr->op += 2;
|
||||
useInstr->flags |= fPCodeFlag20;
|
||||
}
|
||||
useInstr->args[1] = instr->args[1];
|
||||
useInstr->args[2] = instr->args[2];
|
||||
useInstr->alias = instr->alias;
|
||||
} else if (useInstr->op == PC_ADDI) {
|
||||
#line 338
|
||||
CError_ASSERT(useInstr->args[2].data.imm.value == 0);
|
||||
change_opcode(useInstr, PC_ADD);
|
||||
useInstr->args[1] = instr->args[1];
|
||||
useInstr->args[2] = instr->args[2];
|
||||
useInstr->alias = instr->alias;
|
||||
} else if (useInstr->op == PC_MR) {
|
||||
change_opcode(useInstr, PC_ADD);
|
||||
useInstr->flags = instr->flags;
|
||||
change_num_operands(useInstr, 3);
|
||||
useInstr->args[1] = instr->args[1];
|
||||
useInstr->args[2] = instr->args[2];
|
||||
useInstr->alias = instr->alias;
|
||||
} else {
|
||||
#line 352
|
||||
CError_FATAL();
|
||||
}
|
||||
} else if (useInstr->op == PC_MR) {
|
||||
change_opcode(useInstr, PC_ADDI);
|
||||
useInstr->flags = instr->flags;
|
||||
useInstr->alias = instr->alias;
|
||||
change_num_operands(useInstr, 3);
|
||||
useInstr->args[1] = instr->args[1];
|
||||
useInstr->args[2] = instr->args[2];
|
||||
} else {
|
||||
useInstr->args[1] = instr->args[1];
|
||||
if (instr->args[2].kind == PCOp_IMMEDIATE) {
|
||||
SInt32 newValue = useInstr->args[2].data.imm.value + instr->args[2].data.imm.value;
|
||||
useInstr->args[2] = instr->args[2];
|
||||
useInstr->args[2].data.imm.value = newValue;
|
||||
useInstr->flags |= fPCodeFlag20;
|
||||
} else if (instr->args[2].kind == PCOp_MEMORY) {
|
||||
SInt32 newValue = useInstr->args[2].data.imm.value + instr->args[2].data.mem.offset;
|
||||
useInstr->args[2] = instr->args[2];
|
||||
useInstr->args[2].data.mem.offset = newValue;
|
||||
useInstr->flags &= ~fPCodeFlag20;
|
||||
if (useInstr->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag20000 | fPCodeFlag40000))
|
||||
useInstr->alias = make_alias(
|
||||
useInstr->args[2].data.mem.obj,
|
||||
useInstr->args[2].data.mem.offset,
|
||||
nbytes_loaded_or_stored_by(useInstr));
|
||||
} else {
|
||||
#line 382
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deletepcode(instr);
|
||||
propagatedadds = 1;
|
||||
}
|
||||
|
||||
static Propagation add_prop = {
|
||||
&is_add,
|
||||
&addpropagatestouse,
|
||||
&propagateandremoveadd,
|
||||
"ADD",
|
||||
"ADDS",
|
||||
"a%ld",
|
||||
0
|
||||
};
|
||||
|
||||
void propagateaddinstructions(Object *proc) {
|
||||
propagateinstructions(proc, &add_prop, (copts.optimizationlevel >= 4) ? 4 : 1, 1);
|
||||
propagatedadds = propagated_instructions;
|
||||
}
|
@ -0,0 +1,766 @@
|
||||
#include "compiler/Alias.h"
|
||||
#include "compiler/CClass.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/CMachine.h"
|
||||
#include "compiler/CodeGen.h"
|
||||
#include "compiler/CopyPropagation.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeInfo.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
#include "compiler/UseDefChains.h"
|
||||
#include "compiler/ValueNumbering.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/types.h"
|
||||
|
||||
static Alias *aliases;
|
||||
static int n_aliases;
|
||||
static int n_gathered_aliases;
|
||||
static Alias *alias_hash[997];
|
||||
Alias *worst_case;
|
||||
Object worst_case_obj;
|
||||
|
||||
static TypePointer worst_case_memory_type = {
|
||||
TYPEARRAY,
|
||||
0xFFFFFF,
|
||||
TYPE(&stchar)
|
||||
};
|
||||
|
||||
static Boolean is_safe_const(Object *obj) {
|
||||
Type *type;
|
||||
|
||||
type = obj->type;
|
||||
while (IS_TYPE_ARRAY(type))
|
||||
type = TPTR_TARGET(type);
|
||||
|
||||
if (TYPE_FITS_IN_REGISTER(type) || IS_TYPE_VECTOR(type) || IS_TYPE_FLOAT(type) || IS_TYPE_STRUCT(type))
|
||||
return is_const_object(obj);
|
||||
|
||||
if (IS_TYPE_CLASS(type))
|
||||
return is_const_object(obj) && CClass_IsPODClass(TYPE_CLASS(type));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initialize_aliases(void) {
|
||||
int i;
|
||||
|
||||
memclrw(&worst_case_obj, sizeof(Object));
|
||||
worst_case_obj.otype = OT_OBJECT;
|
||||
worst_case_obj.type = TYPE(&worst_case_memory_type);
|
||||
worst_case_obj.datatype = DDATA;
|
||||
worst_case_obj.name = GetHashNameNodeExport("@worst_case@");
|
||||
|
||||
aliases = NULL;
|
||||
n_aliases = 0;
|
||||
n_gathered_aliases = 0;
|
||||
for (i = 0; i < 997; i++)
|
||||
alias_hash[i] = NULL;
|
||||
|
||||
worst_case = make_alias_set();
|
||||
add_alias_member(worst_case, make_alias(&worst_case_obj, 0, 0));
|
||||
}
|
||||
|
||||
static UInt32 hash_alias(Object *object, SInt32 offset, SInt32 size) {
|
||||
return (UInt32) (object->name->hashval * offset * size) % 997;
|
||||
}
|
||||
|
||||
static Alias *create_alias(AliasType type, Object *object, SInt32 offset, SInt32 size, Boolean addToHash) {
|
||||
Alias *alias;
|
||||
UInt32 hash;
|
||||
|
||||
alias = lalloc(sizeof(Alias));
|
||||
memclrw(alias, sizeof(Alias));
|
||||
alias->type = type;
|
||||
alias->index = n_aliases++;
|
||||
alias->next = aliases;
|
||||
aliases = alias;
|
||||
alias->object = object;
|
||||
alias->offset = offset;
|
||||
alias->size = size;
|
||||
|
||||
if (addToHash) {
|
||||
hash = hash_alias(object, offset, size);
|
||||
alias->hashNext = alias_hash[hash];
|
||||
alias_hash[hash] = alias;
|
||||
}
|
||||
|
||||
return alias;
|
||||
}
|
||||
|
||||
static Alias *lookup_alias(Object *object, SInt32 offset, SInt32 size) {
|
||||
Alias *scan;
|
||||
|
||||
for (scan = alias_hash[hash_alias(object, offset, size)]; scan; scan = scan->hashNext) {
|
||||
if (scan->object == object && scan->offset == offset && scan->size == size)
|
||||
return scan;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Alias *make_alias(Object *object, SInt32 offset, SInt32 size) {
|
||||
Alias *alias;
|
||||
Alias *alias2;
|
||||
|
||||
if (!offset && !size)
|
||||
size = object->type->size;
|
||||
|
||||
alias = lookup_alias(object, offset, size);
|
||||
if (!alias) {
|
||||
if (offset > 0 || size != object->type->size) {
|
||||
alias2 = make_alias(object, 0, object->type->size);
|
||||
alias = create_alias(AliasType1, object, offset, size, 1);
|
||||
add_alias_member(alias2, alias);
|
||||
} else {
|
||||
alias = create_alias(AliasType0, object, offset, size, 1);
|
||||
}
|
||||
|
||||
switch (object->datatype) {
|
||||
case DLOCAL:
|
||||
case DNONLAZYPTR:
|
||||
break;
|
||||
default:
|
||||
if (!is_safe_const(object))
|
||||
add_alias_member(worst_case, make_alias(object, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (offset > object->type->size)
|
||||
return NULL;
|
||||
else
|
||||
return alias;
|
||||
}
|
||||
|
||||
Alias *make_alias_set(void) {
|
||||
return create_alias(AliasType2, NULL, 0, 0, 0);
|
||||
}
|
||||
|
||||
void add_alias_member(Alias *parent, Alias *child) {
|
||||
AliasMember *member;
|
||||
|
||||
if (child->type == AliasType2) {
|
||||
for (member = child->parents; member; member = member->nextParent)
|
||||
add_alias_member(parent, member->child);
|
||||
} else {
|
||||
if (parent == worst_case && child->type == AliasType1)
|
||||
child = make_alias(child->object, 0, 0);
|
||||
|
||||
for (member = parent->parents; member; member = member->nextParent) {
|
||||
if (member->child == child)
|
||||
return;
|
||||
}
|
||||
|
||||
member = lalloc(sizeof(AliasMember));
|
||||
member->parent = parent;
|
||||
member->child = child;
|
||||
member->nextParent = parent->parents;
|
||||
parent->parents = member;
|
||||
member->nextChild = child->children;
|
||||
child->children = member;
|
||||
}
|
||||
}
|
||||
|
||||
Alias *make_alias_set_from_IR(void) {
|
||||
#line 333
|
||||
CError_FATAL();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Boolean aliases_overlap(Alias *a, Alias *b) {
|
||||
return (
|
||||
a->offset == b->offset ||
|
||||
(a->offset > b->offset && a->offset < (b->offset + b->size)) ||
|
||||
(b->offset > a->offset && b->offset < (a->offset + a->size))
|
||||
);
|
||||
}
|
||||
|
||||
static int is_address_load(PCode *pcode) {
|
||||
Object *obj;
|
||||
|
||||
switch (pcode->op) {
|
||||
case PC_LWZ:
|
||||
if (pcode->args[2].kind == PCOp_MEMORY && pcode->args[2].data.mem.obj->datatype == DNONLAZYPTR)
|
||||
return 1;
|
||||
break;
|
||||
case PC_LBZU:
|
||||
case PC_LBZUX:
|
||||
case PC_LHZU:
|
||||
case PC_LHZUX:
|
||||
case PC_LHAU:
|
||||
case PC_LHAUX:
|
||||
case PC_LWZU:
|
||||
case PC_LWZUX:
|
||||
case PC_STBU:
|
||||
case PC_STBUX:
|
||||
case PC_STHU:
|
||||
case PC_STHUX:
|
||||
case PC_STWU:
|
||||
case PC_STWUX:
|
||||
return 1;
|
||||
case PC_ADDI:
|
||||
case PC_ADDIS:
|
||||
if (pcode->args[0].data.reg.reg < n_real_registers[RegClass_GPR]) {
|
||||
if (pcode->args[2].kind == PCOp_MEMORY) {
|
||||
obj = pcode->args[2].data.mem.obj;
|
||||
if (obj->datatype == DLOCAL && !is_safe_const(obj))
|
||||
add_alias_member(worst_case, make_alias(obj, 0, 0));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case PC_ADD:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int addresspropagatestouse(int candidateID, int useID) {
|
||||
PCode *candidate_pcode; // r30
|
||||
PCode *use_pcode; // r29
|
||||
int reg; // r28
|
||||
short reg2;
|
||||
Object *object; // r27
|
||||
SInt32 offset; // r26
|
||||
Alias *alias; // r25
|
||||
Boolean flag24; // r24
|
||||
SInt32 size; // r23
|
||||
Alias *aliasSet; // r22
|
||||
int i;
|
||||
PCode *scan;
|
||||
PCodeArg *op;
|
||||
|
||||
candidate_pcode = Candidates[candidateID].pcode;
|
||||
use_pcode = Uses[useID].pcode;
|
||||
flag24 = 0;
|
||||
size = 1;
|
||||
reg = candidate_pcode->args[0].data.reg.reg;
|
||||
|
||||
if (candidate_pcode->alias && (candidate_pcode->alias->type == AliasType0 || candidate_pcode->alias->type == AliasType1)) {
|
||||
object = candidate_pcode->alias->object;
|
||||
offset = candidate_pcode->alias->offset;
|
||||
if (offset == 0 && candidate_pcode->alias->size == object->type->size)
|
||||
flag24 = 1;
|
||||
} else if (candidate_pcode->args[2].kind == PCOp_MEMORY) {
|
||||
object = candidate_pcode->args[2].data.mem.obj;
|
||||
if (candidate_pcode->op == PC_ADDIS)
|
||||
offset = candidate_pcode->args[2].data.mem.offset << 16;
|
||||
else
|
||||
offset = candidate_pcode->args[2].data.mem.offset;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#line 478
|
||||
CError_ASSERT(object->otype == OT_OBJECT);
|
||||
|
||||
if ((candidate_pcode->flags & (fPCodeFlag2 | fPCodeFlag4)) && (candidate_pcode->flags & fPCodeFlag2000000)) {
|
||||
reg = candidate_pcode->args[1].data.reg.reg;
|
||||
offset = 0;
|
||||
flag24 = 1;
|
||||
} else if (candidate_pcode->op == PC_LWZ) {
|
||||
if (object->datatype != DNONLAZYPTR)
|
||||
return 0;
|
||||
|
||||
object = object->u.var.realObj;
|
||||
#line 495
|
||||
CError_ASSERT(object->otype == OT_OBJECT);
|
||||
offset = 0;
|
||||
} else if (candidate_pcode->op == PC_ADDI) {
|
||||
if (!candidate_pcode->alias && object)
|
||||
candidate_pcode->alias = make_alias(object, offset, 1);
|
||||
} else if (candidate_pcode->op == PC_ADDIS) {
|
||||
if (!candidate_pcode->alias && object)
|
||||
candidate_pcode->alias = make_alias(object, offset, 1);
|
||||
} else if (candidate_pcode->op == PC_ADD) {
|
||||
offset = 0;
|
||||
flag24 = 1;
|
||||
} else {
|
||||
#line 509
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
if (
|
||||
!(use_pcode->flags & (fPCodeFlag2 | fPCodeFlag4)) &&
|
||||
use_pcode->op != PC_ADDI &&
|
||||
use_pcode->op != PC_ADD &&
|
||||
use_pcode->op != PC_ADDIS
|
||||
) {
|
||||
if (object->datatype == DLOCAL && !is_safe_const(object))
|
||||
add_alias_member(worst_case, make_alias(object, 0, 0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (
|
||||
(use_pcode->flags & (fPCodeFlag4 | fPCodeFlag40000)) &&
|
||||
use_pcode->args[0].kind == PCOp_REGISTER &&
|
||||
use_pcode->args[0].arg == RegClass_GPR &&
|
||||
use_pcode->args[0].data.reg.reg == reg &&
|
||||
object->datatype == DLOCAL &&
|
||||
!is_safe_const(object)
|
||||
)
|
||||
add_alias_member(worst_case, make_alias(object, 0, 0));
|
||||
|
||||
if (use_pcode->argCount < 3)
|
||||
return 1;
|
||||
|
||||
#line 543
|
||||
CError_ASSERT(use_pcode->args[1].kind == PCOp_REGISTER);
|
||||
|
||||
if (candidate_pcode->block == use_pcode->block && precedes(candidate_pcode, use_pcode)) {
|
||||
for (scan = candidate_pcode->nextPCode; scan && scan != use_pcode; scan = scan->nextPCode) {
|
||||
op = scan->args;
|
||||
i = scan->argCount;
|
||||
while (i--) {
|
||||
if (op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
op->data.reg.reg == reg)
|
||||
return 1;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!bitvectorgetbit(candidateID, propinfo[use_pcode->block->blockIndex].vec8)) {
|
||||
if (bitvectorgetbit(candidate_pcode->defID, usedefinfo[use_pcode->block->blockIndex].defvec8)) {
|
||||
for (scan = use_pcode->block->firstPCode; scan && scan != use_pcode; scan = scan->nextPCode) {
|
||||
op = scan->args;
|
||||
i = scan->argCount;
|
||||
while (i--) {
|
||||
if (op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
op->data.reg.reg == reg)
|
||||
return 1;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (scan = use_pcode->block->firstPCode; scan; scan = scan->nextPCode) {
|
||||
if (scan == use_pcode)
|
||||
break;
|
||||
op = scan->args;
|
||||
i = scan->argCount;
|
||||
while (i--) {
|
||||
if (op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
op->data.reg.reg == reg)
|
||||
return 1;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#line 598
|
||||
CError_ASSERT(object != NULL);
|
||||
|
||||
if (use_pcode->op == PC_ADDI || use_pcode->op == PC_ADD || use_pcode->op == PC_ADDIS) {
|
||||
if (use_pcode->args[0].data.reg.reg < n_real_registers[RegClass_GPR] && !is_safe_const(object))
|
||||
add_alias_member(worst_case, make_alias(object, 0, 0));
|
||||
}
|
||||
|
||||
if (use_pcode->flags & (fPCodeFlag2 | fPCodeFlag4))
|
||||
size = nbytes_loaded_or_stored_by(use_pcode);
|
||||
|
||||
if (use_pcode->args[2].kind == PCOp_REGISTER) {
|
||||
if (use_pcode->args[1].data.reg.reg == 0) {
|
||||
if (use_pcode->args[2].data.reg.reg == reg)
|
||||
alias = make_alias(object, offset, size);
|
||||
} else {
|
||||
if (use_pcode->args[1].data.reg.reg == reg)
|
||||
reg2 = use_pcode->args[2].data.reg.reg;
|
||||
else if (use_pcode->args[2].data.reg.reg == reg)
|
||||
reg2 = use_pcode->args[1].data.reg.reg;
|
||||
else
|
||||
return 1;
|
||||
|
||||
for (scan = use_pcode->prevPCode; scan; scan = scan->prevPCode) {
|
||||
if (scan->op == PC_LI && scan->args[0].data.reg.reg == reg2)
|
||||
break;
|
||||
|
||||
for (i = 0; i < scan->argCount; i++) {
|
||||
if (scan->args[i].kind == PCOp_REGISTER &&
|
||||
scan->args[i].arg == RegClass_GPR &&
|
||||
scan->args[i].data.reg.reg == reg2 &&
|
||||
(scan->args[i].data.reg.effect & EffectWrite)) {
|
||||
scan = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!scan)
|
||||
break;
|
||||
}
|
||||
|
||||
if (scan) {
|
||||
offset += scan->args[1].data.mem.offset;
|
||||
alias = make_alias(object, offset, size);
|
||||
} else {
|
||||
alias = make_alias(object, 0, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (use_pcode->args[1].kind != PCOp_REGISTER ||
|
||||
use_pcode->args[1].arg != RegClass_GPR ||
|
||||
use_pcode->args[1].data.reg.reg != reg)
|
||||
return 1;
|
||||
|
||||
if (use_pcode->args[1].data.reg.effect & EffectWrite) {
|
||||
alias = make_alias(object, 0, 0);
|
||||
} else if (use_pcode->args[2].kind == PCOp_IMMEDIATE) {
|
||||
if (use_pcode->op == PC_ADDIS) {
|
||||
offset += use_pcode->args[2].data.imm.value << 16;
|
||||
alias = make_alias(object, offset, 1);
|
||||
} else {
|
||||
offset += use_pcode->args[2].data.imm.value;
|
||||
alias = make_alias(object, offset, size);
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag24)
|
||||
alias = make_alias(object, 0, 0);
|
||||
|
||||
if (!alias)
|
||||
return 1;
|
||||
|
||||
if (!use_pcode->alias) {
|
||||
if (
|
||||
use_pcode->op == PC_ADDI ||
|
||||
use_pcode->op == PC_ADD ||
|
||||
use_pcode->op == PC_ADDIS ||
|
||||
((candidate_pcode->flags & (fPCodeFlag2 | fPCodeFlag4)) && (candidate_pcode->flags & fPCodeFlag2000000))
|
||||
)
|
||||
recursive_propagation = 1;
|
||||
}
|
||||
|
||||
if (use_pcode->alias) {
|
||||
if (use_pcode->alias == worst_case) {
|
||||
add_alias_member(worst_case, make_alias(object, 0, 0));
|
||||
} else if (use_pcode->alias == alias) {
|
||||
return 1;
|
||||
} else if (use_pcode->alias->type == AliasType0 || use_pcode->alias->type == AliasType1) {
|
||||
if (object == use_pcode->alias->object) {
|
||||
use_pcode->alias = make_alias(object, 0, 0);
|
||||
} else {
|
||||
aliasSet = make_alias_set();
|
||||
if (
|
||||
use_pcode->op == PC_ADDI ||
|
||||
use_pcode->op == PC_ADD ||
|
||||
use_pcode->op == PC_ADDIS ||
|
||||
((use_pcode->flags & (fPCodeFlag2 | fPCodeFlag4)) && (use_pcode->flags & fPCodeFlag2000000))
|
||||
) {
|
||||
if (alias->type == AliasType2)
|
||||
add_alias_member(worst_case, alias);
|
||||
else
|
||||
add_alias_member(worst_case, make_alias(use_pcode->alias->object, 0, 0));
|
||||
}
|
||||
add_alias_member(aliasSet, use_pcode->alias);
|
||||
add_alias_member(aliasSet, alias);
|
||||
use_pcode->alias = aliasSet;
|
||||
}
|
||||
} else {
|
||||
add_alias_member(use_pcode->alias, alias);
|
||||
}
|
||||
} else {
|
||||
use_pcode->alias = alias;
|
||||
}
|
||||
|
||||
propagated_instructions = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void finishpropagatealiases(int id) {
|
||||
propagated_instructions = 1;
|
||||
}
|
||||
|
||||
static Propagation alias_prop = {
|
||||
&is_address_load,
|
||||
&addresspropagatestouse,
|
||||
&finishpropagatealiases,
|
||||
"ALIAS",
|
||||
"ALIASES",
|
||||
"A%ld",
|
||||
1
|
||||
};
|
||||
|
||||
static void propagatealiasinfo(Object *proc) {
|
||||
propagateinstructions(proc, &alias_prop, (copts.optimizationlevel >= 4) ? 4 : 1, 1);
|
||||
}
|
||||
|
||||
void gather_alias_info(void) {
|
||||
UInt32 *myvec; // r31
|
||||
Alias *alias; // r22
|
||||
AliasMember *member;
|
||||
AliasMember *member2;
|
||||
PCodeBlock *block; // r21
|
||||
PCode *pcode; // r20
|
||||
PCodeArg *op; // r19
|
||||
RegUseOrDef *list; // r18
|
||||
int i; // r17
|
||||
Alias *alias_choice; // r16
|
||||
int aliases_idx; // r15 (helper in r23)
|
||||
PCode *defpcode; // r14
|
||||
Alias *alias_array[3];
|
||||
UseOrDef *def;
|
||||
int defID;
|
||||
|
||||
if (coloring) {
|
||||
propagatealiasinfo(gFunction);
|
||||
myvec = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
bitvectorcopy(myvec, usedefinfo[block->blockIndex].defvec8, number_of_Defs);
|
||||
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (pcode->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag20000 | fPCodeFlag40000)) {
|
||||
if (!pcode->alias) {
|
||||
pcode->alias = worst_case;
|
||||
} else {
|
||||
if ((pcode->alias->type == AliasType0 || pcode->alias->type == AliasType1) &&
|
||||
pcode->alias->size == nbytes_loaded_or_stored_by(pcode)) {
|
||||
pcode->flags &= ~fPCodeFlag20;
|
||||
} else {
|
||||
pcode->flags |= fPCodeFlag20;
|
||||
}
|
||||
|
||||
if (pcode->alias != worst_case) {
|
||||
aliases_idx = 0;
|
||||
alias_choice = NULL;
|
||||
op = pcode->args;
|
||||
for (i = 0; i < pcode->argCount; i++, op++) {
|
||||
if (
|
||||
(!(pcode->flags & (fPCodeFlag4 | fPCodeFlag40000)) || op != pcode->args) &&
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
(op->data.reg.effect & EffectRead)
|
||||
) {
|
||||
alias_array[aliases_idx] = NULL;
|
||||
if (aliases_idx >= 2) {
|
||||
alias_choice = worst_case;
|
||||
break;
|
||||
}
|
||||
alias_array[aliases_idx] = pcode->alias;
|
||||
|
||||
for (list = reg_Defs[RegClass_GPR][op->data.reg.reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, myvec)) {
|
||||
defpcode = Defs[list->id].pcode;
|
||||
if (!defpcode->alias || !is_address_load(defpcode) || defpcode->alias == worst_case) {
|
||||
alias_array[aliases_idx] = worst_case;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aliases_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alias_choice) {
|
||||
if (aliases_idx > 0) {
|
||||
alias_choice = alias_array[0];
|
||||
if (aliases_idx == 2) {
|
||||
if (alias_array[0] != worst_case) {
|
||||
if (alias_array[1] != worst_case)
|
||||
alias_choice = worst_case;
|
||||
} else if (alias_array[1] != worst_case) {
|
||||
alias_choice = alias_array[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alias_choice == worst_case) {
|
||||
pcode->flags |= fPCodeFlag20;
|
||||
if (pcode->alias->type == AliasType2)
|
||||
add_alias_member(worst_case, pcode->alias);
|
||||
else
|
||||
add_alias_member(worst_case, make_alias(pcode->alias->object, 0, 0));
|
||||
}
|
||||
|
||||
if (alias_choice)
|
||||
pcode->alias = alias_choice;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((pcode->flags & fPCodeFlag8) && !pcode->alias)
|
||||
pcode->alias = worst_case;
|
||||
}
|
||||
|
||||
for (def = &Defs[defID = pcode->defID]; defID < number_of_Defs && def->pcode == pcode; defID++, def++) {
|
||||
if (def->v.kind == PCOp_REGISTER && def->v.arg == RegClass_GPR) {
|
||||
for (list = reg_Defs[RegClass_GPR][def->v.u.reg]; list; list = list->next)
|
||||
bitvectorclearbit(list->id, myvec);
|
||||
}
|
||||
bitvectorsetbit(defID, myvec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeoheap();
|
||||
} else {
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if ((pcode->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag8 | fPCodeFlag20000 | fPCodeFlag40000)) && !pcode->alias)
|
||||
pcode->alias = worst_case;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n_gathered_aliases != n_aliases) {
|
||||
for (alias = aliases; alias; alias = alias->next) {
|
||||
if (alias->type == AliasType2) {
|
||||
alias->vec24 = lalloc(4 * ((n_aliases + 31) >> 35));
|
||||
bitvectorinitialize(alias->vec24, n_aliases, 0);
|
||||
for (member = alias->parents; member; member = member->nextParent) {
|
||||
bitvectorsetbit(member->child->index, alias->vec24);
|
||||
for (member2 = member->child->parents; member2; member2 = member2->nextParent)
|
||||
bitvectorsetbit(member2->child->index, alias->vec24);
|
||||
}
|
||||
}
|
||||
}
|
||||
n_gathered_aliases = n_aliases;
|
||||
}
|
||||
}
|
||||
|
||||
static Boolean may_alias_alias(Alias *a, Alias *b) {
|
||||
switch ((a->type * 3) + b->type) {
|
||||
case (AliasType0 * 3) + AliasType0:
|
||||
return a == b;
|
||||
case (AliasType0 * 3) + AliasType1:
|
||||
case (AliasType1 * 3) + AliasType0:
|
||||
return a->object == b->object;
|
||||
case (AliasType1 * 3) + AliasType1:
|
||||
return (a->object == b->object) && aliases_overlap(a, b);
|
||||
case (AliasType0 * 3) + AliasType2:
|
||||
case (AliasType1 * 3) + AliasType2:
|
||||
return bitvectorgetbit(a->index, b->vec24) != 0;
|
||||
case (AliasType2 * 3) + AliasType0:
|
||||
case (AliasType2 * 3) + AliasType1:
|
||||
return bitvectorgetbit(b->index, a->vec24) != 0;
|
||||
case (AliasType2 * 3) + AliasType2:
|
||||
return (a == b) || !bitvectorintersectionisempty(a->vec24, b->vec24, n_aliases);
|
||||
default:
|
||||
#line 1054
|
||||
CError_FATAL();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Boolean may_alias(PCode *a, PCode *b) {
|
||||
return may_alias_alias(a->alias, b->alias);
|
||||
}
|
||||
|
||||
Boolean uniquely_aliases(PCode *a, PCode *b) {
|
||||
if (may_alias_alias(a->alias, b->alias)) {
|
||||
if (
|
||||
a->alias->type != AliasType2 &&
|
||||
b->alias->type != AliasType2 &&
|
||||
a->alias &&
|
||||
b->alias &&
|
||||
a->alias->size == nbytes_loaded_or_stored_by(a) &&
|
||||
b->alias->size == nbytes_loaded_or_stored_by(b)
|
||||
)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Boolean may_alias_worst_case(PCode *pcode) {
|
||||
return may_alias_alias(pcode->alias, worst_case);
|
||||
}
|
||||
|
||||
Boolean may_alias_object(PCode *pcode, Object *object) {
|
||||
return may_alias_alias(pcode->alias, make_alias(object, 0, 0));
|
||||
}
|
||||
|
||||
void initialize_alias_values(void) {
|
||||
Alias *alias;
|
||||
|
||||
for (alias = aliases; alias; alias = alias->next) {
|
||||
alias->valuenumber = nextvaluenumber++;
|
||||
alias->valuepcode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void update_alias_value(Alias *alias, PCode *pcode) {
|
||||
AliasMember *member;
|
||||
AliasMember *member2;
|
||||
AliasMember *member3;
|
||||
|
||||
switch (alias->type) {
|
||||
case AliasType0:
|
||||
killmemory(alias, pcode);
|
||||
for (member = alias->children; member; member = member->nextChild) {
|
||||
#line 1152
|
||||
CError_ASSERT(member->parent->type == AliasType2);
|
||||
killmemory(member->parent, NULL);
|
||||
}
|
||||
for (member = alias->parents; member; member = member->nextParent) {
|
||||
#line 1157
|
||||
CError_ASSERT(member->child->type == AliasType1);
|
||||
killmemory(member->child, NULL);
|
||||
for (member2 = member->child->children; member2; member2 = member2->nextChild) {
|
||||
if (member2->parent != alias) {
|
||||
#line 1163
|
||||
CError_ASSERT(member2->parent->type == AliasType2);
|
||||
killmemory(member2->parent, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AliasType1:
|
||||
killmemory(alias, pcode);
|
||||
for (member = alias->children; member; member = member->nextChild) {
|
||||
killmemory(member->parent, NULL);
|
||||
if (member->parent->type == AliasType0) {
|
||||
for (member2 = member->parent->parents; member2; member2 = member2->nextParent) {
|
||||
if (member2->child != alias && aliases_overlap(alias, member2->child)) {
|
||||
killmemory(member2->child, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AliasType2:
|
||||
killmemory(alias, NULL);
|
||||
for (member = alias->parents; member; member = member->nextParent) {
|
||||
killmemory(member->child, NULL);
|
||||
for (member2 = member->child->children; member2; member2 = member2->nextChild) {
|
||||
if (member2->parent != alias)
|
||||
killmemory(member2->parent, NULL);
|
||||
}
|
||||
for (member3 = member->child->parents; member3; member3 = member3->nextParent) {
|
||||
killmemory(member3->child, NULL);
|
||||
for (member2 = member3->child->children; member2; member2 = member2->nextChild) {
|
||||
if (member2->parent != member->child)
|
||||
killmemory(member2->parent, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void update_all_alias_values(void) {
|
||||
Alias *alias;
|
||||
|
||||
for (alias = aliases; alias; alias = alias->next)
|
||||
killmemory(alias, NULL);
|
||||
}
|
||||
|
@ -0,0 +1,122 @@
|
||||
#include "compiler/BitVectors.h"
|
||||
|
||||
void bitvectorcopy(UInt32 *dst, UInt32 *src, int len) {
|
||||
int i = (len + 31) >> 5;
|
||||
|
||||
while (i--)
|
||||
*(dst++) = *(src++);
|
||||
}
|
||||
|
||||
int bitvectorchanged(UInt32 *dst, UInt32 *src, int len) {
|
||||
int i = (len + 31) >> 5;
|
||||
int flag = 0;
|
||||
UInt32 v;
|
||||
|
||||
while (i--) {
|
||||
v = *src;
|
||||
if (*dst != v)
|
||||
flag = 1;
|
||||
*dst = v;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
void bitvectorinitialize(UInt32 *vec, int len, UInt32 initval) {
|
||||
int i = (len + 31) >> 5;
|
||||
|
||||
while (i--)
|
||||
*(vec++) = initval;
|
||||
}
|
||||
|
||||
void bitvectorintersect(UInt32 *dst, UInt32 *src, int len) {
|
||||
int i = (len + 31) >> 5;
|
||||
|
||||
while (i--)
|
||||
*(dst++) &= *(src++);
|
||||
}
|
||||
|
||||
void bitvectorunion(UInt32 *dst, UInt32 *src, int len) {
|
||||
int i = (len + 31) >> 5;
|
||||
|
||||
while (i--)
|
||||
*(dst++) |= *(src++);
|
||||
}
|
||||
|
||||
void bitvectordifference(UInt32 *dst, UInt32 *src, int len) {
|
||||
int i = (len + 31) >> 5;
|
||||
|
||||
while (i--)
|
||||
*(dst++) &= ~*(src++);
|
||||
}
|
||||
|
||||
void bitvectorcomplement(UInt32 *dst, UInt32 *src, int len) {
|
||||
int i = (len + 31) >> 5;
|
||||
|
||||
while (i--)
|
||||
*(dst++) = ~*(src++);
|
||||
}
|
||||
|
||||
int bitvectorcount(UInt32 *vec, int len) {
|
||||
static unsigned char nbits[] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
|
||||
};
|
||||
|
||||
UInt32 v;
|
||||
int i = (len + 31) >> 5;
|
||||
int total = 0;
|
||||
|
||||
while (i--) {
|
||||
if ((v = *vec)) {
|
||||
total += nbits[v & 0xFF];
|
||||
total += nbits[(v >> 8) & 0xFF];
|
||||
total += nbits[(v >> 16) & 0xFF];
|
||||
total += nbits[(v >> 24) & 0xFF];
|
||||
}
|
||||
vec++;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int bitvectorisempty(UInt32 *vec, int len) {
|
||||
int i = (len + 31) >> 5;
|
||||
|
||||
while (i--) {
|
||||
if (*vec)
|
||||
return 0;
|
||||
vec++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int bitvectorintersectionisempty(UInt32 *a, UInt32 *b, int len) {
|
||||
int i = (len + 31) >> 5;
|
||||
|
||||
while (i--) {
|
||||
if (*a & *b)
|
||||
return 0;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
@ -904,6 +904,8 @@ static COptBlock *newblock(void) {
|
||||
block->set1[i] = 0;
|
||||
block->set2[i] = 0;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
static void MarkFollow(COptBlock *block) {
|
||||
@ -1369,6 +1371,8 @@ static CLabel *finallabel(CLabel *label, Statement *stmt) {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
static void optimizegoto(Statement *stmt) {
|
||||
@ -1399,6 +1403,76 @@ static void removeif(Statement *stmt, Boolean flag) {
|
||||
}
|
||||
|
||||
static void optimizeif(Statement *stmt) {
|
||||
Statement *scan;
|
||||
Statement *scan2;
|
||||
Boolean flag;
|
||||
|
||||
if (iszero(stmt->expr)) {
|
||||
removeif(stmt, 0);
|
||||
return;
|
||||
}
|
||||
if (isnotzero(stmt->expr)) {
|
||||
removeif(stmt, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (scan = stmt->next, flag = 0; scan; scan = scan->next) {
|
||||
if (scan->type > ST_LABEL) {
|
||||
if (scan->type == ST_GOTO) {
|
||||
if (scan->label == stmt->label) {
|
||||
stmt->type = ST_EXPRESSION;
|
||||
stmtchanged = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
for (scan2 = scan->next; scan2; scan2 = scan2->next) {
|
||||
if (scan2->type > ST_LABEL)
|
||||
break;
|
||||
if (stmt->label->stmt == scan2) {
|
||||
stmt->label = scan->label;
|
||||
scan->type = ST_NOP;
|
||||
if (stmt->type == ST_IFGOTO)
|
||||
stmt->type = ST_IFNGOTO;
|
||||
else
|
||||
stmt->type = ST_IFGOTO;
|
||||
stmtchanged = 1;
|
||||
stmt->label = finallabel(stmt->label, stmt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (scan->type == ST_RETURN && !scan->expr && !static_for_inlines && !flag) {
|
||||
for (scan2 = scan->next; scan2; scan2 = scan2->next) {
|
||||
if (scan2->type > ST_LABEL)
|
||||
break;
|
||||
if (stmt->label->stmt == scan2) {
|
||||
stmt->label = cleanreturnlabel;
|
||||
needs_cleanup = 1;
|
||||
scan->type = ST_NOP;
|
||||
if (stmt->type == ST_IFGOTO)
|
||||
stmt->type = ST_IFNGOTO;
|
||||
else
|
||||
stmt->type = ST_IFGOTO;
|
||||
stmtchanged = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (scan->type == ST_LABEL)
|
||||
flag = 1;
|
||||
|
||||
if (stmt->label->stmt == scan) {
|
||||
stmt->type = ST_EXPRESSION;
|
||||
stmtchanged = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
stmt->label = finallabel(stmt->label, stmt);
|
||||
}
|
||||
|
||||
static void optimizeswitch(Statement *stmt) {
|
||||
|
@ -0,0 +1,916 @@
|
||||
#include "compiler/CodeMotion.h"
|
||||
#include "compiler/Alias.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/LoopDetection.h"
|
||||
#include "compiler/LoopOptimization.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/UseDefChains.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
|
||||
int movedloopinvariantcode;
|
||||
int unswitchedinvariantcode;
|
||||
|
||||
static int isloopinvariant(PCode *pcode, Loop *loop, UInt32 *vec, int flag1, int flag2) {
|
||||
PCodeArg *op;
|
||||
RegUseOrDef *list;
|
||||
int i;
|
||||
|
||||
if (pcode->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag20000 | fPCodeFlag40000)) {
|
||||
if (pcode->alias) {
|
||||
if (pcode->alias->type == AliasType2 || (pcode->flags & (fIsVolatile | fSideEffects)))
|
||||
return 0;
|
||||
|
||||
if (pcode->flags & fPCodeFlag2) {
|
||||
for (list = findobjectusedef(pcode->alias->object)->defs; list; list = list->next) {
|
||||
if (
|
||||
may_alias(pcode, Defs[list->id].pcode) &&
|
||||
bitvectorgetbit(list->id, vec) &&
|
||||
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcode->flags & fPCodeFlag4) {
|
||||
for (list = findobjectusedef(pcode->alias->object)->uses; list; list = list->next) {
|
||||
if (
|
||||
may_alias(pcode, Uses[list->id].pcode) &&
|
||||
bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pcode->flags & fPCodeFlag4) && !bitvectorgetbit(pcode->block->blockIndex, loop->vec2C))
|
||||
return 0;
|
||||
|
||||
op = pcode->args;
|
||||
i = pcode->argCount;
|
||||
while (i--) {
|
||||
switch (op->kind) {
|
||||
case PCOp_MEMORY:
|
||||
if ((pcode->flags & fPCodeFlag2) && ((pcode->flags == 0) & 0x40)) {
|
||||
for (list = findobjectusedef(op->data.mem.obj)->defs; list; list = list->next) {
|
||||
if (
|
||||
may_alias(pcode, Defs[list->id].pcode) &&
|
||||
bitvectorgetbit(list->id, vec) &&
|
||||
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (pcode->flags & fPCodeFlag4) {
|
||||
for (list = findobjectusedef(op->data.mem.obj)->uses; list; list = list->next) {
|
||||
if (
|
||||
may_alias(pcode, Uses[list->id].pcode) &&
|
||||
bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PCOp_REGISTER:
|
||||
if (op->data.reg.effect & (EffectRead | EffectWrite)) {
|
||||
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
|
||||
if (op->data.reg.reg == _FP_)
|
||||
break;
|
||||
if (op->data.reg.reg == _CALLER_SP_)
|
||||
break;
|
||||
if (op->data.reg.reg == 2)
|
||||
break;
|
||||
}
|
||||
if (op->data.reg.reg < n_real_registers[op->arg]) {
|
||||
if (op->arg == RegClass_CRFIELD) {
|
||||
if (!flag2 || (op->data.reg.effect & EffectRead))
|
||||
return 0;
|
||||
} else if (op->arg == RegClass_SPR) {
|
||||
if (!flag1)
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (op->data.reg.effect & EffectRead) {
|
||||
if (flag1 && op->kind == PCOp_REGISTER && op->arg == RegClass_SPR)
|
||||
break;
|
||||
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
|
||||
if (op->data.reg.reg == _FP_)
|
||||
break;
|
||||
if (op->data.reg.reg == _CALLER_SP_)
|
||||
break;
|
||||
if (op->data.reg.reg == 2)
|
||||
break;
|
||||
}
|
||||
|
||||
for (list = reg_Defs[op->arg][op->data.reg.reg]; list; list = list->next) {
|
||||
if (
|
||||
bitvectorgetbit(list->id, vec) &&
|
||||
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int isuniquedefinition(PCode *pcode, Loop *loop) {
|
||||
RegUseOrDef *list;
|
||||
int defID;
|
||||
UseOrDef *def;
|
||||
|
||||
defID = pcode->defID;
|
||||
def = &Defs[defID];
|
||||
if (defID >= number_of_Defs)
|
||||
return 0;
|
||||
if (def->pcode != pcode)
|
||||
return 0;
|
||||
if ((defID + 1) < number_of_Defs && def[1].pcode == pcode)
|
||||
return 0;
|
||||
|
||||
if (def->v.kind == PCOp_REGISTER) {
|
||||
for (list = reg_Defs[(char) def->v.arg][def->v.u.reg]; list; list = list->next) {
|
||||
if (
|
||||
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
|
||||
list->id != defID
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
} else if (def->v.kind == PCOp_MEMORY) {
|
||||
for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
|
||||
if (
|
||||
may_alias(pcode, Defs[list->id].pcode) &&
|
||||
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
|
||||
list->id != defID
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
#line 292
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int uniquelyreachesuse(int defID, int useID) {
|
||||
UseOrDef *def;
|
||||
UseOrDef *use;
|
||||
RegUseOrDef *list;
|
||||
PCode *pcode;
|
||||
|
||||
def = &Defs[defID];
|
||||
use = &Uses[useID];
|
||||
if (def->v.kind == PCOp_REGISTER) {
|
||||
for (list = reg_Defs[(char) def->v.arg][def->v.u.reg]; list; list = list->next) {
|
||||
if (
|
||||
list->id != defID &&
|
||||
bitvectorgetbit(list->id, usedefinfo[use->pcode->block->blockIndex].defvec8)
|
||||
)
|
||||
break;
|
||||
}
|
||||
} else if (def->v.kind == PCOp_MEMORY) {
|
||||
for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
|
||||
if (
|
||||
may_alias(def->pcode, Defs[list->id].pcode) &&
|
||||
list->id != defID &&
|
||||
bitvectorgetbit(list->id, usedefinfo[use->pcode->block->blockIndex].defvec8)
|
||||
)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!list)
|
||||
return 1;
|
||||
|
||||
if (def->pcode->block == use->pcode->block) {
|
||||
for (pcode = use->pcode->prevPCode; pcode; pcode = pcode->prevPCode) {
|
||||
if (pcode == def->pcode)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniquelyreachesalluses(int defID, Loop *loop) {
|
||||
UseOrDef *def;
|
||||
RegUseOrDef *list;
|
||||
|
||||
def = &Defs[defID];
|
||||
|
||||
if (def->v.kind == PCOp_REGISTER) {
|
||||
for (list = reg_Uses[(char) def->v.arg][def->v.u.reg]; list; list = list->next) {
|
||||
if (
|
||||
bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].usevec1C) ||
|
||||
(bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks) && !uniquelyreachesuse(defID, list->id))
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
} else if (def->v.kind == PCOp_MEMORY) {
|
||||
for (list = findobjectusedef(def->v.u.object)->uses; list; list = list->next) {
|
||||
if (may_alias(def->pcode, Uses[list->id].pcode)) {
|
||||
if (
|
||||
bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].usevec1C) ||
|
||||
(bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks) && !uniquelyreachesuse(defID, list->id))
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#line 382
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int isliveonexit(TinyValue *v, Loop *loop) {
|
||||
RegUseOrDef *list;
|
||||
UInt32 *vec;
|
||||
|
||||
vec = usedefinfo[loop->preheader->blockIndex].usevec1C;
|
||||
|
||||
if (v->kind == PCOp_REGISTER) {
|
||||
for (list = reg_Uses[(char) v->arg][v->u.reg]; list; list = list->next) {
|
||||
if (
|
||||
bitvectorgetbit(list->id, vec) &&
|
||||
!bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
|
||||
)
|
||||
return 1;
|
||||
}
|
||||
} else if (v->kind == PCOp_MEMORY) {
|
||||
for (list = findobjectusedef(v->u.object)->uses; list; list = list->next) {
|
||||
if (
|
||||
bitvectorgetbit(list->id, vec) &&
|
||||
!bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
|
||||
)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dominatesallexits(PCode *pcode, Loop *loop) {
|
||||
return bitvectorgetbit(pcode->block->blockIndex, loop->vec28) != 0;
|
||||
}
|
||||
|
||||
static int maymove(PCode *pcode, Loop *loop) {
|
||||
short reg;
|
||||
|
||||
if (!isuniquedefinition(pcode, loop))
|
||||
return 0;
|
||||
if (!uniquelyreachesalluses(pcode->defID, loop))
|
||||
return 0;
|
||||
if (!dominatesallexits(pcode, loop) && isliveonexit(&Defs[pcode->defID].v, loop))
|
||||
return 0;
|
||||
|
||||
if (loop->bodySize > 25) {
|
||||
switch (pcode->op) {
|
||||
case PC_LI:
|
||||
if (
|
||||
pcode->nextPCode &&
|
||||
pcode->nextPCode->op == PC_LVX &&
|
||||
(pcode->nextPCode->flags & fIsConst)
|
||||
) {
|
||||
reg = pcode->args[0].data.reg.reg;
|
||||
if (pcode->nextPCode->args[1].data.reg.reg == reg ||
|
||||
pcode->nextPCode->args[2].data.reg.reg == reg)
|
||||
return 1;
|
||||
}
|
||||
case PC_VSPLTISB:
|
||||
case PC_VSPLTISH:
|
||||
case PC_VSPLTISW:
|
||||
return 0;
|
||||
default:
|
||||
if (!bitvectorgetbit(pcode->block->blockIndex, loop->vec2C))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void moveinvariantcomputation(PCode *pcode, Loop *loop) {
|
||||
ObjectUseDef *oud;
|
||||
BlockList *blocklist;
|
||||
RegUseOrDef *list;
|
||||
UseOrDef *def;
|
||||
int defID;
|
||||
|
||||
defID = pcode->defID;
|
||||
def = &Defs[defID];
|
||||
deletepcode(pcode);
|
||||
insertpcodebefore(loop->preheader->lastPCode, pcode);
|
||||
loop->bodySize--;
|
||||
movedloopinvariantcode = 1;
|
||||
|
||||
if (def->v.kind == PCOp_REGISTER) {
|
||||
for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
|
||||
for (list = reg_Defs[(char) def->v.arg][def->v.u.reg]; list; list = list->next)
|
||||
bitvectorclearbit(list->id, usedefinfo[blocklist->block->blockIndex].defvec8);
|
||||
bitvectorsetbit(defID, usedefinfo[blocklist->block->blockIndex].defvec8);
|
||||
}
|
||||
} else if (def->v.kind == PCOp_MEMORY) {
|
||||
oud = findobjectusedef(def->v.u.object);
|
||||
for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
|
||||
for (list = oud->defs; list; list = list->next) {
|
||||
if (uniquely_aliases(pcode, Defs[list->id].pcode))
|
||||
bitvectorclearbit(list->id, usedefinfo[blocklist->block->blockIndex].defvec8);
|
||||
}
|
||||
bitvectorsetbit(defID, usedefinfo[blocklist->block->blockIndex].defvec8);
|
||||
}
|
||||
} else {
|
||||
#line 545
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
static int srawi_addze_maymove(PCode *pcode, Loop *loop) {
|
||||
RegUseOrDef *list;
|
||||
UseOrDef *def;
|
||||
int defID;
|
||||
int nextDefID;
|
||||
|
||||
defID = pcode->defID;
|
||||
nextDefID = pcode->nextPCode->defID;
|
||||
|
||||
def = &Defs[defID];
|
||||
if (defID >= number_of_Defs)
|
||||
return 0;
|
||||
if (def->pcode != pcode)
|
||||
return 0;
|
||||
if ((defID + 1) < number_of_Defs && def[1].pcode == pcode)
|
||||
return 0;
|
||||
|
||||
if (def->v.kind == PCOp_REGISTER && def->v.arg == RegClass_GPR) {
|
||||
for (list = reg_Defs[RegClass_GPR][def->v.u.reg]; list; list = list->next) {
|
||||
if (
|
||||
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
|
||||
list->id != defID &&
|
||||
list->id != nextDefID
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
#line 582
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
if (!uniquelyreachesalluses(pcode->defID, loop))
|
||||
return 0;
|
||||
if (!dominatesallexits(pcode, loop) && isliveonexit(&Defs[pcode->defID].v, loop))
|
||||
return 0;
|
||||
if (!dominatesallexits(pcode->nextPCode, loop) && isliveonexit(&Defs[pcode->nextPCode->defID].v, loop))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int srawi_addze_isloopinvariant(PCode *pcode, Loop *loop, UInt32 *vec) {
|
||||
static PCode *oldNextInstr;
|
||||
PCode *nextInstr;
|
||||
|
||||
nextInstr = pcode->nextPCode;
|
||||
if (
|
||||
pcode->op == PC_ADDZE &&
|
||||
oldNextInstr == pcode
|
||||
) {
|
||||
oldNextInstr = NULL;
|
||||
return 1;
|
||||
} else if (
|
||||
pcode->op == PC_SRAWI &&
|
||||
nextInstr &&
|
||||
nextInstr->op == PC_ADDZE &&
|
||||
pcode->args[0].data.reg.reg == nextInstr->args[0].data.reg.reg &&
|
||||
nextInstr->args[0].data.reg.reg == nextInstr->args[1].data.reg.reg &&
|
||||
!(pcode->flags & (fPCodeFlag8 | fPCodeFlag20 | fIsVolatile | fSideEffects)) &&
|
||||
!(nextInstr->flags & (fPCodeFlag8 | fPCodeFlag20 | fIsVolatile | fSideEffects)) &&
|
||||
isloopinvariant(pcode, loop, vec, 1, 0) &&
|
||||
srawi_addze_maymove(pcode, loop)
|
||||
) {
|
||||
oldNextInstr = nextInstr;
|
||||
return 1;
|
||||
} else {
|
||||
oldNextInstr = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void removeblockfromloop(Loop *loop, PCodeBlock *block) {
|
||||
BlockList *list;
|
||||
BlockList **ptr;
|
||||
|
||||
bitvectorclearbit(block->blockIndex, loop->memberblocks);
|
||||
bitvectorclearbit(block->blockIndex, loop->vec24);
|
||||
bitvectorclearbit(block->blockIndex, loop->vec28);
|
||||
bitvectorclearbit(block->blockIndex, loop->vec2C);
|
||||
loop->bodySize -= block->pcodeCount;
|
||||
|
||||
ptr = &loop->blocks;
|
||||
while ((list = *ptr)) {
|
||||
if (list->block == block)
|
||||
*ptr = list->next;
|
||||
else
|
||||
ptr = &list->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void changesuccessor(PCodeBlock *block, PCodeBlock *from, PCodeBlock *to) {
|
||||
PCLink **ptr;
|
||||
PCLink *link;
|
||||
|
||||
for (link = block->successors; link; link = link->nextLink) {
|
||||
if (link->block == from)
|
||||
link->block = to;
|
||||
}
|
||||
|
||||
ptr = &from->predecessors;
|
||||
while ((link = *ptr)) {
|
||||
if (link->block == block) {
|
||||
*ptr = link->nextLink;
|
||||
link->nextLink = to->predecessors;
|
||||
to->predecessors = link;
|
||||
} else {
|
||||
ptr = &link->nextLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void movesuccessor(PCodeBlock *to, PCodeBlock *from, PCodeBlock *block) {
|
||||
PCLink **ptr;
|
||||
PCLink *link;
|
||||
|
||||
for (link = block->predecessors; link; link = link->nextLink) {
|
||||
if (link->block == from)
|
||||
link->block = to;
|
||||
}
|
||||
|
||||
ptr = &from->successors;
|
||||
while ((link = *ptr)) {
|
||||
if (link->block == block) {
|
||||
*ptr = link->nextLink;
|
||||
link->nextLink = to->successors;
|
||||
to->successors = link;
|
||||
} else {
|
||||
ptr = &link->nextLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void movecmptopreheader(Loop *loop, PCodeBlock *block, PCode *pc1, PCode *pc2, PCodeArg *op) {
|
||||
PCodeBlock *preheader;
|
||||
PCode *pc3;
|
||||
|
||||
preheader = loop->preheader;
|
||||
if (PCODE_FLAG_SET_F(pc1) & fPCodeFlag20000000) {
|
||||
moveinvariantcomputation(pc1, loop);
|
||||
} else {
|
||||
deletepcode(pc1);
|
||||
insertpcodebefore(loop->preheader->lastPCode, pc1);
|
||||
loop->bodySize--;
|
||||
movedloopinvariantcode = 1;
|
||||
}
|
||||
loop->preheader = NULL;
|
||||
|
||||
insertpreheaderblock(loop);
|
||||
|
||||
pc3 = preheader->lastPCode;
|
||||
#line 775
|
||||
CError_ASSERT(pc3->op == PC_B);
|
||||
deletepcode(pc3);
|
||||
deletepcode(pc2);
|
||||
appendpcode(preheader, pc2);
|
||||
movesuccessor(preheader, block, op->data.label.label->block);
|
||||
}
|
||||
|
||||
static PCodeBlock *appendheadercopy(Loop *loop, PCodeBlock *block1, PCodeBlock *block2, PCodeBlock *block3) {
|
||||
PCodeBlock *newblock1;
|
||||
PCodeBlock *newblock2;
|
||||
PCLink *link;
|
||||
PCode *scan;
|
||||
|
||||
newblock1 = lalloc(sizeof(PCodeBlock));
|
||||
newblock2 = lalloc(sizeof(PCodeBlock));
|
||||
|
||||
newblock1->labels = NULL;
|
||||
newblock1->predecessors = newblock1->successors = NULL;
|
||||
newblock1->firstPCode = newblock1->lastPCode = NULL;
|
||||
newblock1->pcodeCount = 0;
|
||||
newblock1->loopWeight = loop->body->loopWeight;
|
||||
newblock1->flags = 0;
|
||||
newblock1->blockIndex = pcblockcount++;
|
||||
|
||||
newblock2->labels = NULL;
|
||||
newblock2->predecessors = newblock2->successors = NULL;
|
||||
newblock2->firstPCode = newblock2->lastPCode = NULL;
|
||||
newblock2->pcodeCount = 0;
|
||||
newblock2->loopWeight = loop->body->loopWeight;
|
||||
newblock2->flags = 0;
|
||||
newblock2->blockIndex = pcblockcount++;
|
||||
|
||||
newblock1->nextBlock = newblock2;
|
||||
newblock2->prevBlock = newblock1;
|
||||
newblock1->prevBlock = block1;
|
||||
newblock2->nextBlock = block1->nextBlock;
|
||||
block1->nextBlock = newblock1;
|
||||
newblock2->nextBlock->prevBlock = newblock2;
|
||||
|
||||
pclabel(newblock1, makepclabel());
|
||||
pclabel(newblock2, makepclabel());
|
||||
|
||||
changesuccessor(block1, block1->successors->block, newblock1);
|
||||
|
||||
link = lalloc(sizeof(PCLink));
|
||||
link->block = newblock2;
|
||||
link->nextLink = newblock1->successors;
|
||||
newblock1->successors = link;
|
||||
|
||||
link = lalloc(sizeof(PCLink));
|
||||
link->block = newblock1;
|
||||
link->nextLink = newblock2->predecessors;
|
||||
newblock2->predecessors = link;
|
||||
|
||||
appendpcode(newblock2, makepcode(PC_B, block2->nextBlock->labels));
|
||||
pcbranch(newblock2, block2->nextBlock->labels);
|
||||
pccomputepredecessors1(newblock2);
|
||||
|
||||
for (scan = block2->firstPCode; scan; scan = scan->nextPCode)
|
||||
appendpcode(newblock1, copypcode(scan));
|
||||
|
||||
pcbranch(newblock1, block3->labels);
|
||||
|
||||
link = lalloc(sizeof(PCLink));
|
||||
link->block = newblock1;
|
||||
link->nextLink = block3->predecessors;
|
||||
block3->predecessors = link;
|
||||
|
||||
addblocktoloop(loop, newblock1);
|
||||
if (bitvectorgetbit(block2->blockIndex, loop->vec28))
|
||||
bitvectorsetbit(newblock1->blockIndex, loop->vec28);
|
||||
if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
|
||||
bitvectorsetbit(newblock1->blockIndex, loop->vec2C);
|
||||
|
||||
for (loop = loop->parent; loop; loop = loop->parent) {
|
||||
addblocktoloop(loop, newblock1);
|
||||
if (bitvectorgetbit(block2->blockIndex, loop->vec28))
|
||||
bitvectorsetbit(newblock1->blockIndex, loop->vec28);
|
||||
if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
|
||||
bitvectorsetbit(newblock1->blockIndex, loop->vec2C);
|
||||
|
||||
addblocktoloop(loop, newblock2);
|
||||
if (bitvectorgetbit(block2->blockIndex, loop->vec28))
|
||||
bitvectorsetbit(newblock2->blockIndex, loop->vec28);
|
||||
if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
|
||||
bitvectorsetbit(newblock2->blockIndex, loop->vec2C);
|
||||
}
|
||||
|
||||
return newblock1;
|
||||
}
|
||||
|
||||
static BlockList *findswitchpath(Loop *loop, PCodeBlock *block) {
|
||||
BlockList *head;
|
||||
BlockList *tail;
|
||||
BlockList *node;
|
||||
PCodeBlock *scan;
|
||||
|
||||
head = NULL;
|
||||
tail = NULL;
|
||||
|
||||
for (scan = block; scan && scan != loop->body; scan = scan->successors->block) {
|
||||
if (!bitvectorgetbit(scan->blockIndex, loop->memberblocks))
|
||||
return NULL;
|
||||
if (scan->successors && scan->successors->nextLink)
|
||||
return NULL;
|
||||
|
||||
node = oalloc(sizeof(BlockList));
|
||||
node->block = scan;
|
||||
node->next = NULL;
|
||||
if (head) {
|
||||
tail->next = node;
|
||||
tail = node;
|
||||
} else {
|
||||
head = node;
|
||||
tail = node;
|
||||
}
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static void simpleunswitchloop(Loop *loop) {
|
||||
PCode *pc29;
|
||||
PCodeArg *op27;
|
||||
UInt32 *myvec;
|
||||
PCodeBlock *block26;
|
||||
PCode *pc25; // r25
|
||||
BlockList *path2_24;
|
||||
PCodeArg *op23;
|
||||
PCode *pc23; // r23
|
||||
BlockList *scanlist; // r23
|
||||
BlockList *bestpath1; // r23
|
||||
BlockList *bestpath2; // r22
|
||||
PCodeBlock *headercopy; // r22
|
||||
Loop *newloop; // r21
|
||||
PCodeBlock *preheader21;
|
||||
BlockList *path20;
|
||||
PCode *scan20;
|
||||
PCode *lastpcode;
|
||||
int i;
|
||||
BlockList *pathiter1;
|
||||
BlockList *pathiter2;
|
||||
|
||||
if (!(lastpcode = loop->body->lastPCode))
|
||||
return;
|
||||
if (lastpcode->op != PC_BT && lastpcode->op != PC_BF)
|
||||
return;
|
||||
if (lastpcode->args[2].kind != PCOp_LABEL)
|
||||
return;
|
||||
if (!bitvectorgetbit(lastpcode->args[2].data.label.label->block->blockIndex, loop->memberblocks))
|
||||
return;
|
||||
if (loop->x57)
|
||||
return;
|
||||
if (loop->x4D)
|
||||
return;
|
||||
if (bitvectorgetbit(loop->body->nextBlock->blockIndex, loop->memberblocks))
|
||||
return;
|
||||
|
||||
for (block26 = pcbasicblocks; block26; block26 = block26->nextBlock) {
|
||||
if (bitvectorgetbit(block26->blockIndex, loop->memberblocks))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!block26)
|
||||
return;
|
||||
|
||||
myvec = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
||||
bitvectorcopy(myvec, usedefinfo[block26->blockIndex].defvec8, number_of_Defs);
|
||||
for (pc25 = loop->preheader->nextBlock->firstPCode; pc25; pc25 = pc25->nextPCode) {
|
||||
if (!(PCODE_FLAG_SET_F(pc25) & (fPCodeFlag8 | fPCodeFlag20 | fIsVolatile | fSideEffects | fPCodeFlag20000000))) {
|
||||
if (isloopinvariant(pc25, loop, myvec, 0, 1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pc25 || pc25->argCount < 1)
|
||||
return;
|
||||
|
||||
if (
|
||||
pc25->argCount < 1 ||
|
||||
pc25->args[0].kind != PCOp_REGISTER ||
|
||||
pc25->args[0].arg != RegClass_CRFIELD
|
||||
)
|
||||
return;
|
||||
|
||||
pc29 = pc25->block->lastPCode;
|
||||
if (
|
||||
!pc29 ||
|
||||
!(pc29->flags & fPCodeFlag1) ||
|
||||
pc29->args[0].kind != PCOp_REGISTER ||
|
||||
pc29->args[0].arg != RegClass_CRFIELD
|
||||
)
|
||||
return;
|
||||
|
||||
if (pc29->args[0].data.reg.reg != pc25->args[0].data.reg.reg)
|
||||
return;
|
||||
|
||||
op27 = NULL;
|
||||
for (i = 0; i < pc29->argCount; i++) {
|
||||
if (pc29->args[i].kind == PCOp_LABEL)
|
||||
op27 = &pc29->args[i];
|
||||
}
|
||||
|
||||
if (op27) {
|
||||
preheader21 = loop->preheader;
|
||||
|
||||
path20 = findswitchpath(loop, block26->nextBlock);
|
||||
if (!path20)
|
||||
return;
|
||||
|
||||
path2_24 = findswitchpath(loop, op27->data.label.label->block);
|
||||
if (!path2_24)
|
||||
return;
|
||||
|
||||
bestpath1 = NULL;
|
||||
bestpath2 = NULL;
|
||||
for (pathiter1 = path20; pathiter1; pathiter1 = pathiter1->next) {
|
||||
for (pathiter2 = path2_24; pathiter2; pathiter2 = pathiter2->next) {
|
||||
if (pathiter1->block == pathiter2->block) {
|
||||
bestpath1 = pathiter1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bestpath1)
|
||||
break;
|
||||
bestpath2 = pathiter1;
|
||||
}
|
||||
|
||||
#line 1192
|
||||
CError_ASSERT(bestpath2->block);
|
||||
|
||||
if (bestpath2->block->lastPCode && bestpath2->block->lastPCode->op == PC_B)
|
||||
deletepcode(bestpath2->block->lastPCode);
|
||||
|
||||
while (bestpath1) {
|
||||
for (scan20 = bestpath1->block->firstPCode; scan20; scan20 = scan20->nextPCode) {
|
||||
if (scan20->op != PC_B)
|
||||
appendpcode(bestpath2->block, copypcode(scan20));
|
||||
}
|
||||
bestpath1 = bestpath1->next;
|
||||
}
|
||||
|
||||
headercopy = appendheadercopy(loop, bestpath2->block, loop->body, block26);
|
||||
movecmptopreheader(loop, block26, pc25, pc29, op27);
|
||||
|
||||
if (block26->pcodeCount) {
|
||||
if (path2_24->block->firstPCode) {
|
||||
pc23 = path2_24->block->firstPCode;
|
||||
for (scan20 = block26->firstPCode; scan20; scan20 = scan20->nextPCode) {
|
||||
if (scan20->op != PC_B)
|
||||
insertpcodebefore(pc23, copypcode(scan20));
|
||||
}
|
||||
} else {
|
||||
for (scan20 = block26->firstPCode; scan20; scan20 = scan20->nextPCode) {
|
||||
if (scan20->op != PC_B)
|
||||
appendpcode(path2_24->block, copypcode(scan20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
op23 = NULL;
|
||||
for (i = 0; i < loop->body->lastPCode->argCount; i++) {
|
||||
if (loop->body->lastPCode->args[i].kind == PCOp_LABEL)
|
||||
op23 = &loop->body->lastPCode->args[i];
|
||||
}
|
||||
|
||||
#line 1250
|
||||
CError_ASSERT(op23 != NULL);
|
||||
|
||||
changesuccessor(loop->body, op23->data.label.label->block, path2_24->block);
|
||||
op23->data.label.label = path2_24->block->labels;
|
||||
|
||||
op23 = NULL;
|
||||
for (i = 0; i < preheader21->lastPCode->argCount; i++) {
|
||||
if (preheader21->lastPCode->args[i].kind == PCOp_LABEL)
|
||||
op23 = &preheader21->lastPCode->args[i];
|
||||
}
|
||||
|
||||
#line 1267
|
||||
CError_ASSERT(op23 != NULL);
|
||||
|
||||
changesuccessor(preheader21, op23->data.label.label->block, loop->body);
|
||||
op23->data.label.label = loop->body->labels;
|
||||
|
||||
op23 = NULL;
|
||||
for (i = 0; i < loop->preheader->lastPCode->argCount; i++) {
|
||||
if (loop->preheader->lastPCode->args[i].kind == PCOp_LABEL)
|
||||
op23 = &loop->preheader->lastPCode->args[i];
|
||||
}
|
||||
|
||||
#line 1284
|
||||
CError_ASSERT(op23 != NULL);
|
||||
|
||||
changesuccessor(loop->preheader, op23->data.label.label->block, headercopy);
|
||||
op23->data.label.label = headercopy->labels;
|
||||
|
||||
newloop = lalloc(sizeof(Loop));
|
||||
newloop->parent = loop->parent;
|
||||
newloop->children = NULL;
|
||||
newloop->nextSibling = loop->nextSibling;
|
||||
loop->nextSibling = newloop;
|
||||
newloop->body = loop->body;
|
||||
newloop->preheader = NULL;
|
||||
newloop->blocks = NULL;
|
||||
newloop->basicInductionVars = NULL;
|
||||
newloop->footer = NULL;
|
||||
newloop->pc18 = NULL;
|
||||
newloop->loopWeight = loop->loopWeight;
|
||||
|
||||
bitvectorinitialize(newloop->memberblocks = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
||||
bitvectorinitialize(newloop->vec24 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
||||
bitvectorinitialize(newloop->vec28 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
||||
bitvectorinitialize(newloop->vec2C = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
||||
|
||||
removeblockfromloop(loop, newloop->body);
|
||||
addblocktoloop(newloop, newloop->body);
|
||||
|
||||
bitvectorsetbit(newloop->body->blockIndex, newloop->vec24);
|
||||
bitvectorsetbit(newloop->body->blockIndex, newloop->vec2C);
|
||||
bitvectorsetbit(newloop->body->blockIndex, newloop->vec28);
|
||||
|
||||
for (scanlist = path2_24; scanlist; scanlist = scanlist->next) {
|
||||
removeblockfromloop(loop, scanlist->block);
|
||||
addblocktoloop(newloop, scanlist->block);
|
||||
bitvectorsetbit(scanlist->block->blockIndex, newloop->vec2C);
|
||||
}
|
||||
|
||||
newloop->preheader = NULL;
|
||||
insertpreheaderblock(newloop);
|
||||
analyzeloop(newloop);
|
||||
|
||||
loop->body = headercopy;
|
||||
|
||||
for (scanlist = loop->blocks; scanlist; scanlist = scanlist->next)
|
||||
bitvectorsetbit(scanlist->block->blockIndex, loop->vec2C);
|
||||
|
||||
bitvectorsetbit(headercopy->blockIndex, loop->vec24);
|
||||
analyzeloop(loop);
|
||||
|
||||
unswitchedinvariantcode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void simpleunswitchloops(Loop *loop) {
|
||||
while (loop) {
|
||||
if (loop->children)
|
||||
simpleunswitchloops(loop->children);
|
||||
else if (!loop->x4F)
|
||||
simpleunswitchloop(loop);
|
||||
loop = loop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
static void moveinvariantsfromloop(Loop *loop) {
|
||||
RegUseOrDef *list;
|
||||
BlockList *blocklist;
|
||||
PCode *instr;
|
||||
PCode *nextInstr;
|
||||
UInt32 *myvec;
|
||||
UseOrDef *def;
|
||||
int defID;
|
||||
int flag;
|
||||
PCodeBlock *block;
|
||||
|
||||
myvec = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
||||
do {
|
||||
flag = 0;
|
||||
for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
|
||||
block = blocklist->block;
|
||||
bitvectorcopy(myvec, usedefinfo[block->blockIndex].defvec8, number_of_Defs);
|
||||
for (instr = block->firstPCode; instr; instr = nextInstr) {
|
||||
nextInstr = instr->nextPCode;
|
||||
if (!(instr->flags & fPCodeFlag1) && instr->argCount) {
|
||||
if (
|
||||
!(instr->flags & (fPCodeFlag8 | fPCodeFlag20 | fIsVolatile | fSideEffects)) &&
|
||||
isloopinvariant(instr, loop, myvec, 0, 0) &&
|
||||
maymove(instr, loop)
|
||||
) {
|
||||
moveinvariantcomputation(instr, loop);
|
||||
flag = 1;
|
||||
} else if (srawi_addze_isloopinvariant(instr, loop, myvec)) {
|
||||
moveinvariantcomputation(instr, loop);
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
for (def = &Defs[defID = instr->defID]; defID < number_of_Defs && def->pcode == instr; def++, defID++) {
|
||||
if (def->v.kind == PCOp_REGISTER) {
|
||||
for (list = reg_Defs[(char) def->v.arg][def->v.u.reg]; list; list = list->next)
|
||||
bitvectorclearbit(list->id, myvec);
|
||||
} else if (def->v.kind == PCOp_MEMORY) {
|
||||
if ((char) def->v.arg == 0) {
|
||||
for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
|
||||
if (uniquely_aliases(instr, Defs[list->id].pcode))
|
||||
bitvectorclearbit(list->id, myvec);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#line 1434
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
bitvectorsetbit(defID, myvec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (flag);
|
||||
}
|
||||
|
||||
static void moveinvariantsfromloops(Loop *loop) {
|
||||
while (loop) {
|
||||
if (loop->children)
|
||||
moveinvariantsfromloops(loop->children);
|
||||
moveinvariantsfromloop(loop);
|
||||
loop = loop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
void moveloopinvariantcode(void) {
|
||||
unswitchedinvariantcode = 0;
|
||||
movedloopinvariantcode = 0;
|
||||
if (loopsinflowgraph) {
|
||||
moveinvariantsfromloops(loopsinflowgraph);
|
||||
simpleunswitchloops(loopsinflowgraph);
|
||||
}
|
||||
freeoheap();
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
#include "compiler/Coloring.h"
|
||||
#include "compiler/CFunc.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/InterferenceGraph.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PPCError.h"
|
||||
#include "compiler/Registers.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
#include "compiler/SpillCode.h"
|
||||
#include "compiler/StackFrame.h"
|
||||
#include "compiler/objects.h"
|
||||
|
||||
char coloring_class;
|
||||
static short used_regs_before_coloring;
|
||||
|
||||
static void markspecialregisters(RegClass rclass) {
|
||||
ObjectList *list;
|
||||
Object *object;
|
||||
VarInfo *vi;
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < n_real_registers[rclass]; i++)
|
||||
interferencegraph[i]->x14 = i;
|
||||
|
||||
for (list = arguments; list; list = list->next) {
|
||||
object = list->object;
|
||||
vi = Registers_GetVarInfo(object);
|
||||
if ((vi->flags & VarInfoFlag2) && vi->rclass == rclass) {
|
||||
interferencegraph[vi->reg]->spillTemporary = object;
|
||||
if (vi->flags & VarInfoFlag4) {
|
||||
interferencegraph[vi->reg]->flags |= fPairLow;
|
||||
interferencegraph[vi->regHi]->flags |= fPairHigh;
|
||||
interferencegraph[vi->regHi]->spillTemporary = object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (list = locals; list; list = list->next) {
|
||||
object = list->object;
|
||||
vi = Registers_GetVarInfo(object);
|
||||
if ((vi->flags & VarInfoFlag2) && vi->rclass == rclass) {
|
||||
interferencegraph[vi->reg]->spillTemporary = object;
|
||||
if (vi->flags & VarInfoFlag4) {
|
||||
interferencegraph[vi->reg]->flags |= fPairLow;
|
||||
interferencegraph[vi->regHi]->flags |= fPairHigh;
|
||||
interferencegraph[vi->regHi]->spillTemporary = object;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IGNode *simplifygraph(void) {
|
||||
int availableRegs;
|
||||
IGNode *spilledNodes;
|
||||
IGNode *pushedNodes;
|
||||
IGNode *best;
|
||||
IGNode *node;
|
||||
UInt32 i;
|
||||
UInt32 j;
|
||||
int flag;
|
||||
float bestScore;
|
||||
float score;
|
||||
|
||||
availableRegs = available_registers(coloring_class);
|
||||
pushedNodes = NULL;
|
||||
|
||||
do {
|
||||
spilledNodes = NULL;
|
||||
flag = 0;
|
||||
for (i = n_real_registers[coloring_class]; i < used_virtual_registers[coloring_class]; i++) {
|
||||
node = interferencegraph[i];
|
||||
if (!(node->flags & (fPushed | fCoalesced))) {
|
||||
if (node->x12 < availableRegs) {
|
||||
for (j = 0; j < node->arraySize; j++)
|
||||
interferencegraph[node->array[j]]->x12--;
|
||||
node->flags |= fPushed;
|
||||
node->next = pushedNodes;
|
||||
pushedNodes = node;
|
||||
flag = 1;
|
||||
} else {
|
||||
node->next = spilledNodes;
|
||||
spilledNodes = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (flag);
|
||||
|
||||
if (spilledNodes)
|
||||
estimatespillcosts();
|
||||
|
||||
while (spilledNodes) {
|
||||
best = spilledNodes;
|
||||
bestScore = (spilledNodes->x10 >= used_regs_before_coloring) ? FLT_MAX : ((float) spilledNodes->spillCost / (float) spilledNodes->x12);
|
||||
|
||||
for (node = spilledNodes->next; node; node = node->next) {
|
||||
score = (node->x10 >= used_regs_before_coloring) ? FLT_MAX : ((float) node->spillCost / (float) node->x12);
|
||||
if (score < bestScore) {
|
||||
best = node;
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < best->arraySize; i++)
|
||||
interferencegraph[best->array[i]]->x12--;
|
||||
|
||||
best->flags |= fPushed;
|
||||
best->next = pushedNodes;
|
||||
pushedNodes = best;
|
||||
|
||||
do {
|
||||
spilledNodes = NULL;
|
||||
flag = 0;
|
||||
for (i = n_real_registers[coloring_class]; i < used_virtual_registers[coloring_class]; i++) {
|
||||
node = interferencegraph[i];
|
||||
if (!(node->flags & (fPushed | fCoalesced))) {
|
||||
if (node->x12 < availableRegs) {
|
||||
for (j = 0; j < node->arraySize; j++)
|
||||
interferencegraph[node->array[j]]->x12--;
|
||||
node->flags |= fPushed;
|
||||
node->next = pushedNodes;
|
||||
pushedNodes = node;
|
||||
flag = 1;
|
||||
} else {
|
||||
node->next = spilledNodes;
|
||||
spilledNodes = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (flag);
|
||||
}
|
||||
|
||||
return pushedNodes;
|
||||
}
|
||||
|
||||
static int colorgraph(IGNode *node) {
|
||||
UInt32 volatileRegs;
|
||||
int result;
|
||||
IGNode *otherNode;
|
||||
int reg;
|
||||
UInt32 workingMask;
|
||||
int i;
|
||||
short *array;
|
||||
|
||||
result = 1;
|
||||
|
||||
reset_nonvolatile_registers(coloring_class);
|
||||
volatileRegs = volatile_registers(coloring_class);
|
||||
|
||||
while (node) {
|
||||
workingMask = volatileRegs;
|
||||
for (array = node->array, i = 0; i < node->arraySize; i++) {
|
||||
otherNode = interferencegraph[*(array++)];
|
||||
reg = otherNode->x14;
|
||||
if (reg != -1 && reg < n_real_registers[coloring_class])
|
||||
workingMask &= ~(1 << reg);
|
||||
}
|
||||
|
||||
if (workingMask) {
|
||||
for (i = 0; i < n_real_registers[coloring_class]; i++) {
|
||||
if (workingMask & (1 << i)) {
|
||||
node->x14 = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reg = obtain_nonvolatile_register(coloring_class);
|
||||
if (reg != -1) {
|
||||
volatileRegs |= 1 << (node->x14 = reg);
|
||||
} else {
|
||||
node->flags |= fSpilled;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void rewritepcode(void) {
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
PCodeArg *op;
|
||||
UInt32 i;
|
||||
IGNode *node;
|
||||
int reg;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (PC_OP_IS_ANY_REGISTER(op, coloring_class))
|
||||
op->data.reg.reg = interferencegraph[op->data.reg.reg]->x14;
|
||||
op++;
|
||||
}
|
||||
|
||||
if (
|
||||
(instr->flags & fPCodeFlag10) &&
|
||||
((char) instr->args[1].arg == coloring_class) &&
|
||||
instr->args[1].data.reg.reg == instr->args[0].data.reg.reg
|
||||
)
|
||||
deletepcode(instr);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = n_real_registers[coloring_class]; i < used_virtual_registers[coloring_class]; i++) {
|
||||
node = interferencegraph[i];
|
||||
if (node->spillTemporary && !(node->flags & fSpilled)) {
|
||||
if (node->flags & fCoalesced) {
|
||||
reg = node->x14;
|
||||
while (reg >= n_real_registers[coloring_class]) {
|
||||
reg = interferencegraph[reg]->x14;
|
||||
if (reg < 0)
|
||||
break;
|
||||
}
|
||||
node->x14 = reg;
|
||||
}
|
||||
|
||||
if (node->flags & fPairHigh) {
|
||||
reg = node->x14;
|
||||
Registers_GetVarInfo(node->spillTemporary)->regHi = reg;
|
||||
} else {
|
||||
reg = node->x14;
|
||||
Registers_GetVarInfo(node->spillTemporary)->reg = reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void colorinstructions(Object *proc) {
|
||||
RegClass rclass;
|
||||
int flag;
|
||||
|
||||
for (rclass = 0; rclass < RegClassMax; rclass++) {
|
||||
coloring_class = rclass;
|
||||
|
||||
if (rclass == RegClass_GPR)
|
||||
check_dynamic_aligned_frame();
|
||||
|
||||
if (used_virtual_registers[rclass] > n_real_registers[rclass]) {
|
||||
save_before_coloring_nonvolatile_registers(rclass);
|
||||
used_regs_before_coloring = used_virtual_registers[rclass];
|
||||
if (!available_registers(rclass)) {
|
||||
PPCError_Error(102, register_class_name[rclass]);
|
||||
return;
|
||||
}
|
||||
|
||||
flag = 1;
|
||||
while (flag && used_virtual_registers[rclass] > n_real_registers[rclass]) {
|
||||
buildinterferencegraph(proc);
|
||||
markspecialregisters(rclass);
|
||||
flag = colorgraph(simplifygraph()) ? 0 : 1;
|
||||
|
||||
if (flag)
|
||||
insertspillcode();
|
||||
else
|
||||
rewritepcode();
|
||||
freeoheap();
|
||||
}
|
||||
}
|
||||
|
||||
used_virtual_registers[rclass] = n_real_registers[rclass];
|
||||
}
|
||||
|
||||
coloring = 0;
|
||||
}
|
@ -0,0 +1,643 @@
|
||||
#include "compiler/ConstantPropagation.h"
|
||||
#include "compiler/Alias.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeInfo.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
#include "compiler/StackFrame.h"
|
||||
#include "compiler/UseDefChains.h"
|
||||
#include "compiler/objects.h"
|
||||
|
||||
int propagatedconstants;
|
||||
static int changed;
|
||||
static PCode **defininginstruction;
|
||||
static PCode **vrdefininginstruction;
|
||||
|
||||
static void computedefininginstructions(PCodeBlock *block) {
|
||||
RegUseOrDef *list;
|
||||
PCode *instr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < used_virtual_registers[RegClass_GPR]; i++) {
|
||||
instr = NULL;
|
||||
for (list = reg_Defs[RegClass_GPR][i]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, usedefinfo[block->blockIndex].defvec8)) {
|
||||
if (instr == NULL) {
|
||||
instr = Defs[list->id].pcode;
|
||||
} else {
|
||||
instr = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
defininginstruction[i] = instr;
|
||||
}
|
||||
|
||||
for (i = 0; i < used_virtual_registers[RegClass_VR]; i++) {
|
||||
instr = NULL;
|
||||
for (list = reg_Defs[RegClass_VR][i]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, usedefinfo[block->blockIndex].defvec8)) {
|
||||
if (instr == NULL) {
|
||||
instr = Defs[list->id].pcode;
|
||||
} else {
|
||||
instr = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vrdefininginstruction[i] = instr;
|
||||
}
|
||||
}
|
||||
|
||||
static PCode *isstackoperand(PCodeArg *op, SInt16 *resultValue, SInt16 addend) {
|
||||
PCode *instr;
|
||||
|
||||
if ((instr = defininginstruction[op->data.reg.reg]) && instr->op == PC_ADDI) {
|
||||
if (
|
||||
instr->args[2].kind == PCOp_MEMORY &&
|
||||
(instr->args[1].data.reg.reg == _FP_ || instr->args[1].data.reg.reg == _CALLER_SP_) &&
|
||||
instr->args[2].data.mem.obj->datatype == DLOCAL
|
||||
)
|
||||
{
|
||||
if (can_add_displ_to_local(instr->args[2].data.mem.obj, addend)) {
|
||||
*resultValue = instr->args[2].data.mem.offset;
|
||||
return instr;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int isconstantoperand(PCodeArg *op, SInt16 *resultValue) {
|
||||
PCode *instr;
|
||||
|
||||
if (
|
||||
(instr = defininginstruction[op->data.reg.reg]) &&
|
||||
instr->op == PC_LI &&
|
||||
instr->args[1].kind == PCOp_IMMEDIATE
|
||||
)
|
||||
{
|
||||
*resultValue = instr->args[1].data.imm.value;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int isuint16constantoperand(PCodeArg *op, SInt16 *resultValue) {
|
||||
PCode *instr;
|
||||
|
||||
if (
|
||||
(instr = defininginstruction[op->data.reg.reg]) &&
|
||||
instr->op == PC_LI &&
|
||||
instr->args[1].kind == PCOp_IMMEDIATE &&
|
||||
FITS_IN_USHORT(instr->args[1].data.imm.value)
|
||||
)
|
||||
{
|
||||
*resultValue = instr->args[1].data.imm.value;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int isvectorconstantoperand(PCodeArg *op, SInt16 *resultValue, Opcode *resultNewOp) {
|
||||
PCode *instr;
|
||||
|
||||
if (
|
||||
(instr = vrdefininginstruction[op->data.reg.reg]) &&
|
||||
(instr->op == PC_VSPLTISB || instr->op == PC_VSPLTISH || instr->op == PC_VSPLTISW) &&
|
||||
instr->args[1].kind == PCOp_IMMEDIATE
|
||||
)
|
||||
{
|
||||
*resultValue = instr->args[1].data.imm.value;
|
||||
*resultNewOp = instr->op;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int isunsignedloadoperand(PCodeArg *op) {
|
||||
PCode *instr;
|
||||
|
||||
if ((instr = defininginstruction[op->data.reg.reg])) {
|
||||
if (instr->flags & fPCodeFlag2) {
|
||||
if (instr->op >= PC_LHZ && instr->op <= PC_LHZUX)
|
||||
return 2;
|
||||
if (instr->op >= PC_LBZ && instr->op <= PC_LBZUX)
|
||||
return 1;
|
||||
} else if (instr->op == PC_RLWINM) {
|
||||
int var3 = instr->args[3].data.imm.value;
|
||||
int var4 = instr->args[4].data.imm.value;
|
||||
if (var4 == 31) {
|
||||
if (var3 == 24)
|
||||
return 1;
|
||||
if (var3 == 16)
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ismaskedoperand(PCodeArg *op, UInt32 *resultMask) {
|
||||
PCode *instr;
|
||||
UInt32 mask;
|
||||
|
||||
if ((instr = defininginstruction[op->data.reg.reg]) && instr->op == PC_RLWINM) {
|
||||
if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value) {
|
||||
mask =
|
||||
((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFU >> instr->args[3].data.imm.value)) &
|
||||
~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFU >> (instr->args[4].data.imm.value + 1)));
|
||||
} else {
|
||||
mask =
|
||||
((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFU >> instr->args[3].data.imm.value)) |
|
||||
~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFU >> (instr->args[4].data.imm.value + 1)));
|
||||
}
|
||||
*resultMask = mask;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int issignedloadoperand(PCodeArg *op) {
|
||||
PCode *instr;
|
||||
|
||||
if ((instr = defininginstruction[op->data.reg.reg])) {
|
||||
if (instr->flags & fPCodeFlag2) {
|
||||
if (instr->op >= PC_LHA && instr->op <= PC_LHAUX)
|
||||
return 2;
|
||||
} else if (instr->op == PC_EXTSB) {
|
||||
return 1;
|
||||
} else if (instr->op == PC_EXTSH) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void propagateconstantstoblock(PCodeBlock *block) {
|
||||
PCode *instr;
|
||||
SInt16 immAddend;
|
||||
SInt16 value1;
|
||||
SInt16 valueU16;
|
||||
Opcode newOpcode;
|
||||
SInt16 value2;
|
||||
UInt32 mask;
|
||||
UInt32 mask2;
|
||||
int loadSize;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
switch (instr->op) {
|
||||
case PC_MR:
|
||||
if (isconstantoperand(&instr->args[1], &value1)) {
|
||||
change_opcode(instr, PC_LI);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
break;
|
||||
case PC_VMR:
|
||||
if (isvectorconstantoperand(&instr->args[1], &value1, &newOpcode)) {
|
||||
change_opcode(instr, newOpcode);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
break;
|
||||
case PC_RLWINM:
|
||||
if (
|
||||
!(PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000) &&
|
||||
instr->args[2].data.imm.value == 0 &&
|
||||
instr->args[4].data.imm.value == 31
|
||||
)
|
||||
{
|
||||
if (isconstantoperand(&instr->args[1], &value1)) {
|
||||
if (
|
||||
(instr->args[3].data.imm.value == 16 && value1 == (value1 & 0x7FFF)) ||
|
||||
(instr->args[3].data.imm.value == 24 && value1 == (value1 & 0xFF))
|
||||
)
|
||||
{
|
||||
change_opcode(instr, PC_LI);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
loadSize = isunsignedloadoperand(&instr->args[1]);
|
||||
if (
|
||||
(loadSize == 2 && instr->args[3].data.imm.value <= 16) ||
|
||||
(loadSize == 1 && instr->args[3].data.imm.value <= 24)
|
||||
)
|
||||
{
|
||||
change_opcode(instr, PC_MR);
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ismaskedoperand(&instr->args[1], &mask)) {
|
||||
if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value) {
|
||||
mask2 =
|
||||
((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFU >> instr->args[3].data.imm.value)) &
|
||||
~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFU >> (instr->args[4].data.imm.value + 1)));
|
||||
} else {
|
||||
mask2 =
|
||||
((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFU >> instr->args[3].data.imm.value)) |
|
||||
~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFU >> (instr->args[4].data.imm.value + 1)));
|
||||
}
|
||||
if (mask == (mask & mask2)) {
|
||||
change_opcode(instr, PC_MR);
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PC_EXTSH:
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000)
|
||||
break;
|
||||
|
||||
if (isconstantoperand(&instr->args[1], &value1)) {
|
||||
change_opcode(instr, PC_LI);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
loadSize = issignedloadoperand(&instr->args[1]);
|
||||
if (loadSize == 1 || loadSize == 2) {
|
||||
change_opcode(instr, PC_MR);
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PC_EXTSB:
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000)
|
||||
break;
|
||||
|
||||
if (
|
||||
isconstantoperand(&instr->args[1], &value1) &&
|
||||
value1 >= -128 &&
|
||||
value1 <= 127
|
||||
)
|
||||
{
|
||||
change_opcode(instr, PC_LI);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
loadSize = issignedloadoperand(&instr->args[1]);
|
||||
if (loadSize == 1) {
|
||||
change_opcode(instr, PC_MR);
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PC_ADDI:
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000)
|
||||
break;
|
||||
|
||||
immAddend = instr->args[2].data.imm.value;
|
||||
if (
|
||||
isconstantoperand(&instr->args[1], &value1) &&
|
||||
FITS_IN_SHORT(immAddend + value1)
|
||||
)
|
||||
{
|
||||
change_opcode(instr, PC_LI);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = immAddend + value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PC_ADD:
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000)
|
||||
break;
|
||||
|
||||
if (isconstantoperand(&instr->args[2], &value1)) {
|
||||
if (value1 == 0) {
|
||||
change_opcode(instr, PC_MR);
|
||||
change_num_operands(instr, 2);
|
||||
} else {
|
||||
change_opcode(instr, PC_ADDI);
|
||||
instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
instr->args[2].data.imm.value = value1;
|
||||
instr->args[2].data.imm.obj = NULL;
|
||||
}
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
immAddend = value1;
|
||||
}
|
||||
|
||||
if (isconstantoperand(&instr->args[1], &value1)) {
|
||||
if (instr->op == PC_ADDI || instr->op == PC_MR) {
|
||||
if (FITS_IN_SHORT(immAddend + value1)) {
|
||||
change_opcode(instr, PC_LI);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = immAddend + value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
} else {
|
||||
instr->args[1] = instr->args[2];
|
||||
if (value1 == 0) {
|
||||
change_opcode(instr, PC_MR);
|
||||
change_num_operands(instr, 2);
|
||||
} else {
|
||||
change_opcode(instr, PC_ADDI);
|
||||
instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
instr->args[2].data.imm.value = value1;
|
||||
instr->args[2].data.imm.obj = NULL;
|
||||
}
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (instr->op == PC_MR) {
|
||||
PCode *stackInstr;
|
||||
if ((stackInstr = isstackoperand(&instr->args[1], &value1, 0))) {
|
||||
change_opcode(instr, PC_ADDI);
|
||||
instr->flags = stackInstr->flags;
|
||||
instr->args[1] = stackInstr->args[1];
|
||||
instr->args[2] = stackInstr->args[2];
|
||||
change_num_operands(instr, 3);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
} else if (instr->op == PC_ADDI && instr->args[2].kind == PCOp_IMMEDIATE) {
|
||||
PCode *stackInstr;
|
||||
SInt16 addend = instr->args[2].data.imm.value;
|
||||
if ((stackInstr = isstackoperand(&instr->args[1], &value1, addend))) {
|
||||
change_opcode(instr, PC_ADDI);
|
||||
instr->flags = stackInstr->flags;
|
||||
instr->args[1] = stackInstr->args[1];
|
||||
instr->args[2] = stackInstr->args[2];
|
||||
instr->args[2].data.imm.value = value1 + addend;
|
||||
if (instr->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag20000 | fPCodeFlag40000))
|
||||
instr->alias = make_alias(instr->args[2].data.imm.obj, instr->args[2].data.imm.value, 1);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PC_OR:
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000)
|
||||
break;
|
||||
|
||||
value1 = 0;
|
||||
immAddend = 0;
|
||||
if (isconstantoperand(&instr->args[2], &value1)) {
|
||||
if (isuint16constantoperand(&instr->args[2], &valueU16)) {
|
||||
if (valueU16 != 0) {
|
||||
change_opcode(instr, PC_ORI);
|
||||
instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
instr->args[2].data.imm.value = valueU16;
|
||||
instr->args[2].data.imm.obj = NULL;
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
} else {
|
||||
change_opcode(instr, PC_MR);
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
value1 = valueU16;
|
||||
} else if (value1 == 0) {
|
||||
change_opcode(instr, PC_MR);
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
immAddend = value1;
|
||||
}
|
||||
|
||||
if (isconstantoperand(&instr->args[1], &value1)) {
|
||||
if (instr->op == PC_ORI || instr->op == PC_MR) {
|
||||
change_opcode(instr, PC_LI);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = immAddend | value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
} else if (isuint16constantoperand(&instr->args[1], &valueU16)) {
|
||||
if (valueU16 != 0) {
|
||||
change_opcode(instr, PC_ORI);
|
||||
instr->args[1] = instr->args[2];
|
||||
instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
instr->args[2].data.imm.value = valueU16;
|
||||
instr->args[2].data.imm.obj = NULL;
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
} else {
|
||||
change_opcode(instr, PC_MR);
|
||||
instr->args[1] = instr->args[2];
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
} else if (value1 == 0) {
|
||||
change_opcode(instr, PC_MR);
|
||||
instr->args[1] = instr->args[2];
|
||||
change_num_operands(instr, 2);
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PC_SUBF:
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000)
|
||||
break;
|
||||
|
||||
if (isconstantoperand(&instr->args[1], &value1) && FITS_IN_SHORT(-value1)) {
|
||||
if (isconstantoperand(&instr->args[2], &value2) && FITS_IN_SHORT(value2 - value1)) {
|
||||
change_opcode(instr, PC_LI);
|
||||
instr->args[1].kind = PCOp_IMMEDIATE;
|
||||
instr->args[1].data.imm.value = value2 - value1;
|
||||
instr->args[1].data.imm.obj = NULL;
|
||||
change_num_operands(instr, 2);
|
||||
} else if (value1 == 0) {
|
||||
change_opcode(instr, PC_MR);
|
||||
instr->args[1] = instr->args[2];
|
||||
change_num_operands(instr, 2);
|
||||
} else {
|
||||
change_opcode(instr, PC_ADDI);
|
||||
instr->args[1] = instr->args[2];
|
||||
instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
instr->args[2].data.imm.value = -value1;
|
||||
instr->args[2].data.imm.obj = NULL;
|
||||
}
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
value2 = value1;
|
||||
} else if (isconstantoperand(&instr->args[2], &value1) && FITS_IN_SHORT(-value1)) {
|
||||
if (value1 == 0) {
|
||||
change_opcode(instr, PC_NEG);
|
||||
change_num_operands(instr, 2);
|
||||
} else {
|
||||
instr->flags = opcodeinfo[PC_SUBFIC].flags | (instr->flags & ~opcodeinfo[PC_SUBF].flags);
|
||||
change_opcode(instr, PC_SUBFIC);
|
||||
instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
instr->args[2].data.imm.value = value1;
|
||||
instr->args[2].data.imm.obj = NULL;
|
||||
instr->args[3].kind = PCOp_REGISTER;
|
||||
instr->args[3].arg = RegClass_SPR;
|
||||
instr->args[3].data.reg.reg = 0;
|
||||
instr->args[3].data.reg.effect = EffectWrite;
|
||||
change_num_operands(instr, 4);
|
||||
}
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PC_LBZ:
|
||||
case PC_LHZ:
|
||||
case PC_LHA:
|
||||
case PC_LWZ:
|
||||
case PC_STB:
|
||||
case PC_STH:
|
||||
case PC_STW:
|
||||
case PC_LFS:
|
||||
case PC_LFD:
|
||||
case PC_STFS:
|
||||
case PC_STFD:
|
||||
if (instr->args[2].kind == PCOp_IMMEDIATE) {
|
||||
PCode *stackInstr;
|
||||
SInt16 addend = instr->args[2].data.imm.value;
|
||||
|
||||
if ((stackInstr = isstackoperand(&instr->args[1], &value1, addend))) {
|
||||
instr->args[1] = stackInstr->args[1];
|
||||
instr->args[2] = stackInstr->args[2];
|
||||
instr->args[2].data.imm.value = value1 + addend;
|
||||
if (instr->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag20000 | fPCodeFlag40000))
|
||||
instr->alias = make_alias(instr->args[2].data.imm.obj, instr->args[2].data.imm.value,
|
||||
nbytes_loaded_or_stored_by(instr));
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PC_LBZX:
|
||||
case PC_LHZX:
|
||||
case PC_LHAX:
|
||||
case PC_LWZX:
|
||||
case PC_STBX:
|
||||
case PC_STHX:
|
||||
case PC_STWX:
|
||||
case PC_LFSX:
|
||||
case PC_LFDX:
|
||||
case PC_STFSX:
|
||||
case PC_STFDX:
|
||||
if (isconstantoperand(&instr->args[2], &value1)) {
|
||||
instr->op -= 2;
|
||||
instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
instr->args[2].data.imm.value = value1;
|
||||
instr->args[2].data.imm.obj = NULL;
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
} else if (isconstantoperand(&instr->args[1], &value1)) {
|
||||
instr->op -= 2;
|
||||
instr->args[1] = instr->args[2];
|
||||
instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
instr->args[2].data.imm.value = value1;
|
||||
instr->args[2].data.imm.obj = NULL;
|
||||
propagatedconstants = 1;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
(op->data.reg.effect & EffectWrite)
|
||||
)
|
||||
{
|
||||
defininginstruction[op->data.reg.reg] = instr;
|
||||
}
|
||||
else if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_VR &&
|
||||
(op->data.reg.effect & EffectWrite)
|
||||
)
|
||||
{
|
||||
vrdefininginstruction[op->data.reg.reg] = instr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void propagateconstants(void) {
|
||||
PCodeBlock *block;
|
||||
int i;
|
||||
|
||||
propagatedconstants = 0;
|
||||
computeusedefchains(0);
|
||||
defininginstruction = galloc(sizeof(PCode *) * used_virtual_registers[RegClass_GPR]);
|
||||
vrdefininginstruction = galloc(sizeof(PCode *) * used_virtual_registers[RegClass_VR]);
|
||||
|
||||
do {
|
||||
changed = 0;
|
||||
for (i = 0; i < pcblockcount; i++) {
|
||||
if ((block = depthfirstordering[i])) {
|
||||
computedefininginstructions(block);
|
||||
propagateconstantstoblock(block);
|
||||
}
|
||||
}
|
||||
} while (changed);
|
||||
|
||||
freeoheap();
|
||||
}
|
@ -0,0 +1,474 @@
|
||||
#include "compiler/CopyPropagation.h"
|
||||
#include "compiler/CMangler.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/CodeGen.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/UseDefChains.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
|
||||
// TODO move me
|
||||
extern void pclistblocks(char *, char *);
|
||||
|
||||
int propagatedcopies;
|
||||
int propagated_instructions;
|
||||
int recursive_propagation;
|
||||
int number_of_candidates;
|
||||
Candidate *Candidates;
|
||||
PropInfo *propinfo;
|
||||
int *ncandidatesinblock;
|
||||
int *firstcandidateinblock;
|
||||
static int moreaggressiveoptimization;
|
||||
static PropagateAndFinishFunc propagateandfinish;
|
||||
static PropagatesToUseFunc propagatestouse;
|
||||
static IsCandidateFunc is_candidate;
|
||||
|
||||
static void precomputecanidatecounts(void) {
|
||||
PCodeBlock *block;
|
||||
PCode *pcode;
|
||||
int count;
|
||||
|
||||
ncandidatesinblock = oalloc(sizeof(int) * pcblockcount);
|
||||
firstcandidateinblock = oalloc(sizeof(int) * pcblockcount);
|
||||
number_of_candidates = 0;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
firstcandidateinblock[block->blockIndex] = number_of_candidates;
|
||||
|
||||
count = 0;
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (is_candidate(pcode)) {
|
||||
number_of_candidates++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
ncandidatesinblock[block->blockIndex] = count;
|
||||
}
|
||||
}
|
||||
|
||||
static void computecandidatelist(void) {
|
||||
RegUseOrDef *list; // r23
|
||||
PCodeBlock *block; // r22
|
||||
PCode *pcode; // r21
|
||||
Candidate *candidate; // r20
|
||||
UInt32 *vec; // r19
|
||||
int reg;
|
||||
RegUseOrDef *newlist;
|
||||
UseOrDef *def;
|
||||
UseOrDef *use;
|
||||
int defID;
|
||||
int useID;
|
||||
|
||||
Candidates = oalloc(sizeof(Candidate) * number_of_candidates);
|
||||
vec = oalloc(4 * ((number_of_Uses + 31) >> 5));
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
if (ncandidatesinblock[block->blockIndex]) {
|
||||
bitvectorcopy(vec, usedefinfo[block->blockIndex].usevec1C, number_of_Uses);
|
||||
candidate = &Candidates[firstcandidateinblock[block->blockIndex] + ncandidatesinblock[block->blockIndex] - 1];
|
||||
for (pcode = block->lastPCode; pcode; pcode = pcode->prevPCode) {
|
||||
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
||||
if (is_candidate(pcode)) {
|
||||
reg = pcode->args[0].data.reg.reg;
|
||||
candidate->pcode = pcode;
|
||||
candidate->list = NULL;
|
||||
|
||||
for (list = reg_Uses[pcode->args[0].arg][reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, vec)) {
|
||||
newlist = oalloc(sizeof(RegUseOrDef));
|
||||
newlist->id = list->id;
|
||||
newlist->next = candidate->list;
|
||||
candidate->list = newlist;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pcode->flags & fPCodeFlag2 | fPCodeFlag4) && (pcode->flags & fPCodeFlag2000000)) {
|
||||
for (list = reg_Uses[pcode->args[1].arg][pcode->args[1].data.reg.reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, vec)) {
|
||||
newlist = oalloc(sizeof(RegUseOrDef));
|
||||
newlist->id = list->id;
|
||||
newlist->next = candidate->list;
|
||||
candidate->list = newlist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
candidate--;
|
||||
}
|
||||
|
||||
for (def = &Defs[defID = pcode->defID]; defID < number_of_Defs && def->pcode == pcode; def++, defID++) {
|
||||
if (def->kind == PCOp_REGISTER) {
|
||||
for (list = reg_Uses[def->arg][def->u.reg]; list; list = list->next)
|
||||
bitvectorclearbit(list->id, vec);
|
||||
}
|
||||
}
|
||||
for (use = &Uses[useID = pcode->useID]; useID < number_of_Uses && use->pcode == pcode; use++, useID++) {
|
||||
if (use->kind == PCOp_REGISTER)
|
||||
bitvectorsetbit(useID, vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void allocatepropinfo(void) {
|
||||
PropInfo *info;
|
||||
int i;
|
||||
|
||||
propinfo = oalloc(sizeof(PropInfo) * pcblockcount);
|
||||
for (i = 0, info = propinfo; i < pcblockcount; i++, info++) {
|
||||
info->vec0 = oalloc(4 * ((number_of_candidates + 31) >> 5));
|
||||
info->vec4 = oalloc(4 * ((number_of_candidates + 31) >> 5));
|
||||
info->vec8 = oalloc(4 * ((number_of_candidates + 31) >> 5));
|
||||
info->vecC = oalloc(4 * ((number_of_candidates + 31) >> 5));
|
||||
}
|
||||
}
|
||||
|
||||
static void computelocalpropinfo(Boolean flag) {
|
||||
PropInfo *info;
|
||||
PCode *pcode;
|
||||
PCodeBlock *block;
|
||||
UInt32 *vec0;
|
||||
UInt32 *vec4;
|
||||
int index;
|
||||
PCodeArg *op;
|
||||
PCodeArg *candOp;
|
||||
int i;
|
||||
int j;
|
||||
int cndi;
|
||||
Candidate *candidate;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
info = &propinfo[block->blockIndex];
|
||||
vec0 = info->vec0;
|
||||
vec4 = info->vec4;
|
||||
bitvectorinitialize(vec0, number_of_candidates, 0);
|
||||
bitvectorinitialize(vec4, number_of_candidates, 0);
|
||||
index = firstcandidateinblock[block->blockIndex];
|
||||
|
||||
if (flag) {
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
||||
i = pcode->argCount;
|
||||
op = pcode->args;
|
||||
while (i--) {
|
||||
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR && (op->data.reg.effect & EffectWrite)) {
|
||||
for (cndi = 0, candidate = Candidates; cndi < number_of_candidates; cndi++, candidate++) {
|
||||
for (j = 0; j < candidate->pcode->argCount; j++) {
|
||||
candOp = candidate->pcode->args + j;
|
||||
if (candOp->kind == PCOp_REGISTER && candOp->arg == RegClass_GPR && candOp->data.reg.reg == op->data.reg.reg) {
|
||||
if (candidate->pcode->block == block)
|
||||
bitvectorclearbit(cndi, vec0);
|
||||
else
|
||||
bitvectorsetbit(cndi, vec4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
if (is_candidate(pcode)) {
|
||||
bitvectorsetbit(index, vec0);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
||||
i = pcode->argCount;
|
||||
op = pcode->args;
|
||||
while (i--) {
|
||||
if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite)) {
|
||||
for (cndi = 0, candidate = Candidates; cndi < number_of_candidates; cndi++, candidate++) {
|
||||
for (j = 0; j < candidate->pcode->argCount; j++) {
|
||||
candOp = candidate->pcode->args + j;
|
||||
if (candOp->kind == PCOp_REGISTER && candOp->arg == op->arg) {
|
||||
if (candOp->data.reg.reg == op->data.reg.reg) {
|
||||
if (candidate->pcode->block == block)
|
||||
bitvectorclearbit(cndi, vec0);
|
||||
else
|
||||
bitvectorsetbit(cndi, vec4);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (j == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
if (is_candidate(pcode)) {
|
||||
bitvectorsetbit(index, vec0);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void computeglobalpropinfo(void) {
|
||||
PropInfo *info;
|
||||
PCodeBlock *block;
|
||||
int bitvecsize;
|
||||
UInt32 *vec0;
|
||||
UInt32 *vec4;
|
||||
UInt32 *vec8;
|
||||
UInt32 *vecC;
|
||||
int i;
|
||||
int j;
|
||||
int flag;
|
||||
PCLink *preds;
|
||||
UInt32 val;
|
||||
|
||||
bitvecsize = (number_of_candidates + 31) >> 5;
|
||||
flag = 1;
|
||||
info = &propinfo[pcbasicblocks->blockIndex];
|
||||
bitvectorinitialize(info->vec8, number_of_candidates, 0);
|
||||
bitvectorcopy(info->vecC, info->vec0, number_of_candidates);
|
||||
|
||||
for (block = pcbasicblocks->nextBlock; block; block = block->nextBlock) {
|
||||
info = &propinfo[block->blockIndex];
|
||||
vecC = info->vecC;
|
||||
vec4 = info->vec4;
|
||||
for (i = 0; i < bitvecsize; vecC++, vec4++, i++)
|
||||
*vecC = ~*vec4;
|
||||
}
|
||||
|
||||
while (flag) {
|
||||
flag = 0;
|
||||
for (i = 0; i < pcblockcount; i++) {
|
||||
if (depthfirstordering[i]) {
|
||||
info = &propinfo[depthfirstordering[i]->blockIndex];
|
||||
if ((preds = depthfirstordering[i]->predecessors)) {
|
||||
vec8 = info->vec8;
|
||||
bitvectorcopy(vec8, propinfo[preds->block->blockIndex].vecC, number_of_candidates);
|
||||
for (preds = preds->nextLink; preds; preds = preds->nextLink)
|
||||
bitvectorintersect(vec8, propinfo[preds->block->blockIndex].vecC, number_of_candidates);
|
||||
}
|
||||
|
||||
vecC = info->vecC;
|
||||
vec8 = info->vec8;
|
||||
vec0 = info->vec0;
|
||||
vec4 = info->vec4;
|
||||
for (j = 0; j < bitvecsize; j++) {
|
||||
val = *vec0 | (*vec8 & ~*vec4);
|
||||
if (val != *vecC) {
|
||||
*vecC = val;
|
||||
flag = 1;
|
||||
}
|
||||
vec8++;
|
||||
vecC++;
|
||||
vec4++;
|
||||
vec0++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int precedes(PCode *a, PCode *b) {
|
||||
PCode *scan;
|
||||
|
||||
for (scan = a->nextPCode; scan; scan = scan->nextPCode) {
|
||||
if (scan == b)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int canidatepropagatestoalluses(int id) {
|
||||
RegUseOrDef *list;
|
||||
|
||||
if (PCODE_FLAG_SET_F(Candidates[id].pcode) & (fPCodeFlag20000000 | fSideEffects))
|
||||
return 0;
|
||||
|
||||
for (list = Candidates[id].list; list; list = list->next) {
|
||||
if (!propagatestouse(id, list->id))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void propagatecandidates(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < number_of_candidates; i++) {
|
||||
if (canidatepropagatestoalluses(i))
|
||||
propagateandfinish(i);
|
||||
}
|
||||
}
|
||||
|
||||
void propagateinstructions(Object *proc, Propagation *config, int passCount, Boolean localflag) {
|
||||
char buf[64];
|
||||
|
||||
is_candidate = config->is_candidate;
|
||||
propagatestouse = config->propagatestouse;
|
||||
propagateandfinish = config->propagateandfinish;
|
||||
propagated_instructions = 0;
|
||||
|
||||
while (1) {
|
||||
recursive_propagation = 0;
|
||||
precomputecanidatecounts();
|
||||
if (number_of_candidates <= 0) {
|
||||
freeoheap();
|
||||
if (config->computesUseDefChains)
|
||||
computeusedefchains(0);
|
||||
return;
|
||||
}
|
||||
|
||||
computeusedefchains(0);
|
||||
computecandidatelist();
|
||||
allocatepropinfo();
|
||||
computelocalpropinfo(localflag);
|
||||
computedepthfirstordering();
|
||||
computeglobalpropinfo();
|
||||
propagatecandidates();
|
||||
passCount--;
|
||||
|
||||
if (propagated_instructions && copts.debuglisting) {
|
||||
sprintf(buf, "AFTER %s PROPAGATION", config->name);
|
||||
pclistblocks(CMangler_GetLinkName(proc)->name, buf);
|
||||
}
|
||||
|
||||
if (!passCount || !recursive_propagation) {
|
||||
if (!config->computesUseDefChains)
|
||||
freeoheap();
|
||||
return;
|
||||
}
|
||||
|
||||
freeoheap();
|
||||
}
|
||||
}
|
||||
|
||||
static int is_copy(PCode *pcode) {
|
||||
return (pcode->flags & fPCodeFlag10) && (pcode->args[0].data.reg.reg >= n_real_registers[pcode->args[0].arg]);
|
||||
}
|
||||
|
||||
static int copypropagatestouse(int candidateID, int useID) {
|
||||
UseOrDef *use;
|
||||
short reg1;
|
||||
short reg2;
|
||||
char rclass;
|
||||
PCode *pcode;
|
||||
int i;
|
||||
PCode *scan;
|
||||
PCodeArg *op;
|
||||
|
||||
pcode = Candidates[candidateID].pcode;
|
||||
use = Uses + useID;
|
||||
rclass = pcode->args[0].arg;
|
||||
reg1 = pcode->args[0].data.reg.reg;
|
||||
reg2 = pcode->args[1].data.reg.reg;
|
||||
|
||||
if (use->pcode->flags & fPCodeFlag10)
|
||||
return 0;
|
||||
|
||||
if (rclass == RegClass_GPR && use->pcode->op == PC_RLWIMI && use->pcode->args[0].data.reg.reg == reg1)
|
||||
return 0;
|
||||
|
||||
if (pcode->block == use->pcode->block && precedes(pcode, use->pcode)) {
|
||||
for (scan = pcode->nextPCode; scan && scan != use->pcode; scan = scan->nextPCode) {
|
||||
op = scan->args;
|
||||
i = scan->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == rclass &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
op->data.reg.reg == reg2
|
||||
)
|
||||
return 0;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!bitvectorgetbit(candidateID, propinfo[use->pcode->block->blockIndex].vec8))
|
||||
return 0;
|
||||
|
||||
for (scan = use->pcode->block->firstPCode; scan; scan = scan->nextPCode) {
|
||||
op = scan->args;
|
||||
i = scan->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == rclass &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
op->data.reg.reg == reg2
|
||||
)
|
||||
return 0;
|
||||
op++;
|
||||
}
|
||||
if (scan == use->pcode)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void propagateandremovecopy(int id) {
|
||||
Candidate *candidate;
|
||||
unsigned char rclass;
|
||||
short reg1;
|
||||
short reg2;
|
||||
RegUseOrDef *list;
|
||||
int i;
|
||||
PCodeArg *op;
|
||||
|
||||
candidate = &Candidates[id];
|
||||
rclass = candidate->pcode->args[0].arg;
|
||||
reg1 = candidate->pcode->args[0].data.reg.reg;
|
||||
reg2 = candidate->pcode->args[1].data.reg.reg;
|
||||
|
||||
if (rclass == RegClass_GPR && reg1 >= 32 && reg1 <= last_exception_register[RegClass_GPR])
|
||||
return;
|
||||
|
||||
if (!moreaggressiveoptimization && reg2 < n_real_registers[(char) rclass])
|
||||
return;
|
||||
|
||||
for (list = candidate->list; list; list = list->next) {
|
||||
op = Uses[list->id].pcode->args;
|
||||
i = Uses[list->id].pcode->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == (char) rclass &&
|
||||
op->data.reg.reg == reg1 &&
|
||||
(op->data.reg.effect & EffectRead)
|
||||
)
|
||||
op->data.reg.reg = reg2;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
|
||||
deletepcode(candidate->pcode);
|
||||
propagated_instructions = 1;
|
||||
}
|
||||
|
||||
static Propagation copy_prop = {
|
||||
&is_copy,
|
||||
©propagatestouse,
|
||||
&propagateandremovecopy,
|
||||
"COPY",
|
||||
"COPIES",
|
||||
"c%ld",
|
||||
0
|
||||
};
|
||||
|
||||
void propagatecopyinstructions(Object *proc, int flag) {
|
||||
moreaggressiveoptimization = flag;
|
||||
propagateinstructions(proc, ©_prop, 1, 0);
|
||||
propagatedcopies = propagated_instructions;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,11 +22,11 @@
|
||||
#include "compiler/PCodeUtilities.h"
|
||||
#include "compiler/StackFrame.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/Alias.h"
|
||||
|
||||
// TODO: move me
|
||||
extern int countexceptionactionregisters(ExceptionAction *);
|
||||
extern void noteexceptionactionregisters(ExceptionAction *, PCodeArg *);
|
||||
extern void *make_alias(Object *obj, SInt32 offset, SInt32 size);
|
||||
|
||||
char asm_alloc_flags[10];
|
||||
unsigned char sm_section;
|
||||
@ -2090,7 +2090,7 @@ static PCode *InlineAsm_TranslateIRtoPCodePPC(InlineAsm *ia, int argcount, UInt8
|
||||
dest->data.mem.obj = src->u.obj.obj;
|
||||
dest->data.mem.offset = src->u.obj.offset;
|
||||
if (pc->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag20000 | fPCodeFlag40000)) {
|
||||
pc->_18 = make_alias(dest->data.mem.obj, dest->data.mem.offset, nbytes_loaded_or_stored_by(pc));
|
||||
pc->alias = make_alias(dest->data.mem.obj, dest->data.mem.offset, nbytes_loaded_or_stored_by(pc));
|
||||
if (is_volatile_object(dest->data.mem.obj))
|
||||
pc->flags |= fIsVolatile;
|
||||
if (OBJ_GET_TARGET_CONST(dest->data.mem.obj))
|
||||
|
@ -0,0 +1,404 @@
|
||||
#include "compiler/InterferenceGraph.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/Coloring.h"
|
||||
#include "compiler/LiveInfo.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeListing.h"
|
||||
#include "compiler/PCodeUtilities.h"
|
||||
#include "compiler/Registers.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
|
||||
IGNode **interferencegraph;
|
||||
static UInt32 *interferencematrix;
|
||||
Boolean coalesced_nregisters;
|
||||
static SInt16 *coalesced;
|
||||
|
||||
static void makeinterfere(UInt32 a, UInt32 b) {
|
||||
if (a < b)
|
||||
bitvectorsetbit(((b * b) / 2) + a, interferencematrix);
|
||||
else if (a > b)
|
||||
bitvectorsetbit(((a * a) / 2) + b, interferencematrix);
|
||||
}
|
||||
|
||||
int interferes(UInt32 a, UInt32 b) {
|
||||
if (a < b)
|
||||
return bitvectorgetbit(((b * b) / 2) + a, interferencematrix) > 0;
|
||||
else if (a > b)
|
||||
return bitvectorgetbit(((a * a) / 2) + b, interferencematrix) > 0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void buildinterferencematrix(void) {
|
||||
UInt32 regs; // r31
|
||||
PCodeBlock *block; // r30
|
||||
PCode *instr; // r29
|
||||
UInt32 *vec; // r28
|
||||
PCodeArg *op;
|
||||
long reg;
|
||||
UInt32 i;
|
||||
UInt32 j;
|
||||
|
||||
regs = used_virtual_registers[coloring_class];
|
||||
interferencematrix = oalloc(4 * ((((regs * regs) / 2) + 31) >> 5));
|
||||
bitvectorinitialize(interferencematrix, (regs * regs) / 2, 0);
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
for (j = 0; j < 32; j++)
|
||||
if (i != j)
|
||||
makeinterfere(i, j);
|
||||
|
||||
vec = oalloc(4 * ((regs + 31) >> 5));
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
bitvectorcopy(vec, liveinfo[block->blockIndex].vecC, regs);
|
||||
for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == coloring_class &&
|
||||
(op->data.reg.effect & EffectWrite)
|
||||
)
|
||||
{
|
||||
reg = op->data.reg.reg;
|
||||
bitvectorclearbit(reg, vec);
|
||||
for (j = 0; j < regs; j++) {
|
||||
if (bitvectorgetbit(j, vec)) {
|
||||
if (
|
||||
(instr->flags & fPCodeFlag10) &&
|
||||
instr->args[0].kind == PCOp_REGISTER &&
|
||||
(char) instr->args[0].arg == coloring_class &&
|
||||
instr->args[1].data.reg.reg == j
|
||||
)
|
||||
continue;
|
||||
makeinterfere(reg, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == coloring_class &&
|
||||
(op->data.reg.effect & EffectRead)
|
||||
)
|
||||
{
|
||||
reg = op->data.reg.reg;
|
||||
if (bitvectorgetbit(reg, vec) == 0)
|
||||
op->data.reg.effect |= Effect4;
|
||||
bitvectorsetbit(reg, vec);
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
if (coloring_class == RegClass_GPR) {
|
||||
if (PCODE_FLAG_SET_F(instr) & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag40000)) {
|
||||
if (instr->args[1].data.reg.reg >= n_real_registers[coloring_class])
|
||||
makeinterfere(0, instr->args[1].data.reg.reg);
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag2000000)
|
||||
makeinterfere(instr->args[0].data.reg.reg, instr->args[1].data.reg.reg);
|
||||
} else {
|
||||
switch (instr->op) {
|
||||
case PC_DCBF:
|
||||
case PC_DCBST:
|
||||
case PC_DCBT:
|
||||
case PC_DCBTST:
|
||||
case PC_DCBZ:
|
||||
case PC_DCBI:
|
||||
case PC_ICBI:
|
||||
case PC_DCCCI:
|
||||
case PC_ICBT:
|
||||
case PC_ICCCI:
|
||||
case PC_ICREAD:
|
||||
case PC_DCBA:
|
||||
case PC_DST:
|
||||
case PC_DSTT:
|
||||
case PC_DSTST:
|
||||
case PC_DSTSTT:
|
||||
if (instr->args[0].data.reg.reg >= n_real_registers[coloring_class])
|
||||
makeinterfere(0, instr->args[0].data.reg.reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (coloring_class == RegClass_GPR && (instr->flags & fPCodeFlag8)) {
|
||||
i = branch_count_volatiles();
|
||||
op = instr->args;
|
||||
#line 219
|
||||
CError_ASSERT(instr->argCount != 0);
|
||||
|
||||
while (op->kind != PCOp_REGISTER && !(op->data.reg.effect & EffectWrite)) {
|
||||
i++;
|
||||
op++;
|
||||
#line 226
|
||||
CError_ASSERT(i <= instr->argCount);
|
||||
}
|
||||
|
||||
op = instr->args + i;
|
||||
while (i < instr->argCount) {
|
||||
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
|
||||
for (j = 0; j < n_scratch_registers[coloring_class]; j++)
|
||||
makeinterfere(op->data.reg.reg, scratch_registers[coloring_class][j]);
|
||||
}
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static short coalesced_path(short id) {
|
||||
while (id != coalesced[id])
|
||||
id = coalesced[id];
|
||||
return id;
|
||||
}
|
||||
|
||||
static void coalescenodes(void) {
|
||||
PCodeArg *op;
|
||||
UInt32 regs;
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
UInt32 i;
|
||||
short path1;
|
||||
short path2;
|
||||
short node1;
|
||||
short node2;
|
||||
|
||||
regs = used_virtual_registers[coloring_class];
|
||||
coalesced = oalloc(sizeof(SInt16) * regs);
|
||||
|
||||
for (i = 0; i < regs; i++)
|
||||
coalesced[i] = i;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
if ((instr->flags & fPCodeFlag10) && !(instr->flags & fSideEffects)) {
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000) {
|
||||
#line 309
|
||||
CError_FATAL();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (instr->argCount > 2) {
|
||||
if (instr->argCount != 3 || instr->args[2].kind != PCOp_PLACEHOLDEROPERAND) {
|
||||
#line 316
|
||||
CError_FATAL();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (instr->args[0].kind == PCOp_REGISTER && (char) instr->args[0].arg == coloring_class) {
|
||||
path1 = coalesced_path(instr->args[0].data.reg.reg);
|
||||
path2 = coalesced_path(instr->args[1].data.reg.reg);
|
||||
if (path1 == path2) {
|
||||
deletepcode(instr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!interferes(path1, path2)) {
|
||||
if (path1 >= n_real_registers[coloring_class] && path2 >= n_real_registers[coloring_class]) {
|
||||
if (path1 < first_fe_temporary_register[coloring_class])
|
||||
continue;
|
||||
if (path1 > last_temporary_register[coloring_class])
|
||||
continue;
|
||||
if (path2 < first_fe_temporary_register[coloring_class])
|
||||
continue;
|
||||
if (path2 > last_temporary_register[coloring_class])
|
||||
continue;
|
||||
}
|
||||
|
||||
node1 = (path2 < path1) ? path2 : path1;
|
||||
node2 = (path2 > path1) ? path2 : path1;
|
||||
|
||||
if (coloring_class == RegClass_GPR && node2 == _CALLER_SP_)
|
||||
continue;
|
||||
|
||||
coalesced[node2] = node1;
|
||||
for (i = 0; i < regs; i++) {
|
||||
if (interferes(node2, i))
|
||||
makeinterfere(node1, i);
|
||||
}
|
||||
|
||||
deletepcode(instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == coloring_class &&
|
||||
op->data.reg.reg != coalesced[op->data.reg.reg]
|
||||
)
|
||||
op->data.reg.reg = coalesced_path(op->data.reg.reg);
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void buildadjacencyvectors(void) {
|
||||
IGNode *node;
|
||||
UInt32 regs;
|
||||
UInt32 i;
|
||||
UInt32 counter;
|
||||
short *array;
|
||||
short *dest;
|
||||
short *src;
|
||||
UInt32 j;
|
||||
|
||||
regs = used_virtual_registers[coloring_class];
|
||||
interferencegraph = oalloc(sizeof(IGNode *) * regs);
|
||||
array = oalloc(sizeof(short) * regs);
|
||||
|
||||
for (i = 0; i < regs; i++) {
|
||||
counter = 0;
|
||||
for (j = 0; j < regs; j++) {
|
||||
if (interferes(i, j))
|
||||
array[counter++] = j;
|
||||
}
|
||||
|
||||
node = interferencegraph[i] = oalloc(sizeof(IGNode) + sizeof(short) * (counter - 1));
|
||||
memclrw(node, sizeof(IGNode) + sizeof(short) * (counter - 1));
|
||||
|
||||
node->x10 = i;
|
||||
node->x14 = -1;
|
||||
node->arraySize = counter;
|
||||
node->x12 = counter;
|
||||
|
||||
dest = node->array;
|
||||
src = array;
|
||||
for (j = 0; j < counter; j++)
|
||||
*(dest++) = *(src++);
|
||||
|
||||
if (i != coalesced[i]) {
|
||||
node->flags |= fCoalesced;
|
||||
j = coalesced_path(i);
|
||||
interferencegraph[j]->flags |= fCoalescedInto;
|
||||
node->x14 = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void eliminatedeadcode(void) {
|
||||
UInt32 regs;
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
UInt32 *vec;
|
||||
UInt32 i;
|
||||
PCodeArg *op;
|
||||
|
||||
regs = used_virtual_registers[coloring_class];
|
||||
vec = oalloc(4 * ((regs + 31) >> 5));
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
bitvectorcopy(vec, liveinfo[block->blockIndex].vecC, regs);
|
||||
for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
|
||||
if (dead(instr, coloring_class, vec)) {
|
||||
deletepcode(instr);
|
||||
continue;
|
||||
}
|
||||
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == coloring_class &&
|
||||
(op->data.reg.effect & EffectWrite)
|
||||
)
|
||||
bitvectorclearbit(op->data.reg.reg, vec);
|
||||
op++;
|
||||
}
|
||||
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == coloring_class &&
|
||||
(op->data.reg.effect & EffectRead)
|
||||
)
|
||||
{
|
||||
int reg = op->data.reg.reg;
|
||||
if (!bitvectorgetbit(reg, vec))
|
||||
op->data.reg.effect |= Effect4;
|
||||
bitvectorsetbit(reg, vec);
|
||||
}
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void findrematerializations(void) {
|
||||
UInt32 regs;
|
||||
UInt32 i;
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
PCodeArg *op;
|
||||
IGNode *node;
|
||||
|
||||
regs = used_virtual_registers[coloring_class];
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == coloring_class &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
op->data.reg.reg >= n_real_registers[coloring_class] &&
|
||||
!(interferencegraph[op->data.reg.reg]->flags & (fPairLow | fPairHigh)) &&
|
||||
!(interferencegraph[op->data.reg.reg]->flags & fIGNode40)
|
||||
)
|
||||
{
|
||||
node = interferencegraph[op->data.reg.reg];
|
||||
if (!node->instr8) {
|
||||
node->instr8 = instr;
|
||||
} else {
|
||||
node->instr8 = NULL;
|
||||
node->flags |= fIGNode40;
|
||||
}
|
||||
}
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < regs; i++) {
|
||||
node = interferencegraph[i];
|
||||
if (node->instr8 && !is_location_independent(node->instr8))
|
||||
node->instr8 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void buildinterferencegraph(Object *proc) {
|
||||
int regs = used_virtual_registers[coloring_class];
|
||||
|
||||
computelivevariables(proc);
|
||||
eliminatedeadcode();
|
||||
buildinterferencematrix();
|
||||
if (copts.debuglisting)
|
||||
pclistinterferences(register_class_format[coloring_class], regs);
|
||||
coalescenodes();
|
||||
buildadjacencyvectors();
|
||||
findrematerializations();
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/CParser.h"
|
||||
|
||||
Boolean DoScalarize;
|
||||
Boolean DoLinearize;
|
||||
Boolean EarlyReturn;
|
||||
Boolean IRO_CPFirstTime;
|
||||
Boolean VectorPhaseCalledFromUnroll;
|
||||
Boolean IRO_Log;
|
||||
static Boolean stIsSetup;
|
||||
|
||||
static void CountRefToObject() {
|
||||
}
|
||||
|
||||
static void CountARef() {
|
||||
}
|
||||
|
||||
static void CountDoubleInd() {
|
||||
}
|
||||
|
||||
static void CountUsage() {
|
||||
}
|
||||
|
||||
Statement *IRO_Optimizer(Object *obj, Statement *stmt) {
|
||||
}
|
||||
|
||||
void IRO_Setup(void) {
|
||||
static Boolean ENodeArraysHaveBeenInitialized;
|
||||
}
|
||||
|
||||
void IRO_Cleanup(void) {
|
||||
}
|
||||
|
||||
void CodeGen_UpdateOptimizerOptions(void) {
|
||||
copts.opt_dead_code = copts.optimizationlevel > 0;
|
||||
copts.opt_propagation = copts.optimizationlevel > 1;
|
||||
copts.opt_common_subs = copts.optimizationlevel > 1;
|
||||
copts.opt_vectorize_loops = copts.optimizationlevel > 2;
|
||||
copts.opt_unroll_loops = copts.optimizationlevel > 2;
|
||||
copts.opt_dead_assignments = copts.optimizationlevel > 2;
|
||||
copts.opt_lifetimes = copts.optimizationlevel > 2;
|
||||
copts.opt_strength_reduction = copts.optimizationlevel > 2;
|
||||
copts.opt_loop_invariants = copts.optimizationlevel > 2;
|
||||
copts._B4 = copts.optimizationlevel > 3;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#include "compiler/IroBitVect.h"
|
||||
#include "compiler/BitVector.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
|
||||
void Bv_AllocVector(BitVector **bv, UInt32 size) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,652 @@
|
||||
#include "compiler/IroDump.h"
|
||||
#include "compiler/IroFlowgraph.h"
|
||||
#include "compiler/IroLinearForm.h"
|
||||
#include "compiler/IroPropagate.h"
|
||||
#include "compiler/IroUtil.h"
|
||||
#include "compiler/CFunc.h"
|
||||
#include "compiler/CInt64.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/IroVars.h"
|
||||
#include "compiler/IroCSE.h"
|
||||
|
||||
static FILE *DumpFile;
|
||||
static char *nodenames[MAXEXPR];
|
||||
|
||||
char *IRO_NodeName(ENodeType nodetype) {
|
||||
return nodenames[nodetype];
|
||||
}
|
||||
|
||||
void IRO_InitializeNodeNamesArray(void) {
|
||||
int i;
|
||||
for (i = 0; i < MAXEXPR; i++)
|
||||
nodenames[i] = "";
|
||||
|
||||
nodenames[EPOSTINC] = "EPOSTINC";
|
||||
nodenames[EPOSTDEC] = "EPOSTDEC";
|
||||
nodenames[EPREINC] = "EPREINC";
|
||||
nodenames[EPREDEC] = "EPREDEC";
|
||||
nodenames[EINDIRECT] = "EINDIRECT";
|
||||
nodenames[EMONMIN] = "EMONMIN";
|
||||
nodenames[EBINNOT] = "EBINNOT";
|
||||
nodenames[ELOGNOT] = "ELOGNOT";
|
||||
nodenames[EFORCELOAD] = "EFORCELOAD";
|
||||
nodenames[EMUL] = "EMUL";
|
||||
nodenames[EMULV] = "EMULV";
|
||||
nodenames[EDIV] = "EDIV";
|
||||
nodenames[EMODULO] = "EMODULO";
|
||||
nodenames[EADDV] = "EADDV";
|
||||
nodenames[ESUBV] = "ESUBV";
|
||||
nodenames[EADD] = "EADD";
|
||||
nodenames[ESUB] = "ESUB";
|
||||
nodenames[ESHL] = "ESHL";
|
||||
nodenames[ESHR] = "ESHR";
|
||||
nodenames[ELESS] = "ELESS";
|
||||
nodenames[EGREATER] = "EGREATER";
|
||||
nodenames[ELESSEQU] = "ELESSEQU";
|
||||
nodenames[EGREATEREQU] = "EGREATEREQU";
|
||||
nodenames[EEQU] = "EEQU";
|
||||
nodenames[ENOTEQU] = "ENOTEQU";
|
||||
nodenames[EAND] = "EAND";
|
||||
nodenames[EXOR] = "EXOR";
|
||||
nodenames[EOR] = "EOR";
|
||||
nodenames[ELAND] = "ELAND";
|
||||
nodenames[ELOR] = "ELOR";
|
||||
nodenames[EASS] = "EASS";
|
||||
nodenames[EMULASS] = "EMULASS";
|
||||
nodenames[EDIVASS] = "EDIVASS";
|
||||
nodenames[EMODASS] = "EMODASS";
|
||||
nodenames[EADDASS] = "EADDASS";
|
||||
nodenames[ESUBASS] = "ESUBASS";
|
||||
nodenames[ESHLASS] = "ESHLASS";
|
||||
nodenames[ESHRASS] = "ESHRASS";
|
||||
nodenames[EANDASS] = "EANDASS";
|
||||
nodenames[EXORASS] = "EXORASS";
|
||||
nodenames[EORASS] = "EORASS";
|
||||
nodenames[ECOMMA] = "ECOMMA";
|
||||
nodenames[EPMODULO] = "EPMODULO";
|
||||
nodenames[EROTL] = "EROTL";
|
||||
nodenames[EROTR] = "EROTR";
|
||||
nodenames[EBCLR] = "EBCLR";
|
||||
nodenames[EBTST] = "EBTST";
|
||||
nodenames[EBSET] = "EBSET";
|
||||
nodenames[ETYPCON] = "ETYPCON";
|
||||
nodenames[EBITFIELD] = "EBITFIELD";
|
||||
nodenames[EINTCONST] = "EINTCONST";
|
||||
nodenames[EFLOATCONST] = "EFLOATCONST";
|
||||
nodenames[ESTRINGCONST] = "ESTRINGCONST";
|
||||
nodenames[ECOND] = "ECOND";
|
||||
nodenames[EFUNCCALL] = "EFUNCCALL";
|
||||
nodenames[EFUNCCALLP] = "EFUNCCALLP";
|
||||
nodenames[EOBJREF] = "EOBJREF";
|
||||
nodenames[EMFPOINTER] = "EMFPOINTER";
|
||||
nodenames[ENULLCHECK] = "ENULLCHECK";
|
||||
nodenames[EPRECOMP] = "EPRECOMP";
|
||||
nodenames[ETEMP] = "ETEMP";
|
||||
nodenames[EARGOBJ] = "EARGOBJ";
|
||||
nodenames[ELOCOBJ] = "ELOCOBJ";
|
||||
nodenames[ELABEL] = "ELABEL";
|
||||
nodenames[ESETCONST] = "ESETCONST";
|
||||
nodenames[ENEWEXCEPTION] = "ENEWEXCEPTION";
|
||||
nodenames[ENEWEXCEPTIONARRAY] = "ENEWEXCEPTIONARRAY";
|
||||
nodenames[EOBJLIST] = "EOBJLIST";
|
||||
nodenames[EMEMBER] = "EMEMBER";
|
||||
nodenames[ETEMPLDEP] = "ETEMPLDEP";
|
||||
nodenames[EINSTRUCTION] = "EINSTRUCTION";
|
||||
nodenames[EDEFINE] = "EDEFINE";
|
||||
nodenames[EREUSE] = "EREUSE";
|
||||
nodenames[EASSBLK] = "EASSBLK";
|
||||
nodenames[EVECTOR128CONST] = "EVECTOR128CONST";
|
||||
nodenames[ECONDASS] = "ECONDASS";
|
||||
}
|
||||
|
||||
static void DumpENode(ENode *enode) {
|
||||
char buf[64];
|
||||
|
||||
if (IRO_Log) {
|
||||
switch (enode->type) {
|
||||
case EOBJREF:
|
||||
fprintf(DumpFile, "%s", enode->data.objref->name->name);
|
||||
break;
|
||||
case EINTCONST:
|
||||
CInt64_PrintDec(buf, enode->data.intval);
|
||||
fprintf(DumpFile, "%s", buf);
|
||||
break;
|
||||
case EFLOATCONST:
|
||||
fprintf(DumpFile, "%g", enode->data.floatval.value);
|
||||
break;
|
||||
case EVECTOR128CONST:
|
||||
fprintf(DumpFile, "%.8lX%.8lX%.8lX%.8lX",
|
||||
enode->data.vector128val.ul[0],
|
||||
enode->data.vector128val.ul[1],
|
||||
enode->data.vector128val.ul[2],
|
||||
enode->data.vector128val.ul[3]
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpLinearNode(IROLinear *linear) {
|
||||
int i;
|
||||
|
||||
if (IRO_Log) {
|
||||
fprintf(DumpFile, "%4d: ", linear->index);
|
||||
switch (linear->type) {
|
||||
case IROLinearNop:
|
||||
fprintf(DumpFile, "Nop");
|
||||
break;
|
||||
case IROLinearOperand:
|
||||
fprintf(DumpFile, "Operand ");
|
||||
DumpENode(linear->u.node);
|
||||
break;
|
||||
case IROLinearOp1Arg:
|
||||
fprintf(DumpFile, "%s %d", nodenames[linear->nodetype], linear->u.monadic->index);
|
||||
break;
|
||||
case IROLinearOp2Arg:
|
||||
fprintf(DumpFile, "%s %d %d", nodenames[linear->nodetype], linear->u.diadic.left->index, linear->u.diadic.right->index);
|
||||
break;
|
||||
case IROLinearGoto:
|
||||
fprintf(DumpFile, "Goto %s", linear->u.label.label->name->name);
|
||||
break;
|
||||
case IROLinearIf:
|
||||
fprintf(DumpFile, "If %d %s", linear->u.label.x4->index, linear->u.label.label->name->name);
|
||||
break;
|
||||
case IROLinearIfNot:
|
||||
fprintf(DumpFile, "IfNot %d %s", linear->u.label.x4->index, linear->u.label.label->name->name);
|
||||
break;
|
||||
case IROLinearReturn:
|
||||
fprintf(DumpFile, "Return ");
|
||||
if (linear->u.monadic)
|
||||
fprintf(DumpFile, "%d", linear->u.monadic->index);
|
||||
break;
|
||||
case IROLinearLabel:
|
||||
fprintf(DumpFile, "Label %s", linear->u.label.label->name->name);
|
||||
break;
|
||||
case IROLinearSwitch:
|
||||
fprintf(DumpFile, "Switch %d", linear->u.swtch.x4->index);
|
||||
break;
|
||||
case IROLinearOp3Arg:
|
||||
fprintf(DumpFile, "%s %d %d %d",
|
||||
nodenames[linear->nodetype],
|
||||
linear->u.args3.a->index,
|
||||
linear->u.args3.b->index,
|
||||
linear->u.args3.c->index);
|
||||
break;
|
||||
case IROLinearFunccall:
|
||||
fprintf(DumpFile, "Funccall %d(", linear->u.funccall.linear8->index);
|
||||
for (i = 0; i < linear->u.funccall.argCount; i++) {
|
||||
fprintf(DumpFile, "%d", linear->u.funccall.args[i]->index);
|
||||
if (i < (linear->u.funccall.argCount - 1))
|
||||
fprintf(DumpFile, ",");
|
||||
}
|
||||
fprintf(DumpFile, ")");
|
||||
break;
|
||||
case IROLinearBeginCatch:
|
||||
fprintf(DumpFile, "BeginCatch %d", linear->u.ctch.linear->index);
|
||||
break;
|
||||
case IROLinearEndCatch:
|
||||
fprintf(DumpFile, "EndCatch %d", linear->u.monadic->index);
|
||||
break;
|
||||
case IROLinearEndCatchDtor:
|
||||
fprintf(DumpFile, "EndCatchDtor %d", linear->u.monadic->index);
|
||||
break;
|
||||
case IROLinearEnd:
|
||||
fprintf(DumpFile, "End");
|
||||
break;
|
||||
}
|
||||
|
||||
if (linear->flags & IROLF_Assigned) fprintf(DumpFile, " <assigned>");
|
||||
if (linear->flags & IROLF_Used) fprintf(DumpFile, " <used>");
|
||||
if (linear->flags & IROLF_Ind) fprintf(DumpFile, " <ind>");
|
||||
if (linear->flags & IROLF_Subs) fprintf(DumpFile, " <subs>");
|
||||
if (linear->flags & IROLF_LoopInvariant) fprintf(DumpFile, " <loop invariant>");
|
||||
if (linear->flags & IROLF_BeginLoop) fprintf(DumpFile, " <begin loop>");
|
||||
if (linear->flags & IROLF_EndLoop) fprintf(DumpFile, " <end loop>");
|
||||
if (linear->flags & IROLF_Ris) fprintf(DumpFile, " <ris>");
|
||||
if (linear->flags & IROLF_Immind) fprintf(DumpFile, " <immind>");
|
||||
if (linear->flags & IROLF_Reffed) fprintf(DumpFile, " <reffed>");
|
||||
if (linear->flags & IROLF_VecOp) fprintf(DumpFile, " <vec op>");
|
||||
if (linear->flags & IROLF_VecOpBase) fprintf(DumpFile, " <vec op_base>");
|
||||
if (linear->flags & IROLF_CounterLoop) fprintf(DumpFile, " <counter loop>");
|
||||
if (linear->flags & IROLF_BitfieldIndirect) fprintf(DumpFile, " <bitfield_indirect>");
|
||||
if (linear->flags & IROLF_CouldError) fprintf(DumpFile, " <could_error>");
|
||||
|
||||
if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS))
|
||||
fprintf(DumpFile, " <volatile>");
|
||||
|
||||
if (IS_LINEAR_ENODE(linear, EOBJREF)) {
|
||||
VarRecord *var = IRO_FindVar(linear->u.node->data.objref, 0, 1);
|
||||
if (var && is_volatile_object(var->object))
|
||||
fprintf(DumpFile, " <volatile obj>");
|
||||
}
|
||||
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpAct(IROLinear *linear, Boolean isFirst) {
|
||||
if (!isFirst)
|
||||
DumpLinearNode(linear);
|
||||
}
|
||||
|
||||
void IRO_DumpIntTree(IROLinear *linear) {
|
||||
IRO_WalkTree(linear, DumpAct);
|
||||
}
|
||||
|
||||
void IRO_DumpLinearList(IROLinear *linear) {
|
||||
if (!IRO_Log)
|
||||
return;
|
||||
|
||||
while (linear) {
|
||||
DumpLinearNode(linear);
|
||||
linear = linear->next;
|
||||
}
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
|
||||
static void DumpList(int num, UInt16 *list) {
|
||||
int i;
|
||||
|
||||
if (IRO_Log) {
|
||||
for (i = 0; i < num; i++)
|
||||
fprintf(DumpFile, "%d ", list[i]);
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_DumpBits(char *name, BitVector *bv) {
|
||||
SInt32 i;
|
||||
SInt32 rangeStart;
|
||||
Boolean inRange = 0;
|
||||
Boolean isFirst = 1;
|
||||
|
||||
if (!IRO_Log)
|
||||
return;
|
||||
|
||||
fprintf(DumpFile, name);
|
||||
if (!bv) {
|
||||
fprintf(DumpFile, "NULL");
|
||||
} else {
|
||||
for (i = 0; i < (bv->size * 32); i++) {
|
||||
if (Bv_IsBitSet(i, bv)) {
|
||||
if (!inRange) {
|
||||
if (!isFirst)
|
||||
fputc(',', DumpFile);
|
||||
isFirst = 0;
|
||||
fprintf(DumpFile, "%d", i);
|
||||
inRange = 1;
|
||||
rangeStart = i;
|
||||
}
|
||||
} else {
|
||||
if (inRange) {
|
||||
inRange = 0;
|
||||
if (i != (rangeStart + 1))
|
||||
fprintf(DumpFile, "-%d", i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inRange && i != (rangeStart + 1))
|
||||
fprintf(DumpFile, "-%d", i - 1);
|
||||
}
|
||||
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
|
||||
void IRO_DumpAfterPhase(char *str, Boolean flag) {
|
||||
if (flag) {
|
||||
IRO_Dump("Dumping function %s after %s \n", FunctionName ? FunctionName->name->name : "Init-code", str);
|
||||
IRO_Dump("--------------------------------------------------------------------------------\n");
|
||||
IRO_DumpFlowgraph();
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_LogForFunction(char *name) {
|
||||
if (FunctionName) {
|
||||
if (!strcmp(FunctionName->name->name, name))
|
||||
IRO_Log = 1;
|
||||
else
|
||||
IRO_Log = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_DumpFlowgraph(void) {
|
||||
IRONode *node;
|
||||
IROLinear *linear;
|
||||
|
||||
if (IRO_Log && DumpFile) {
|
||||
fprintf(DumpFile, "\nFlowgraph\n");
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
fprintf(DumpFile, "Flowgraph node %d First=%d, Last=%d\n", node->index, node->first->index, node->last->index);
|
||||
|
||||
fprintf(DumpFile, "Succ = ");
|
||||
DumpList(node->numsucc, node->succ);
|
||||
fprintf(DumpFile, "Pred = ");
|
||||
DumpList(node->numpred, node->pred);
|
||||
|
||||
fprintf(DumpFile, "MustReach = %d, MustReach1=%d\n", node->mustreach, node->mustreach1);
|
||||
fprintf(DumpFile, "LoopDepth = %d\n", node->loopdepth);
|
||||
|
||||
IRO_DumpBits("Dom: ", node->dom);
|
||||
if ((linear = node->first)) {
|
||||
while (1) {
|
||||
DumpLinearNode(linear);
|
||||
if (linear == node->last)
|
||||
break;
|
||||
linear = linear->next;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(DumpFile, "\n\n");
|
||||
}
|
||||
fprintf(DumpFile, "\n");
|
||||
fflush(DumpFile);
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_DumpNode(IRONode *node) {
|
||||
IROLinear *linear;
|
||||
|
||||
if (IRO_Log) {
|
||||
if (!DumpFile)
|
||||
return;
|
||||
|
||||
while (node) {
|
||||
fprintf(DumpFile, "Flowgraph node %d First=%d, Last=%d\n", node->index, node->first->index,
|
||||
node->last->index);
|
||||
|
||||
fprintf(DumpFile, "Succ = ");
|
||||
DumpList(node->numsucc, node->succ);
|
||||
fprintf(DumpFile, "Pred = ");
|
||||
DumpList(node->numpred, node->pred);
|
||||
|
||||
fprintf(DumpFile, "MustReach = %d MustReach1 = %d\n", node->mustreach, node->mustreach1);
|
||||
fprintf(DumpFile, "LoopDepth = %d\n", node->loopdepth);
|
||||
|
||||
IRO_DumpBits("Dom: ", node->dom);
|
||||
if ((linear = node->first)) {
|
||||
while (1) {
|
||||
DumpLinearNode(linear);
|
||||
if (linear == node->last)
|
||||
break;
|
||||
linear = linear->next;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(DumpFile, "\n\n");
|
||||
node = node->nextnode;
|
||||
}
|
||||
|
||||
fprintf(DumpFile, "\n");
|
||||
fflush(DumpFile);
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_DumpAssignments(void) {
|
||||
IROAssign *assign;
|
||||
|
||||
if (IRO_Log) {
|
||||
fprintf(DumpFile, "\nAssignments\n\n");
|
||||
for (assign = IRO_FirstAssign; assign; assign = assign->next) {
|
||||
fprintf(DumpFile, "%5d ", assign->index);
|
||||
DumpLinearNode(assign->linear);
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_DumpVars(void) {
|
||||
VarRecord *var;
|
||||
|
||||
if (IRO_Log) {
|
||||
fprintf(DumpFile, "\nVariables\n");
|
||||
for (var = IRO_FirstVar; var; var = var->next) {
|
||||
fprintf(DumpFile, "%5d %s %s\n", var->index, var->object->name->name, var->xB ? "<addressed>" : "");
|
||||
}
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_DumpDf(void) {
|
||||
IRONode *node;
|
||||
|
||||
if (IRO_Log) {
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
fprintf(DumpFile, "Node %d\n", node->index);
|
||||
if (node->x16) IRO_DumpBits("In: ", node->x16);
|
||||
if (node->x1E) IRO_DumpBits("Gen: ", node->x1E);
|
||||
if (node->x22) IRO_DumpBits("Kill: ", node->x22);
|
||||
if (node->x1A) IRO_DumpBits("Out: ", node->x1A);
|
||||
if (node->x2A) IRO_DumpBits("AA: ", node->x2A);
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_DumpExprs(void) {
|
||||
IROExpr *expr;
|
||||
|
||||
if (IRO_Log) {
|
||||
fprintf(DumpFile, "Expressions\n\n");
|
||||
for (expr = IRO_FirstExpr; expr; expr = expr->next) {
|
||||
fprintf(DumpFile, "%4d: %d FN:%d CE:%d NS:%d ", expr->index, expr->linear->index, expr->node->index, expr->couldError, expr->notSubable);
|
||||
IRO_DumpBits("Depends: ", expr->depends);
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_SetupDump(void) {
|
||||
if (IRO_Log) {
|
||||
if ((DumpFile = fopen("OPT.LOG", "wt")) == NULL)
|
||||
IRO_Log = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_CleanupDump(void) {
|
||||
if (DumpFile)
|
||||
fclose(DumpFile);
|
||||
}
|
||||
|
||||
void IRO_Dump(char *format, ...) {
|
||||
va_list va;
|
||||
if (IRO_Log) {
|
||||
va_start(va, format);
|
||||
vfprintf(DumpFile, format, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_DumpAddr(IROAddrRecord *rec) {
|
||||
IROElmList *list;
|
||||
|
||||
if (IRO_Log && DumpFile) {
|
||||
fprintf(DumpFile, "\n");
|
||||
fprintf(DumpFile, "Address :\n");
|
||||
IRO_DumpIntTree(rec->linear);
|
||||
fprintf(DumpFile, "\n");
|
||||
fprintf(DumpFile, "BaseTerms:\n");
|
||||
for (list = rec->objRefs; list; list = list->next) {
|
||||
IRO_DumpIntTree(list->element);
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
fprintf(DumpFile, "VarTerms:\n");
|
||||
for (list = rec->misc; list; list = list->next) {
|
||||
IRO_DumpIntTree(list->element);
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
fprintf(DumpFile, "ConstTerms:\n");
|
||||
for (list = rec->ints; list; list = list->next) {
|
||||
IRO_DumpIntTree(list->element);
|
||||
fprintf(DumpFile, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void IRO_DumpType(Type *type) {
|
||||
char buf[256];
|
||||
IRO_SpellType(type, buf);
|
||||
fprintf(DumpFile, " (%s)", buf);
|
||||
}
|
||||
|
||||
void IRO_SpellType(Type *type, char *buf) {
|
||||
char mybuf[256];
|
||||
char mybuf2[256];
|
||||
|
||||
switch (type->type) {
|
||||
case TYPEVOID:
|
||||
strcpy(buf, "void");
|
||||
break;
|
||||
case TYPEINT:
|
||||
switch (TYPE_INTEGRAL(type)->integral) {
|
||||
case IT_BOOL:
|
||||
strcpy(buf, "bool");
|
||||
break;
|
||||
case IT_CHAR:
|
||||
strcpy(buf, "char");
|
||||
break;
|
||||
case IT_WCHAR_T:
|
||||
strcpy(buf, "wchar_t");
|
||||
break;
|
||||
case IT_SCHAR:
|
||||
strcpy(buf, "signed char");
|
||||
break;
|
||||
case IT_UCHAR:
|
||||
strcpy(buf, "unsigned char");
|
||||
break;
|
||||
case IT_SHORT:
|
||||
strcpy(buf, "short");
|
||||
break;
|
||||
case IT_USHORT:
|
||||
strcpy(buf, "unsigned short");
|
||||
break;
|
||||
case IT_INT:
|
||||
strcpy(buf, "int");
|
||||
break;
|
||||
case IT_UINT:
|
||||
strcpy(buf, "unsigned int");
|
||||
break;
|
||||
case IT_LONG:
|
||||
strcpy(buf, "long");
|
||||
break;
|
||||
case IT_ULONG:
|
||||
strcpy(buf, "unsigned long");
|
||||
break;
|
||||
case IT_LONGLONG:
|
||||
strcpy(buf, "long long");
|
||||
break;
|
||||
case IT_ULONGLONG:
|
||||
strcpy(buf, "unsigned long long");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TYPEFLOAT:
|
||||
switch (TYPE_INTEGRAL(type)->integral) {
|
||||
case IT_FLOAT:
|
||||
strcpy(buf, "float");
|
||||
break;
|
||||
case IT_SHORTDOUBLE:
|
||||
strcpy(buf, "short double");
|
||||
break;
|
||||
case IT_DOUBLE:
|
||||
strcpy(buf, "double");
|
||||
break;
|
||||
case IT_LONGDOUBLE:
|
||||
strcpy(buf, "long double");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TYPEENUM:
|
||||
strcpy(buf, "enum ");
|
||||
if (TYPE_ENUM(type)->enumname)
|
||||
strcat(buf, TYPE_ENUM(type)->enumname->name);
|
||||
break;
|
||||
case TYPESTRUCT:
|
||||
if (IS_TYPESTRUCT_VECTOR(type)) {
|
||||
switch (TYPE_STRUCT(type)->stype) {
|
||||
case STRUCT_TYPE_4:
|
||||
strcpy(buf, "vector unsigned char ");
|
||||
break;
|
||||
case STRUCT_TYPE_5:
|
||||
strcpy(buf, "vector signed char ");
|
||||
break;
|
||||
case STRUCT_TYPE_6:
|
||||
strcpy(buf, "vector bool char ");
|
||||
break;
|
||||
case STRUCT_TYPE_7:
|
||||
strcpy(buf, "vector unsigned short ");
|
||||
break;
|
||||
case STRUCT_TYPE_8:
|
||||
strcpy(buf, "vector signed short ");
|
||||
break;
|
||||
case STRUCT_TYPE_9:
|
||||
strcpy(buf, "vector bool short ");
|
||||
break;
|
||||
case STRUCT_TYPE_A:
|
||||
strcpy(buf, "vector unsigned long ");
|
||||
break;
|
||||
case STRUCT_TYPE_B:
|
||||
strcpy(buf, "vector signed long ");
|
||||
break;
|
||||
case STRUCT_TYPE_C:
|
||||
strcpy(buf, "vector bool long ");
|
||||
break;
|
||||
case STRUCT_TYPE_D:
|
||||
strcpy(buf, "vector float ");
|
||||
break;
|
||||
case STRUCT_TYPE_E:
|
||||
strcpy(buf, "vector pixel ");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
strcpy(buf, "struct ");
|
||||
}
|
||||
if (TYPE_STRUCT(type)->name)
|
||||
strcat(buf, TYPE_STRUCT(type)->name->name);
|
||||
break;
|
||||
case TYPECLASS:
|
||||
strcpy(buf, "class ");
|
||||
if (TYPE_CLASS(type)->classname)
|
||||
strcat(buf, TYPE_CLASS(type)->classname->name);
|
||||
break;
|
||||
case TYPEFUNC:
|
||||
IRO_SpellType(TYPE_FUNC(type)->functype, mybuf);
|
||||
strcpy(buf, "freturns(");
|
||||
strcat(buf, mybuf);
|
||||
strcat(buf, ")");
|
||||
break;
|
||||
case TYPEBITFIELD:
|
||||
IRO_SpellType(TYPE_BITFIELD(type)->bitfieldtype, mybuf);
|
||||
sprintf(buf, "bitfield(%s){%d:%d}", mybuf, TYPE_BITFIELD(type)->unkA, TYPE_BITFIELD(type)->unkB);
|
||||
break;
|
||||
case TYPELABEL:
|
||||
strcpy(buf, "label");
|
||||
break;
|
||||
case TYPEPOINTER:
|
||||
IRO_SpellType(TPTR_TARGET(type), mybuf);
|
||||
strcpy(buf, "pointer(");
|
||||
strcat(buf, mybuf);
|
||||
strcat(buf, ")");
|
||||
break;
|
||||
case TYPEARRAY:
|
||||
IRO_SpellType(TPTR_TARGET(type), mybuf);
|
||||
strcpy(buf, "array(");
|
||||
strcat(buf, mybuf);
|
||||
strcat(buf, ")");
|
||||
break;
|
||||
case TYPEMEMBERPOINTER:
|
||||
IRO_SpellType(TYPE_MEMBER_POINTER(type)->ty2, mybuf);
|
||||
IRO_SpellType(TYPE_MEMBER_POINTER(type)->ty1, mybuf2);
|
||||
strcpy(buf, "memberpointer(");
|
||||
strcat(buf, mybuf);
|
||||
strcat(buf, ",");
|
||||
strcat(buf, mybuf2);
|
||||
strcat(buf, ")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,567 @@
|
||||
#include "compiler/IroEmptyLoop.h"
|
||||
#include "compiler/IroDump.h"
|
||||
#include "compiler/IroFlowgraph.h"
|
||||
#include "compiler/IroLinearForm.h"
|
||||
#include "compiler/IroLoop.h"
|
||||
#include "compiler/IroUtil.h"
|
||||
#include "compiler/IroVars.h"
|
||||
#include "compiler/CInt64.h"
|
||||
|
||||
// forward decls
|
||||
static Boolean EmptyLoop(IRONode *fnode);
|
||||
static int CanRemoveRedundantLoop(IROLoop *loop);
|
||||
static int CanRemoveRedundantLoop1(IROLoop *loop);
|
||||
static int RedundantLoopCheck(IROLoop *loop);
|
||||
static int CheckStepOverFlow1_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2);
|
||||
static int CheckStepOverFlow2_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2);
|
||||
|
||||
void IRO_FindEmptyLoops(void) {
|
||||
IRONode *fnode;
|
||||
IRONode *pred;
|
||||
UInt16 i;
|
||||
UInt16 x;
|
||||
|
||||
for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
|
||||
x = 0;
|
||||
for (i = 0; i < fnode->numpred; i++) {
|
||||
pred = IRO_NodeTable[fnode->pred[i]];
|
||||
if (Bv_IsBitSet(fnode->index, pred->dom)) {
|
||||
if (!x) {
|
||||
Bv_AllocVector(&InLoop, IRO_NumNodes + 1);
|
||||
Bv_Clear(InLoop);
|
||||
Bv_SetBit(fnode->index, InLoop);
|
||||
}
|
||||
x = 1;
|
||||
Bv_SetBit(pred->index, InLoop);
|
||||
if (pred != fnode)
|
||||
AddPreds(pred);
|
||||
}
|
||||
}
|
||||
|
||||
if (x) {
|
||||
IRO_Dump("IRO_FindEmptyLoops:Found loop with header %d\n", fnode->index);
|
||||
IRO_DumpBits("Loop includes: ", InLoop);
|
||||
EmptyLoop(fnode);
|
||||
IRO_UpdateFlagsOnInts();
|
||||
}
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
}
|
||||
|
||||
static Boolean EmptyLoop(IRONode *fnode) {
|
||||
VarRecord *var;
|
||||
IRONode *bestpred;
|
||||
IRONode *pred;
|
||||
UInt16 i;
|
||||
int flag2;
|
||||
IRONode *r24;
|
||||
Boolean flag;
|
||||
int counter;
|
||||
int j;
|
||||
IRONode *succ;
|
||||
IRONode *bestsucc;
|
||||
int counter2;
|
||||
UInt32 counter3;
|
||||
IROLoop *loop;
|
||||
IRONode *r21;
|
||||
IRONode *r20;
|
||||
IROLinear *constnd;
|
||||
Type *type20;
|
||||
ENode *enode;
|
||||
IROLinear *save;
|
||||
|
||||
flag = 0;
|
||||
counter = 0;
|
||||
LoopNode = fnode;
|
||||
FindMustReach();
|
||||
|
||||
for (var = IRO_FirstVar; var; var = var->next)
|
||||
var->xA = 1;
|
||||
|
||||
ComputeLoopKills();
|
||||
ComputeLoopInvariance();
|
||||
ComputeLoopInduction();
|
||||
|
||||
LoopNode = fnode;
|
||||
ConditionalHeaderAtBottom = 0;
|
||||
|
||||
bestpred = NULL;
|
||||
flag2 = 0;
|
||||
for (i = 0; i < LoopNode->numpred; i++) {
|
||||
pred = IRO_NodeTable[LoopNode->pred[i]];
|
||||
if (!Bv_IsBitSet(pred->index, InLoop)) {
|
||||
flag2 = 1;
|
||||
if (pred->nextnode == fnode) {
|
||||
#line 173
|
||||
CError_ASSERT(!bestpred || pred == bestpred);
|
||||
bestpred = pred;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!flag2) {
|
||||
IRO_Dump("No predecessor outside the loop\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bestsucc = NULL;
|
||||
for (i = 0; i < LoopNode->numsucc; i++) {
|
||||
succ = IRO_NodeTable[LoopNode->succ[i]];
|
||||
if (Bv_IsBitSet(succ->index, InLoop)) {
|
||||
bestsucc = succ;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
if (LoopNode == bestsucc && counter == 1)
|
||||
flag = 1;
|
||||
|
||||
if (LoopNode->last->type != IROLinearIf || LoopNode->last->type != IROLinearIfNot || flag) {
|
||||
counter2 = 0;
|
||||
for (j = 0; j < LoopNode->numpred; j++) {
|
||||
if (Bv_IsBitSet(IRO_NodeTable[LoopNode->pred[j]]->index, InLoop)) {
|
||||
r21 = IRO_NodeTable[LoopNode->pred[j]];
|
||||
counter2++;
|
||||
}
|
||||
}
|
||||
|
||||
r24 = NULL;
|
||||
counter3 = 0;
|
||||
for (j = 0; j < LoopNode->numpred; j++) {
|
||||
if (!Bv_IsBitSet(IRO_NodeTable[LoopNode->pred[j]]->index, InLoop)) {
|
||||
r24 = IRO_NodeTable[LoopNode->pred[j]];
|
||||
counter3++;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter2 == 1 && counter3 == 1) {
|
||||
if (r21->last->type == IROLinearIf) {
|
||||
if ((Bv_IsBitSet(LoopNode->nextnode->index, InLoop) && !Bv_IsBitSet(r21->nextnode->index, InLoop)) || flag) {
|
||||
IRO_Dump("Standard while loop layout\n");
|
||||
loop = ExtractLoopInfo(r21);
|
||||
if (flag)
|
||||
loop->flags |= LoopFlags_20000;
|
||||
FindAssignmenttoInductionVar(loop, r24);
|
||||
r20 = r24;
|
||||
while (r20 && !loop->nd14 && r20->numpred == 1 && IRO_NodeTable[r20->pred[0]]->numsucc == 1) {
|
||||
FindAssignmenttoInductionVar(loop, IRO_NodeTable[r20->pred[0]]);
|
||||
r20 = IRO_NodeTable[r20->pred[0]];
|
||||
}
|
||||
|
||||
if (CanRemoveRedundantLoop(loop)) {
|
||||
IRO_Dump("EmptyLoop: # of iterations =%ld, FinalStoreVal=%ld\n", CInt64_GetULong(&loop->x28), CInt64_GetULong(&loop->x30));
|
||||
IRO_NopOut(r21->last->u.label.x4);
|
||||
r21->last->type = IROLinearNop;
|
||||
type20 = loop->induction->nd->rtype;
|
||||
constnd = IRO_NewLinear(IROLinearOperand);
|
||||
constnd->index = ++IRO_NumLinear;
|
||||
enode = IRO_NewENode(EINTCONST);
|
||||
enode->rtype = type20;
|
||||
enode->data.intval = loop->x30;
|
||||
constnd->u.node = enode;
|
||||
constnd->rtype = type20;
|
||||
|
||||
if (loop->induction->nd->type == IROLinearOp1Arg) {
|
||||
save = loop->induction->nd->u.monadic;
|
||||
loop->induction->nd->type = IROLinearOp2Arg;
|
||||
loop->induction->nd->nodetype = EASS;
|
||||
loop->induction->nd->u.diadic.left = save;
|
||||
loop->induction->nd->u.diadic.right = constnd;
|
||||
IRO_Paste(constnd, constnd, loop->induction->nd);
|
||||
} else if (loop->induction->nd->type == IROLinearOp2Arg) {
|
||||
loop->induction->nd->nodetype = EASS;
|
||||
IRO_NopOut(loop->induction->nd->u.diadic.right);
|
||||
loop->induction->nd->u.diadic.right = constnd;
|
||||
IRO_Paste(constnd, constnd, loop->induction->nd);
|
||||
}
|
||||
} else if (CanRemoveRedundantLoop1(loop)) {
|
||||
IRO_Dump("EmptyLoop: self recursive dowhile(--n ) loop\n");
|
||||
|
||||
r21->last->type = IROLinearNop;
|
||||
type20 = loop->induction->nd->rtype;
|
||||
constnd = IRO_NewLinear(IROLinearOperand);
|
||||
constnd->index = ++IRO_NumLinear;
|
||||
enode = IRO_NewENode(EINTCONST);
|
||||
enode->rtype = type20;
|
||||
enode->data.intval = cint64_zero;
|
||||
constnd->u.node = enode;
|
||||
constnd->rtype = type20;
|
||||
|
||||
save = loop->induction->nd->u.monadic;
|
||||
loop->induction->nd->type = IROLinearOp2Arg;
|
||||
loop->induction->nd->nodetype = EASS;
|
||||
loop->induction->nd->u.diadic.left = save;
|
||||
loop->induction->nd->u.diadic.right = constnd;
|
||||
IRO_Paste(constnd, constnd, loop->induction->nd);
|
||||
}
|
||||
} else {
|
||||
IRO_Dump("NonStandard while loop layout\n");
|
||||
}
|
||||
} else {
|
||||
IRO_Dump("NonStandard while loop layout\n");
|
||||
}
|
||||
} else {
|
||||
IRO_Dump("Cannot handle Do While Loop with multiple tails\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CanRemoveRedundantLoop(IROLoop *loop) {
|
||||
IROLinear *inner;
|
||||
|
||||
if (loop->flags & LoopFlags_10000) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because detection of dowhile(n--) loop not supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_LOOP_HAS_ASM) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_ASM \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_IFEXPR_NON_CANONICAL) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No due to LP_IFEXPR_NON_CANONICAL \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_LOOP_HAS_CALLS) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_CALLS \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_CNTRLFLOW \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_INDUCTION_NOT_FOUND) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No due to LP_INDUCTION_NOT_FOUND \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_HAS_MULTIPLE_INDUCTIONS) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No due to LP_HAS_MULTIPLE_INDUCTIONS \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(loop->flags & LoopFlags_200)) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because header does not follow induction update \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(loop->flags & LoopFlags_10000)) {
|
||||
inner = loop->nd18->u.diadic.right;
|
||||
if (!IRO_IsIntConstant(inner) && !(inner->flags & IROLF_LoopInvariant)) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because Loop Upper Bound is Variant in the loop\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!loop->nd14) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because there is no initialization of loop index in PreHeader\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IRO_IsVariable(loop->nd14->u.diadic.left)) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction stored thru pointer\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IRO_IsUnsignedType(loop->nd14->rtype)) {
|
||||
if (IRO_IsIntConstant(loop->nd14->u.diadic.right)) {
|
||||
if (!CInt64_GreaterEqual(loop->nd14->u.diadic.right->u.node->data.intval, cint64_zero)) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction is signed but < 0\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction is signed and not constant\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(loop->flags & LP_LOOP_STEP_ISPOS) && !(loop->flags & LP_LOOP_STEP_ISNEG)) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because LP_LOOP_STEP_ISPOS/LP_LOOP_STEP_ISNEG is not set\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((loop->flags & LP_LOOP_STEP_ISPOS) && CheckStepOverFlow1_EmptyLoop(loop, &loop->x28, &loop->x30)) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because Final Value of indution will overflow\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((loop->flags & LP_LOOP_STEP_ISNEG) && CheckStepOverFlow2_EmptyLoop(loop, &loop->x28, &loop->x30)) {
|
||||
IRO_Dump("CanRemoveRedundantLoop:No because Final Value of indution will overflow\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return RedundantLoopCheck(loop) != 0;
|
||||
}
|
||||
|
||||
static int CanRemoveRedundantLoop1(IROLoop *loop) {
|
||||
if ((loop->flags & LoopFlags_10000) && (loop->flags & LoopFlags_20000)) {
|
||||
if (loop->flags & LP_LOOP_HAS_ASM) {
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_ASM \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_IFEXPR_NON_CANONICAL) {
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No due to LP_IFEXPR_NON_CANONICAL \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_LOOP_HAS_CALLS) {
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_CALLS \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) {
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_CNTRLFLOW \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_INDUCTION_NOT_FOUND) {
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No due to LP_INDUCTION_NOT_FOUND \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_HAS_MULTIPLE_INDUCTIONS) {
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No due to LP_HAS_MULTIPLE_INDUCTIONS \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) {
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(loop->flags & LoopFlags_200)) {
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No because header does not follow induction update \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loop->induction->nd->type == IROLinearOp1Arg && loop->induction->nd->nodetype == EPREDEC) {
|
||||
if (IRO_IsUnsignedType(loop->induction->nd->rtype))
|
||||
return 1;
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No because induction not of the right type \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
IRO_Dump("CanRemoveRedundantLoop1:No because induction operator not a predec \n");
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int RedundantLoopCheck(IROLoop *loop) {
|
||||
IRONode *fnode;
|
||||
IROLinear *nd;
|
||||
|
||||
for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
|
||||
if (Bv_IsBitSet(fnode->index, InLoop) && fnode != loop->fnode && (nd = fnode->first)) {
|
||||
while (1) {
|
||||
if ((nd->index < loop->index20 || nd->index > loop->index24) && nd->type != IROLinearNop && nd->type != IROLinearLabel) {
|
||||
if (IS_LINEAR_DIADIC(nd, EASS)) {
|
||||
if (!(nd->flags & IROLF_Reffed)) {
|
||||
if (IS_LINEAR_MONADIC(nd->u.diadic.left, EINDIRECT)) {
|
||||
if (nd->u.diadic.left->rtype && CParser_IsVolatile(nd->u.diadic.left->rtype, nd->u.diadic.left->nodeflags & ENODE_FLAG_QUALS)) {
|
||||
IRO_Dump(" EASS at %d fail as store to volatile memory \n", nd->index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((nd->u.diadic.left->u.monadic->flags & IROLF_LoopInvariant) && (nd->u.diadic.right->flags & IROLF_LoopInvariant)) {
|
||||
IRO_Dump(" EASS at %d pass\n", nd->index);
|
||||
} else {
|
||||
IRO_Dump(" EASS at %d fail, either LHS address or RHS is variant \n", nd->index);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
IRO_Dump("Found EASS nodes whose lhs root is not a EINDIRECT node\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
IRO_Dump("Found EASS node that is referenced i.e embedded assignment\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!(nd->flags & IROLF_Reffed)) {
|
||||
IRO_Dump("Found non EASS top level node in the loop\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nd == fnode->last)
|
||||
break;
|
||||
nd = nd->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int CheckStepOverFlow1_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2) {
|
||||
Boolean isUnsigned;
|
||||
IROLinear *nd2;
|
||||
IROLinear *nd1;
|
||||
CInt64 nd2value;
|
||||
CInt64 nd1value;
|
||||
CInt64 addConst;
|
||||
CInt64 work;
|
||||
CInt64 neg1;
|
||||
|
||||
nd2 = loop->nd14->u.diadic.right;
|
||||
nd1 = loop->nd18->u.diadic.right;
|
||||
isUnsigned = IRO_IsUnsignedType(loop->nd18->u.diadic.right->rtype);
|
||||
|
||||
if (IRO_IsIntConstant(nd2) && IRO_IsIntConstant(nd1)) {
|
||||
nd2value = nd2->u.node->data.intval;
|
||||
nd1value = nd1->u.node->data.intval;
|
||||
if (isUnsigned) {
|
||||
if (CInt64_LessEqualU(nd1value, nd2value))
|
||||
return 1;
|
||||
} else {
|
||||
if (CInt64_LessEqual(nd1value, nd2value))
|
||||
return 1;
|
||||
}
|
||||
|
||||
CInt64_SetLong(&addConst, loop->induction->addConst);
|
||||
CInt64_SetLong(&neg1, -1);
|
||||
*val1 = CInt64_Sub(nd1value, nd2value);
|
||||
*val1 = CInt64_Add(*val1, addConst);
|
||||
if (IS_LINEAR_DIADIC(loop->nd18, ELESS))
|
||||
*val1 = CInt64_Add(*val1, neg1);
|
||||
|
||||
#line 855
|
||||
CError_ASSERT(!CInt64_IsZero(&addConst));
|
||||
|
||||
if (isUnsigned)
|
||||
*val1 = CInt64_DivU(*val1, addConst);
|
||||
else
|
||||
*val1 = CInt64_Div(*val1, addConst);
|
||||
|
||||
if (CInt64_Equal(*val1, cint64_zero))
|
||||
return 1;
|
||||
|
||||
if (isUnsigned) {
|
||||
if (CInt64_LessEqualU(*val1, cint64_zero)) {
|
||||
#line 877
|
||||
CError_FATAL();
|
||||
}
|
||||
} else {
|
||||
if (CInt64_LessEqual(*val1, cint64_zero)) {
|
||||
#line 886
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
if (isUnsigned) {
|
||||
*val2 = CInt64_MulU(*val1, addConst);
|
||||
*val2 = CInt64_Add(*val2, nd2value);
|
||||
} else {
|
||||
*val2 = CInt64_Mul(*val1, addConst);
|
||||
*val2 = CInt64_Add(*val2, nd2value);
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CInt64_SetLong(&addConst, loop->induction->addConst);
|
||||
work = CInt64_Add(nd1value, addConst);
|
||||
|
||||
if (isUnsigned) {
|
||||
if (CInt64_LessU(work, nd1value))
|
||||
return 1;
|
||||
} else {
|
||||
if (CInt64_Less(work, nd1value))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CheckStepOverFlow2_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2) {
|
||||
Boolean isUnsigned;
|
||||
IROLinear *nd2;
|
||||
IROLinear *nd1;
|
||||
CInt64 nd2value;
|
||||
CInt64 nd1value;
|
||||
CInt64 addConst;
|
||||
CInt64 work;
|
||||
CInt64 neg1;
|
||||
|
||||
nd1 = loop->nd14->u.diadic.right;
|
||||
nd2 = loop->nd18->u.diadic.right;
|
||||
isUnsigned = IRO_IsUnsignedType(loop->nd18->u.diadic.right->rtype);
|
||||
|
||||
if (IRO_IsIntConstant(nd2) && IRO_IsIntConstant(nd1)) {
|
||||
nd2value = nd2->u.node->data.intval;
|
||||
nd1value = nd1->u.node->data.intval;
|
||||
if (isUnsigned) {
|
||||
if (CInt64_LessEqualU(nd1value, nd2value))
|
||||
return 1;
|
||||
} else {
|
||||
if (CInt64_LessEqual(nd1value, nd2value))
|
||||
return 1;
|
||||
}
|
||||
|
||||
CInt64_SetLong(&addConst, loop->induction->addConst);
|
||||
CInt64_SetLong(&neg1, -1);
|
||||
*val1 = CInt64_Sub(nd1value, nd2value);
|
||||
*val1 = CInt64_Add(*val1, addConst);
|
||||
if (IS_LINEAR_DIADIC(loop->nd18, EGREATER))
|
||||
*val1 = CInt64_Add(*val1, neg1);
|
||||
|
||||
#line 995
|
||||
CError_ASSERT(!CInt64_IsZero(&addConst));
|
||||
|
||||
if (isUnsigned)
|
||||
*val1 = CInt64_DivU(*val1, addConst);
|
||||
else
|
||||
*val1 = CInt64_Div(*val1, addConst);
|
||||
|
||||
if (CInt64_Equal(*val1, cint64_zero))
|
||||
return 1;
|
||||
|
||||
if (isUnsigned) {
|
||||
if (CInt64_LessEqualU(*val1, cint64_zero))
|
||||
return 0;
|
||||
} else {
|
||||
if (CInt64_LessEqual(*val1, cint64_zero))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isUnsigned) {
|
||||
*val2 = CInt64_MulU(*val1, addConst);
|
||||
*val2 = CInt64_Sub(nd1value, *val2);
|
||||
} else {
|
||||
*val2 = CInt64_Mul(*val1, addConst);
|
||||
*val2 = CInt64_Sub(nd1value, *val2);
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CInt64_SetLong(&addConst, loop->induction->addConst);
|
||||
work = CInt64_Sub(nd2value, addConst);
|
||||
|
||||
if (isUnsigned) {
|
||||
if (CInt64_GreaterU(work, nd2value))
|
||||
return 1;
|
||||
} else {
|
||||
if (CInt64_Greater(work, nd1value))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,336 @@
|
||||
#include "compiler/IroFlowgraph.h"
|
||||
#include "compiler/IroCSE.h"
|
||||
#include "compiler/IroLinearForm.h"
|
||||
#include "compiler/IroPropagate.h"
|
||||
#include "compiler/IROUseDef.h"
|
||||
#include "compiler/IroUtil.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CFunc.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/Exceptions.h"
|
||||
#include "compiler/InlineAsmPPC.h"
|
||||
|
||||
UInt16 IRO_NumNodes;
|
||||
IRONode *IRO_FirstNode;
|
||||
IRONode *IRO_LastNode;
|
||||
IRONode *IRO_EndNode;
|
||||
IRONode **IRO_NodeTable;
|
||||
BitVector *IRO_VarKills;
|
||||
BitVector *IRO_Avail;
|
||||
BitVector *IRO_FuncKills;
|
||||
BitVector *IRO_ExprKills;
|
||||
|
||||
static IRONode *StartNode(IROLinear *linear) {
|
||||
IRONode *node = oalloc(sizeof(IRONode));
|
||||
|
||||
node->index = IRO_NumNodes;
|
||||
node->numsucc = 0;
|
||||
node->succ = NULL;
|
||||
node->numpred = 0;
|
||||
node->pred = NULL;
|
||||
node->first = linear;
|
||||
node->last = linear;
|
||||
node->x16 = NULL;
|
||||
node->x1A = NULL;
|
||||
node->x1E = NULL;
|
||||
node->x22 = NULL;
|
||||
node->x26 = 0;
|
||||
node->x2A = NULL;
|
||||
node->dom = NULL;
|
||||
node->nextnode = NULL;
|
||||
node->x36 = 0;
|
||||
node->x37 = 0;
|
||||
node->mustreach = 0;
|
||||
node->x39 = 0;
|
||||
node->loopdepth = 0;
|
||||
node->x3C = 0;
|
||||
node->addressed = NULL;
|
||||
|
||||
IRO_NumNodes++;
|
||||
if (!IRO_FirstNode)
|
||||
IRO_FirstNode = node;
|
||||
else
|
||||
IRO_LastNode->nextnode = node;
|
||||
IRO_LastNode = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void AddSucc(IRONode *a, IRONode *b) {
|
||||
a->succ[a->numsucc++] = b->index;
|
||||
b->numpred++;
|
||||
}
|
||||
|
||||
static void AddLabelSucc(IRONode *node, CLabel *label) {
|
||||
IRONode *targetnode = (IRONode *) label->stmt;
|
||||
if (targetnode) {
|
||||
AddSucc(node, targetnode);
|
||||
targetnode->x39 = 1;
|
||||
} else {
|
||||
#line 126
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
static void AddSwitchSucc(IRONode *node) {
|
||||
SwitchInfo *info = node->last->u.swtch.info;
|
||||
SwitchCase *curcase = info->cases;
|
||||
SInt32 i = 1;
|
||||
|
||||
while (curcase) {
|
||||
curcase = curcase->next;
|
||||
i++;
|
||||
}
|
||||
|
||||
node->succ = oalloc(sizeof(UInt16) * i);
|
||||
for (curcase = info->cases; curcase; curcase = curcase->next)
|
||||
AddLabelSucc(node, curcase->label);
|
||||
AddLabelSucc(node, info->defaultlabel);
|
||||
}
|
||||
|
||||
static void AddPred(UInt32 a, UInt16 b) {
|
||||
IRONode *node = IRO_NodeTable[a];
|
||||
node->pred[node->numpred++] = b;
|
||||
}
|
||||
|
||||
void IRO_ComputeSuccPred(void) {
|
||||
CLabel *label;
|
||||
IRONode *node;
|
||||
SInt32 count;
|
||||
IROLinear *linear;
|
||||
ExceptionAction *action;
|
||||
IAEffects effects;
|
||||
UInt16 i;
|
||||
|
||||
for (label = Labels; label; label = label->next)
|
||||
label->stmt = NULL;
|
||||
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
node->x39 = 0;
|
||||
node->numsucc = 0;
|
||||
node->numpred = 0;
|
||||
node->x36 = 0;
|
||||
node->x37 = 0;
|
||||
if (node->first && node->first->type == IROLinearLabel)
|
||||
node->first->u.label.label->stmt = (Statement *) node;
|
||||
}
|
||||
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (!node->first) {
|
||||
if (node->nextnode) {
|
||||
node->succ = oalloc(sizeof(UInt16));
|
||||
AddSucc(node, node->nextnode);
|
||||
}
|
||||
} else {
|
||||
linear = node->last;
|
||||
next_linear:
|
||||
switch (linear->type) {
|
||||
case IROLinearReturn:
|
||||
case IROLinearEnd:
|
||||
break;
|
||||
case IROLinearGoto:
|
||||
node->succ = oalloc(sizeof(UInt16));
|
||||
AddLabelSucc(node, linear->u.label.label);
|
||||
break;
|
||||
case IROLinearIf:
|
||||
case IROLinearIfNot:
|
||||
node->succ = oalloc(sizeof(UInt16) * 2);
|
||||
AddSucc(node, node->nextnode);
|
||||
AddLabelSucc(node, linear->u.label.label);
|
||||
break;
|
||||
case IROLinearSwitch:
|
||||
AddSwitchSucc(node);
|
||||
break;
|
||||
case IROLinearFunccall:
|
||||
count = 1;
|
||||
if (IRO_FunctionCallMightThrowException(linear)) {
|
||||
for (action = linear->stmt->dobjstack; action; action = action->prev) {
|
||||
if (action->type == EAT_CATCHBLOCK || action->type == EAT_SPECIFICATION)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
node->succ = oalloc(sizeof(UInt16) * count);
|
||||
AddSucc(node, node->nextnode);
|
||||
if (IRO_FunctionCallMightThrowException(linear)) {
|
||||
for (action = linear->stmt->dobjstack; action; action = action->prev) {
|
||||
if (action->type == EAT_CATCHBLOCK)
|
||||
AddLabelSucc(node, action->data.catch_block.catch_label);
|
||||
else if (action->type == EAT_SPECIFICATION)
|
||||
AddLabelSucc(node, action->data.specification.unexp_label);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IROLinearAsm:
|
||||
CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
|
||||
node->succ = oalloc(sizeof(UInt16) * (!effects.x5 + effects.numlabels));
|
||||
if (!effects.x5)
|
||||
AddSucc(node, node->nextnode);
|
||||
for (i = 0; i < effects.numlabels; i++)
|
||||
AddLabelSucc(node, effects.labels[i]);
|
||||
break;
|
||||
case IROLinearOp2Arg:
|
||||
if (linear->nodetype == ECOMMA) {
|
||||
linear = linear->u.diadic.right;
|
||||
goto next_linear;
|
||||
}
|
||||
default:
|
||||
if (node->nextnode) {
|
||||
node->succ = oalloc(sizeof(UInt16));
|
||||
AddSucc(node, node->nextnode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (node->numpred)
|
||||
node->pred = oalloc(sizeof(UInt16) * node->numpred);
|
||||
else
|
||||
node->pred = NULL;
|
||||
node->numpred = 0;
|
||||
}
|
||||
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
for (i = 0; i < node->numsucc; i++)
|
||||
AddPred(node->succ[i], node->index);
|
||||
}
|
||||
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (node->first && node->first->type == IROLinearLabel) {
|
||||
IROLinear *linear = node->first;
|
||||
do {
|
||||
if (linear->type == IROLinearBeginCatch || linear->type == IROLinearEndCatch || linear->type == IROLinearEndCatchDtor) {
|
||||
node->x39 = 1;
|
||||
break;
|
||||
}
|
||||
} while (linear != node->last && (linear = linear->next));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_ComputeDom(void) {
|
||||
IRONode *node;
|
||||
BitVector *bv;
|
||||
SInt32 i;
|
||||
int repeat;
|
||||
|
||||
Bv_AllocVector(&IRO_FirstNode->dom, IRO_NumNodes);
|
||||
Bv_SetBit(IRO_FirstNode->index, IRO_FirstNode->dom);
|
||||
for (node = IRO_FirstNode->nextnode; node; node = node->nextnode) {
|
||||
Bv_AllocVector(&node->dom, IRO_NumNodes);
|
||||
Bv_Set(node->dom);
|
||||
}
|
||||
|
||||
Bv_AllocVector(&bv, IRO_NumNodes);
|
||||
|
||||
do {
|
||||
repeat = 0;
|
||||
for (node = IRO_FirstNode->nextnode; node; node = node->nextnode) {
|
||||
if (node->numpred) {
|
||||
Bv_Set(bv);
|
||||
for (i = 0; i < node->numpred; i++) {
|
||||
Bv_And(IRO_NodeTable[node->pred[i]]->dom, bv);
|
||||
}
|
||||
Bv_SetBit(node->index, bv);
|
||||
} else {
|
||||
Bv_Clear(bv);
|
||||
Bv_SetBit(node->index, bv);
|
||||
}
|
||||
|
||||
if (!Bv_Compare(bv, node->dom)) {
|
||||
Bv_Copy(bv, node->dom);
|
||||
repeat = 1;
|
||||
}
|
||||
}
|
||||
} while (repeat);
|
||||
}
|
||||
|
||||
void IRO_BuildFlowgraph(IROLinear *linear) {
|
||||
IROLinear *scan;
|
||||
CLabel *label;
|
||||
ExceptionAction *action;
|
||||
IAEffects effects;
|
||||
IRONode *node;
|
||||
SInt32 i;
|
||||
int flag;
|
||||
|
||||
for (label = Labels; label; label = label->next)
|
||||
label->stmt = NULL;
|
||||
|
||||
scan = linear;
|
||||
IRO_NumNodes = 0;
|
||||
IRO_FirstNode = IRO_LastNode = IRO_EndNode = NULL;
|
||||
while (scan) {
|
||||
StartNode(scan);
|
||||
if (scan->type == IROLinearLabel)
|
||||
scan->u.label.label->stmt = (Statement *) IRO_LastNode;
|
||||
|
||||
flag = 0;
|
||||
while (!flag && scan->next && !(scan->next->flags & IROLF_1)) {
|
||||
switch (scan->type) {
|
||||
case IROLinearGoto:
|
||||
case IROLinearReturn:
|
||||
case IROLinearEntry:
|
||||
case IROLinearExit:
|
||||
case IROLinearEnd:
|
||||
flag = 1;
|
||||
break;
|
||||
case IROLinearIf:
|
||||
case IROLinearIfNot:
|
||||
case IROLinearSwitch:
|
||||
flag = 1;
|
||||
skip:
|
||||
if (scan->next->type == IROLinearLabel) {
|
||||
IROLinear *nw = IRO_NewLinear(IROLinearNop);
|
||||
nw->index = ++IRO_NumLinear;
|
||||
nw->next = scan->next;
|
||||
scan->next = nw;
|
||||
}
|
||||
break;
|
||||
case IROLinearFunccall:
|
||||
if (IRO_FunctionCallMightThrowException(scan)) {
|
||||
for (action = scan->stmt->dobjstack; action; action = action->prev) {
|
||||
if (action->type == EAT_CATCHBLOCK || action->type == EAT_SPECIFICATION) {
|
||||
flag = 1;
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IROLinearAsm:
|
||||
CodeGen_GetAsmEffects(scan->u.asm_stmt, &effects);
|
||||
if (effects.numlabels)
|
||||
flag = 1;
|
||||
break;
|
||||
}
|
||||
if (!flag)
|
||||
scan = scan->next;
|
||||
}
|
||||
|
||||
if (scan->type == IROLinearEnd)
|
||||
IRO_EndNode = IRO_LastNode;
|
||||
IRO_LastNode->last = scan;
|
||||
scan = scan->next;
|
||||
}
|
||||
|
||||
IRO_NodeTable = oalloc(IRO_NumNodes * sizeof(IRONode *));
|
||||
memset(IRO_NodeTable, 0, IRO_NumNodes * sizeof(IRONode *));
|
||||
for (node = IRO_FirstNode, i = 0; node; node = node->nextnode)
|
||||
IRO_NodeTable[i++] = node;
|
||||
|
||||
IRO_ComputeSuccPred();
|
||||
IRO_ComputeDom();
|
||||
IRO_CheckForUserBreak();
|
||||
}
|
||||
|
||||
IRONode *IRO_NewFlowGraphNode(void) {
|
||||
IRONode *node = oalloc(sizeof(IRONode));
|
||||
memset(node, 0, sizeof(IRONode));
|
||||
node->index = IRO_NumNodes;
|
||||
IRO_NumNodes++;
|
||||
node->nextnode = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
IRONode *IRO_MergeFlowGraphNodes(IRONode *a, IRONode *b) {
|
||||
// TODO
|
||||
}
|
@ -0,0 +1,267 @@
|
||||
#include "compiler/IroJump.h"
|
||||
#include "compiler/IroDump.h"
|
||||
#include "compiler/IroFlowgraph.h"
|
||||
#include "compiler/IroLinearForm.h"
|
||||
#include "compiler/IroUtil.h"
|
||||
#include "compiler/CFunc.h"
|
||||
#include "compiler/Exceptions.h"
|
||||
|
||||
static Boolean CheckChain(CLabel **labelptr) {
|
||||
IRONode *node;
|
||||
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (node->first && node->first->type == IROLinearLabel && node->first->u.label.label == *labelptr) {
|
||||
IROLinear *linear;
|
||||
CLabel *lab;
|
||||
for (linear = node->first->next, lab = NULL; linear && (linear->type == IROLinearLabel || linear->type == IROLinearNop); linear = linear->next) {
|
||||
if (linear->type == IROLinearLabel)
|
||||
lab = linear->u.label.label;
|
||||
}
|
||||
|
||||
if (linear->type == IROLinearGoto && *labelptr != linear->u.label.label) {
|
||||
*labelptr = linear->u.label.label;
|
||||
IRO_Dump("Chaining goto at %d\n", linear->index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lab && *labelptr != lab)
|
||||
*labelptr = lab;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Boolean IRO_DoJumpChaining(void) {
|
||||
IRONode *node;
|
||||
IROLinear *linear;
|
||||
Boolean flag;
|
||||
SwitchInfo *info;
|
||||
SwitchCase *curcase;
|
||||
Boolean result;
|
||||
|
||||
result = 0;
|
||||
do {
|
||||
flag = 0;
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (node->first) {
|
||||
linear = node->last;
|
||||
switch (linear->type) {
|
||||
case IROLinearGoto:
|
||||
if (CheckChain(&linear->u.label.label))
|
||||
flag = 1;
|
||||
break;
|
||||
case IROLinearIf:
|
||||
case IROLinearIfNot:
|
||||
if (CheckChain(&linear->u.label.label))
|
||||
flag = 1;
|
||||
break;
|
||||
case IROLinearSwitch:
|
||||
info = linear->u.swtch.info;
|
||||
for (curcase = info->cases; curcase; curcase = curcase->next) {
|
||||
if (CheckChain(&curcase->label))
|
||||
flag = 1;
|
||||
}
|
||||
if (CheckChain(&info->defaultlabel))
|
||||
flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
result |= flag;
|
||||
IRO_CheckForUserBreak();
|
||||
} while (flag);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IRO_MakeReachable(IRONode *node) {
|
||||
UInt16 i;
|
||||
Boolean flag;
|
||||
|
||||
node->x36 = 1;
|
||||
do {
|
||||
flag = 0;
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (node->x36 && !node->x37) {
|
||||
for (i = 0; i < node->numsucc; i++) {
|
||||
if (!IRO_NodeTable[node->succ[i]]->x36) {
|
||||
flag = 1;
|
||||
IRO_NodeTable[node->succ[i]]->x36 = 1;
|
||||
}
|
||||
}
|
||||
node->x37 = 1;
|
||||
}
|
||||
}
|
||||
} while (flag);
|
||||
}
|
||||
|
||||
Boolean IRO_RemoveUnreachable(void) {
|
||||
IRONode *node2;
|
||||
IRONode *node1;
|
||||
IROLinear *scan;
|
||||
IROLinear *linear;
|
||||
Boolean result;
|
||||
ExceptionAction **actptr;
|
||||
ExceptionAction *act;
|
||||
|
||||
result = 0;
|
||||
IRO_ComputeSuccPred();
|
||||
IRO_MakeReachable(IRO_FirstNode);
|
||||
node1 = IRO_FirstNode;
|
||||
for (node2 = IRO_FirstNode->nextnode; node2; node2 = node2->nextnode) {
|
||||
if (node2->first && !node2->x36) {
|
||||
IRO_Dump("Removing unreachable code at: %d\n", node2->index);
|
||||
node1->nextnode = node2->nextnode;
|
||||
node1->last->next = node2->last->next;
|
||||
result = 1;
|
||||
for (linear = node2->first; linear && linear->type == IROLinearLabel && linear != node2->last->next; linear = linear->next) {
|
||||
for (scan = IRO_FirstLinear; scan; scan = scan->next) {
|
||||
if (scan->stmt)
|
||||
scan->stmt->marked = 0;
|
||||
}
|
||||
|
||||
for (scan = IRO_FirstLinear; scan; scan = scan->next) {
|
||||
if (scan->stmt && !scan->stmt->marked) {
|
||||
scan->stmt->marked = 1;
|
||||
for (actptr = &scan->stmt->dobjstack; (act = *actptr); actptr = &act->prev) {
|
||||
if (
|
||||
(act->type == EAT_CATCHBLOCK && act->data.catch_block.catch_label == linear->u.label.label) ||
|
||||
(act->type == EAT_SPECIFICATION && act->data.specification.unexp_label == linear->u.label.label)) {
|
||||
*actptr = act->prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node2 == IRO_LastNode)
|
||||
IRO_LastNode = node1;
|
||||
} else {
|
||||
node1 = node2;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
IRO_ComputeSuccPred();
|
||||
IRO_ComputeDom();
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
return result;
|
||||
}
|
||||
|
||||
Boolean IRO_RemoveRedundantJumps(void) {
|
||||
IRONode *node;
|
||||
IROLinear *linear;
|
||||
IROLinear *scan;
|
||||
IROLinear *scan2;
|
||||
SwitchInfo *info;
|
||||
SwitchCase *curcase;
|
||||
Boolean result;
|
||||
|
||||
result = 0;
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (node->first) {
|
||||
linear = node->last;
|
||||
switch (linear->type) {
|
||||
case IROLinearGoto:
|
||||
scan = linear->next;
|
||||
while (scan && ((scan->type == IROLinearNop) || (scan->type == IROLinearLabel && scan->u.label.label != linear->u.label.label)))
|
||||
scan = scan->next;
|
||||
while (1) {
|
||||
if (!scan) break;
|
||||
if (scan->type != IROLinearLabel) break;
|
||||
if (scan->u.label.label == linear->u.label.label) {
|
||||
IRO_Dump("Removing goto next at %d\n", linear->index);
|
||||
linear->type = IROLinearNop;
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
scan = scan->next;
|
||||
}
|
||||
break;
|
||||
|
||||
case IROLinearIf:
|
||||
case IROLinearIfNot:
|
||||
scan = linear->next;
|
||||
while (scan && scan->type == IROLinearNop)
|
||||
scan = scan->next;
|
||||
if (scan && scan->type == IROLinearGoto) {
|
||||
scan2 = scan->next;
|
||||
while (scan2 && ((scan2->type == IROLinearNop) || (scan2->type == IROLinearLabel && scan2->u.label.label != linear->u.label.label)))
|
||||
scan2 = scan2->next;
|
||||
|
||||
if (scan2 && scan2->type == IROLinearLabel && scan2->u.label.label == linear->u.label.label) {
|
||||
if (linear->type == IROLinearIf)
|
||||
linear->type = IROLinearIfNot;
|
||||
else
|
||||
linear->type = IROLinearIf;
|
||||
|
||||
linear->u.label.label = scan->u.label.label;
|
||||
scan->type = IROLinearNop;
|
||||
IRO_Dump("Removing branch around goto at %d\n", linear->index);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
scan2 = linear->next;
|
||||
while (scan2 && ((scan2->type == IROLinearNop) || (scan2->type == IROLinearLabel && scan2->u.label.label != linear->u.label.label)))
|
||||
scan2 = scan2->next;
|
||||
while (1) {
|
||||
if (!scan2) break;
|
||||
if (scan2->type != IROLinearLabel) break;
|
||||
if (scan2->u.label.label == linear->u.label.label) {
|
||||
IRO_Dump("Removing If/IfNot_Goto next at %d\n", linear->index);
|
||||
linear->type = IROLinearNop;
|
||||
IRO_CheckSideEffect(linear->u.label.x4);
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
scan2 = scan2->next;
|
||||
}
|
||||
break;
|
||||
|
||||
case IROLinearSwitch:
|
||||
info = linear->u.swtch.info;
|
||||
curcase = info->cases;
|
||||
while (curcase && curcase->label == info->defaultlabel)
|
||||
curcase = curcase->next;
|
||||
if (!curcase) {
|
||||
IRO_Dump("Removing Switch next at %d\n", linear->index);
|
||||
IRO_CheckSideEffect(linear->u.swtch.x4);
|
||||
linear->type = IROLinearGoto;
|
||||
linear->u.label.label = info->defaultlabel;
|
||||
result = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
IRO_ComputeSuccPred();
|
||||
IRO_ComputeDom();
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
return result;
|
||||
}
|
||||
|
||||
Boolean IRO_RemoveLabels(void) {
|
||||
Boolean result;
|
||||
IRONode *node;
|
||||
|
||||
result = 0;
|
||||
IRO_ComputeSuccPred();
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (node->first && node->first->type == IROLinearLabel && !node->x39) {
|
||||
node->first->type = IROLinearNop;
|
||||
node->first->flags &= ~IROLF_1;
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
return result;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,564 @@
|
||||
#include "compiler/IroMalloc.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
|
||||
#define FLAGMASK 0xF
|
||||
|
||||
typedef struct Block {
|
||||
struct Block *prev;
|
||||
struct Block *next;
|
||||
void *x8;
|
||||
void *xC;
|
||||
size_t remain;
|
||||
size_t x14;
|
||||
} Block;
|
||||
|
||||
typedef struct SubBlockBase {
|
||||
size_t x0;
|
||||
Block *block;
|
||||
} SubBlockBase;
|
||||
|
||||
typedef struct SubBlock {
|
||||
size_t x0;
|
||||
Block *block;
|
||||
struct SubBlock *x8;
|
||||
struct SubBlock *xC;
|
||||
} SubBlock;
|
||||
|
||||
typedef struct SubBlockTail {
|
||||
size_t x0copy;
|
||||
} SubBlockTail;
|
||||
|
||||
typedef struct BlockTail {
|
||||
size_t x14copy;
|
||||
SubBlock *unk;
|
||||
} BlockTail;
|
||||
|
||||
typedef struct FixStart {
|
||||
struct FixBlock *a;
|
||||
struct FixSubBlock *b;
|
||||
long count;
|
||||
} FixStart;
|
||||
|
||||
typedef struct FixBlock {
|
||||
struct FixBlock *prev;
|
||||
struct FixBlock *next;
|
||||
size_t entrysize;
|
||||
} FixBlock;
|
||||
|
||||
typedef struct FixSubBlockBase {
|
||||
FixBlock *fixblock;
|
||||
} FixSubBlockBase;
|
||||
|
||||
typedef struct FixSubBlock {
|
||||
FixBlock *fixblock;
|
||||
struct FixSubBlock *next;
|
||||
} FixSubBlock;
|
||||
|
||||
static const size_t fix_pool_sizes[] = {0xC, 0x1C, 0x2C, 0x4C};
|
||||
static Block *start_;
|
||||
static FixStart fix_start[4];
|
||||
static int initialized;
|
||||
|
||||
// forward decls
|
||||
static void Block_link(Block *block, SubBlock *subblock);
|
||||
static void Block_unlink(Block *block, SubBlock *subblock);
|
||||
static void SubBlock_construct(SubBlock *subblock, size_t size, Block *block, int flag1, int flag2);
|
||||
static SubBlock *SubBlock_split(SubBlock *subblock, size_t pos);
|
||||
static SubBlock *SubBlock_merge_prev(SubBlock *subblock, SubBlock **sbptr);
|
||||
static void SubBlock_merge_next(SubBlock *subblock, SubBlock **sbptr);
|
||||
|
||||
#define BLOCK_TAIL(block) ((BlockTail *) ((long) (block) + ((block)->x14 & ~FLAGMASK) - sizeof(BlockTail)))
|
||||
|
||||
#define BUF_LOCATOR(buf) (*((size_t *) ((long) (buf) - sizeof(size_t))))
|
||||
#define SBB_BLOCK(sbb) ((Block *) ((long) ((sbb)->block) & ~1))
|
||||
|
||||
#define BUF_IS_VAR(buf) (BUF_LOCATOR(buf) & 1)
|
||||
#define VARBUF_SBB(buf) ((SubBlockBase *) ((long) (buf) - sizeof(SubBlockBase)))
|
||||
#define VARBUF_SB(buf) ((SubBlock *) ((long) (buf) - sizeof(SubBlockBase)))
|
||||
#define VARBUF_BLOCKSIZE(buf) (VARBUF_SBB(buf)->x0 & ~FLAGMASK)
|
||||
#define VARBUF_SIZE(buf) (((VARBUF_SBB(buf)->x0 & ~FLAGMASK) - sizeof(SubBlockBase)))
|
||||
#define VARBUF_BLOCK(buf) SBB_BLOCK(VARBUF_SBB(buf))
|
||||
#define FIXBUF_SIZE(buf) (((FixBlock *) BUF_LOCATOR(buf))->entrysize)
|
||||
|
||||
#define BUF_SIZE(buf) BUF_IS_VAR(buf) ? VARBUF_SIZE(buf) : FIXBUF_SIZE(buf)
|
||||
|
||||
static void Block_construct(Block *block, size_t size) {
|
||||
SubBlock *subblock;
|
||||
|
||||
block->x14 = size | 3;
|
||||
((BlockTail *) ((long) block + size - sizeof(BlockTail)))->x14copy = block->x14;
|
||||
|
||||
subblock = (SubBlock *) (block + 1);
|
||||
SubBlock_construct(subblock, size - sizeof(Block) - sizeof(BlockTail), block, 0, 0);
|
||||
|
||||
block->remain = size - sizeof(Block) - sizeof(BlockTail);
|
||||
BLOCK_TAIL(block)->unk = NULL;
|
||||
|
||||
Block_link(block, subblock);
|
||||
}
|
||||
|
||||
static SubBlock *Block_subBlock(Block *block, size_t size) {
|
||||
SubBlock *subblock;
|
||||
size_t check;
|
||||
size_t best;
|
||||
|
||||
if (!BLOCK_TAIL(block)->unk)
|
||||
return NULL;
|
||||
|
||||
subblock = BLOCK_TAIL(block)->unk;
|
||||
best = subblock->x0 & ~FLAGMASK;
|
||||
check = subblock->x0 & ~FLAGMASK;
|
||||
while (check < size) {
|
||||
subblock = subblock->xC;
|
||||
check = subblock->x0 & ~FLAGMASK;
|
||||
if (best < check)
|
||||
best = check;
|
||||
if (subblock == BLOCK_TAIL(block)->unk) {
|
||||
block->remain = best;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((check - size) >= 0x60)
|
||||
SubBlock_split(subblock, size);
|
||||
|
||||
BLOCK_TAIL(block)->unk = subblock->xC;
|
||||
Block_unlink(block, subblock);
|
||||
return subblock;
|
||||
}
|
||||
|
||||
static void Block_link(Block *block, SubBlock *subblock) {
|
||||
size_t size;
|
||||
SubBlock **sbptr;
|
||||
|
||||
size = subblock->x0 & ~FLAGMASK;
|
||||
subblock->x0 &= ~2;
|
||||
((SubBlock *) ((long) subblock + size))->x0 &= ~4;
|
||||
((SubBlockTail *) ((long) subblock + size - sizeof(SubBlockTail)))->x0copy = size;
|
||||
|
||||
sbptr = &BLOCK_TAIL(block)->unk;
|
||||
if (*sbptr) {
|
||||
subblock->x8 = (*sbptr)->x8;
|
||||
subblock->x8->xC = subblock;
|
||||
subblock->xC = *sbptr;
|
||||
(*sbptr)->x8 = subblock;
|
||||
*sbptr = subblock;
|
||||
*sbptr = SubBlock_merge_prev(*sbptr, sbptr);
|
||||
SubBlock_merge_next(*sbptr, sbptr);
|
||||
} else {
|
||||
*sbptr = subblock;
|
||||
subblock->x8 = subblock;
|
||||
subblock->xC = subblock;
|
||||
}
|
||||
|
||||
if (block->remain < ((*sbptr)->x0 & ~FLAGMASK))
|
||||
block->remain = (*sbptr)->x0 & ~FLAGMASK;
|
||||
}
|
||||
|
||||
static void Block_unlink(Block *block, SubBlock *subblock) {
|
||||
size_t size;
|
||||
SubBlock **sbptr;
|
||||
|
||||
size = subblock->x0 & ~FLAGMASK;
|
||||
subblock->x0 |= 2;
|
||||
((SubBlock *) ((long) subblock + size))->x0 |= 4;
|
||||
|
||||
sbptr = &BLOCK_TAIL(block)->unk;
|
||||
if (*sbptr == subblock)
|
||||
*sbptr = subblock->xC;
|
||||
|
||||
if (*sbptr == subblock) {
|
||||
*sbptr = NULL;
|
||||
block->remain = 0;
|
||||
} else {
|
||||
subblock->xC->x8 = subblock->x8;
|
||||
subblock->x8->xC = subblock->xC;
|
||||
}
|
||||
}
|
||||
|
||||
static void SubBlock_construct(SubBlock *subblock, size_t size, Block *block, int flag1, int flag2) {
|
||||
subblock->block = (Block *) ((long) block | 1);
|
||||
subblock->x0 = size;
|
||||
if (flag1)
|
||||
subblock->x0 |= 4;
|
||||
if (flag2) {
|
||||
subblock->x0 |= 2;
|
||||
((SubBlock *) (((long) subblock) + size))->x0 |= 4;
|
||||
} else {
|
||||
((SubBlockTail *) (((long) subblock) + size - sizeof(SubBlockTail)))->x0copy = size;
|
||||
}
|
||||
}
|
||||
|
||||
static SubBlock *SubBlock_split(SubBlock *subblock, size_t pos) {
|
||||
size_t oldsize;
|
||||
int flag;
|
||||
SubBlock *splitright;
|
||||
Block *block;
|
||||
|
||||
oldsize = subblock->x0 & ~FLAGMASK;
|
||||
flag = !(subblock->x0 & 2);
|
||||
splitright = (SubBlock *) ((long) subblock + pos);
|
||||
block = (Block *) ((long) subblock->block & ~1);
|
||||
SubBlock_construct(subblock, pos, block, subblock->x0 & 4, !flag);
|
||||
SubBlock_construct(splitright, oldsize - pos, block, !flag, !flag);
|
||||
if (flag) {
|
||||
splitright->xC = subblock->xC;
|
||||
splitright->xC->x8 = splitright;
|
||||
splitright->x8 = subblock;
|
||||
subblock->xC = splitright;
|
||||
}
|
||||
|
||||
return splitright;
|
||||
}
|
||||
|
||||
static SubBlock *SubBlock_merge_prev(SubBlock *subblock, SubBlock **sbptr) {
|
||||
size_t prevsize;
|
||||
SubBlock *prevblock;
|
||||
|
||||
if (!(subblock->x0 & 4)) {
|
||||
prevsize = ((SubBlockTail *) ((long) subblock - sizeof(SubBlockTail)))->x0copy;
|
||||
if (prevsize & 2)
|
||||
return subblock;
|
||||
|
||||
prevblock = (SubBlock *) ((long) subblock - prevsize);
|
||||
prevblock->x0 = prevblock->x0 & FLAGMASK;
|
||||
prevblock->x0 |= (prevsize + (subblock->x0 & ~FLAGMASK)) & ~FLAGMASK;
|
||||
if (!(prevblock->x0 & 2))
|
||||
((SubBlockTail *) ((long) prevblock + prevsize + (subblock->x0 & ~FLAGMASK) - sizeof(SubBlockTail)))->x0copy = prevsize + (subblock->x0 & ~FLAGMASK);
|
||||
|
||||
if (*sbptr == subblock)
|
||||
*sbptr = (*sbptr)->xC;
|
||||
|
||||
subblock->xC->x8 = subblock->x8;
|
||||
subblock->xC->x8->xC = subblock->xC;
|
||||
return prevblock;
|
||||
}
|
||||
|
||||
return subblock;
|
||||
}
|
||||
|
||||
static void SubBlock_merge_next(SubBlock *subblock, SubBlock **sbptr) {
|
||||
SubBlock *nextblock;
|
||||
size_t nextsize;
|
||||
|
||||
nextblock = (SubBlock *) ((long) subblock + (subblock->x0 & ~FLAGMASK));
|
||||
if (!(nextblock->x0 & 2)) {
|
||||
nextsize = (subblock->x0 & ~FLAGMASK) + (nextblock->x0 & ~FLAGMASK);
|
||||
subblock->x0 = subblock->x0 & FLAGMASK;
|
||||
subblock->x0 |= nextsize & ~FLAGMASK;
|
||||
|
||||
if (!(subblock->x0 & 2))
|
||||
((SubBlockTail *) ((long) subblock + nextsize - sizeof(SubBlockTail)))->x0copy = nextsize;
|
||||
|
||||
if (!(subblock->x0 & 2))
|
||||
((SubBlock *) ((long) subblock + nextsize))->x0 &= ~4;
|
||||
else
|
||||
((SubBlock *) ((long) subblock + nextsize))->x0 |= 4;
|
||||
|
||||
if (*sbptr == nextblock)
|
||||
*sbptr = (*sbptr)->xC;
|
||||
if (*sbptr == nextblock)
|
||||
*sbptr = NULL;
|
||||
|
||||
nextblock->xC->x8 = nextblock->x8;
|
||||
nextblock->x8->xC = nextblock->xC;
|
||||
}
|
||||
}
|
||||
|
||||
static void link_block(Block *block) {
|
||||
if (start_) {
|
||||
block->prev = start_->prev;
|
||||
block->prev->next = block;
|
||||
block->next = start_;
|
||||
|
||||
start_->prev = block;
|
||||
start_ = block;
|
||||
} else {
|
||||
start_ = block;
|
||||
block->prev = block;
|
||||
block->next = block;
|
||||
}
|
||||
}
|
||||
|
||||
static Block *unlink_block(Block *block) {
|
||||
Block *newblock;
|
||||
|
||||
newblock = block->next;
|
||||
if (newblock == block)
|
||||
newblock = NULL;
|
||||
|
||||
if (start_ == block)
|
||||
start_ = newblock;
|
||||
|
||||
if (newblock) {
|
||||
newblock->prev = block->prev;
|
||||
newblock->prev->next = newblock;
|
||||
}
|
||||
|
||||
block->prev = block->next = NULL;
|
||||
return newblock;
|
||||
}
|
||||
|
||||
static Block *link_new_block(size_t size) {
|
||||
Block *block;
|
||||
|
||||
size = (size + 0x1000 + sizeof(Block) + sizeof(BlockTail) - 1) & ~0xFFF;
|
||||
if (size < 0x10000)
|
||||
size = 0x10000;
|
||||
|
||||
if (!(block = galloc(size)))
|
||||
return NULL;
|
||||
|
||||
Block_construct(block, size);
|
||||
link_block(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
static void *allocate_from_var_pools(size_t size) {
|
||||
Block *block;
|
||||
SubBlock *subblock;
|
||||
|
||||
size = (size + sizeof(Block) - 1) & ~0xF;
|
||||
if (size < 0x60)
|
||||
size = 0x60;
|
||||
|
||||
block = start_ ? start_ : link_new_block(size);
|
||||
if (!block)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
if (size <= block->remain) {
|
||||
if ((subblock = Block_subBlock(block, size))) {
|
||||
start_ = block;
|
||||
goto allocated;
|
||||
}
|
||||
}
|
||||
} while ((block = block->next) != start_);
|
||||
|
||||
block = link_new_block(size);
|
||||
if (!block)
|
||||
return NULL;
|
||||
subblock = Block_subBlock(block, size);
|
||||
allocated:
|
||||
return (SubBlockBase *) subblock + 1;
|
||||
}
|
||||
|
||||
static void deallocate_from_var_pools(void *buf) {
|
||||
Block *block;
|
||||
SubBlock *subblock;
|
||||
int flag;
|
||||
|
||||
subblock = (SubBlock *) ((long) buf - sizeof(SubBlockBase));
|
||||
block = (Block *) ((long) subblock->block & ~1);
|
||||
Block_link(block, subblock);
|
||||
|
||||
flag = 0;
|
||||
subblock = (SubBlock *) (block + 1);
|
||||
if (!(subblock->x0 & 2)) {
|
||||
if ((subblock->x0 & ~FLAGMASK) == ((block->x14 & ~FLAGMASK) - sizeof(Block) - sizeof(BlockTail)))
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
unlink_block(block);
|
||||
}
|
||||
|
||||
static void FixBlock_construct(FixBlock *fixblock, FixBlock *prev, FixBlock *next, int poolIndex, void *buffer, size_t buffersize) {
|
||||
size_t entrysize;
|
||||
size_t entrycount;
|
||||
size_t i;
|
||||
FixSubBlock *fsb;
|
||||
FixSubBlock *fsbnext;
|
||||
|
||||
fixblock->prev = prev;
|
||||
fixblock->next = next;
|
||||
fixblock->entrysize = fix_pool_sizes[poolIndex];
|
||||
|
||||
entrysize = fix_pool_sizes[poolIndex] + sizeof(void *);
|
||||
entrycount = (buffersize / entrysize);
|
||||
fsb = buffer;
|
||||
for (i = 0; i < (entrycount - 1); i++) {
|
||||
fsbnext = (FixSubBlock *) ((long) fsb + entrysize);
|
||||
fsb->fixblock = fixblock;
|
||||
fsb->next = fsbnext;
|
||||
fsb = fsbnext;
|
||||
}
|
||||
|
||||
fsb->fixblock = fixblock;
|
||||
fsb->next = fix_start[poolIndex].b;
|
||||
fix_start[poolIndex].b = buffer;
|
||||
}
|
||||
|
||||
static void *allocate_from_fixed_pools(size_t size) {
|
||||
int poolIndex;
|
||||
FixSubBlock *fsb;
|
||||
|
||||
poolIndex = 0;
|
||||
while (size > fix_pool_sizes[poolIndex])
|
||||
poolIndex++;
|
||||
|
||||
if (!fix_start[poolIndex].b) {
|
||||
void *buf;
|
||||
size_t bufsize;
|
||||
|
||||
buf = allocate_from_var_pools(4000);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
bufsize = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
|
||||
FixBlock_construct(
|
||||
buf, NULL, fix_start[poolIndex].a, poolIndex,
|
||||
((FixBlock *) buf) + 1,
|
||||
bufsize - sizeof(FixBlock)
|
||||
);
|
||||
fix_start[poolIndex].a = buf;
|
||||
}
|
||||
|
||||
fsb = fix_start[poolIndex].b;
|
||||
fix_start[poolIndex].b = fsb->next;
|
||||
fix_start[poolIndex].count++;
|
||||
return ((FixSubBlockBase *) fsb) + 1;
|
||||
}
|
||||
|
||||
static void deallocate_from_fixed_pools(void *buf, size_t size) {
|
||||
int poolIndex;
|
||||
FixBlock *fixblock;
|
||||
FixBlock *nextfb;
|
||||
FixSubBlock *fsb;
|
||||
|
||||
poolIndex = 0;
|
||||
while (size > fix_pool_sizes[poolIndex])
|
||||
poolIndex++;
|
||||
|
||||
fsb = (FixSubBlock *) ((long) buf - sizeof(FixSubBlockBase));
|
||||
fsb->next = fix_start[poolIndex].b;
|
||||
fix_start[poolIndex].b = fsb;
|
||||
if (--fix_start[poolIndex].count == 0) {
|
||||
fixblock = fix_start[poolIndex].a;
|
||||
while (fixblock) {
|
||||
nextfb = fixblock->next;
|
||||
deallocate_from_var_pools(fixblock);
|
||||
fixblock = nextfb;
|
||||
}
|
||||
fix_start[poolIndex].a = NULL;
|
||||
fix_start[poolIndex].b = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t IRO_msize(void *buf) {
|
||||
return BUF_SIZE(buf);
|
||||
}
|
||||
|
||||
void *IRO_malloc(size_t size) {
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
if (size <= 0x4C)
|
||||
return allocate_from_fixed_pools(size);
|
||||
else
|
||||
return allocate_from_var_pools(size);
|
||||
}
|
||||
|
||||
void IRO_free(void *buf) {
|
||||
if (buf) {
|
||||
size_t size = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
|
||||
|
||||
if (size <= 0x4C)
|
||||
deallocate_from_fixed_pools(buf, size);
|
||||
else
|
||||
deallocate_from_var_pools(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void *IRO_realloc(void *buf, size_t newsize) {
|
||||
size_t oldsize;
|
||||
size_t newblocksize;
|
||||
void *newbuf;
|
||||
|
||||
if (!buf)
|
||||
return IRO_malloc(newsize);
|
||||
|
||||
if (!newsize) {
|
||||
IRO_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
oldsize = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
|
||||
if (newsize > oldsize) {
|
||||
if (BUF_IS_VAR(buf)) {
|
||||
newblocksize = (newsize + sizeof(Block) - 1) & ~FLAGMASK;
|
||||
if (newblocksize < 0x60)
|
||||
newblocksize = 0x60;
|
||||
SubBlock_merge_next(VARBUF_SB(buf), &BLOCK_TAIL(VARBUF_BLOCK(buf))->unk);
|
||||
if (VARBUF_BLOCKSIZE(buf) >= newblocksize) {
|
||||
if ((VARBUF_BLOCKSIZE(buf) - newblocksize) >= 0x60) {
|
||||
Block_link(VARBUF_BLOCK(buf), SubBlock_split(VARBUF_SB(buf), newblocksize));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
newbuf = IRO_malloc(newsize);
|
||||
if (!newbuf)
|
||||
return NULL;
|
||||
|
||||
memcpy(newbuf, buf, oldsize);
|
||||
IRO_free(buf);
|
||||
return newbuf;
|
||||
}
|
||||
|
||||
if (BUF_IS_VAR(buf)) {
|
||||
newsize = (newsize + sizeof(Block) - 1) & ~FLAGMASK;
|
||||
if (newsize < 0x60)
|
||||
newsize = 0x60;
|
||||
if ((VARBUF_BLOCKSIZE(buf) - newsize) >= 0x60) {
|
||||
Block_link(VARBUF_BLOCK(buf), SubBlock_split(VARBUF_SB(buf), newsize));
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void *IRO_calloc(size_t a, size_t b) {
|
||||
void *buf;
|
||||
size_t len = b * a;
|
||||
buf = IRO_malloc(len);
|
||||
if (buf)
|
||||
memset(buf, 0, len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void IRO_pool_free_all(void) {
|
||||
int i;
|
||||
Block *block;
|
||||
if ((block = start_)) {
|
||||
do {
|
||||
block = block->next;
|
||||
} while (block != start_);
|
||||
start_ = NULL;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
fix_start[i].a = NULL;
|
||||
fix_start[i].b = NULL;
|
||||
fix_start[i].count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_InitializeAllocator(void) {
|
||||
if (!initialized) {
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
fix_start[i].a = NULL;
|
||||
fix_start[i].b = NULL;
|
||||
fix_start[i].count = 0;
|
||||
}
|
||||
start_ = NULL;
|
||||
initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void IRO_TerminateAllocator(void) {
|
||||
initialized = 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
2925
compiler_and_linker/unsorted/IroPointerAnalysisADTs.c
Normal file
2925
compiler_and_linker/unsorted/IroPointerAnalysisADTs.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,595 @@
|
||||
#include "compiler/IroPropagate.h"
|
||||
#include "compiler/IroCSE.h"
|
||||
#include "compiler/IroDump.h"
|
||||
#include "compiler/IroEval.h"
|
||||
#include "compiler/IroFlowgraph.h"
|
||||
#include "compiler/IroLinearForm.h"
|
||||
#include "compiler/IROUseDef.h"
|
||||
#include "compiler/IroUtil.h"
|
||||
#include "compiler/IroVars.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/CExpr.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/InlineAsm.h"
|
||||
#include "compiler/InlineAsmPPC.h"
|
||||
|
||||
IROAssign *IRO_FirstAssign;
|
||||
IROAssign *IRO_LastAssign;
|
||||
SInt32 IRO_NumAssign;
|
||||
|
||||
static Boolean VarIsUsedInOtherFNodes(VarRecord *var, IRONode *node) {
|
||||
if (var->defs && var->uses) {
|
||||
IROUse *use;
|
||||
IRODef *def = NULL;
|
||||
for (use = var->uses; use; use = use->varnext) {
|
||||
if (!def && use->node == node && use->linear && !(use->linear->flags & IROLF_Assigned)) {
|
||||
for (def = var->defs; def; def = def->varnext) {
|
||||
if (Bv_IsBitSet(def->index, use->x18))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (def) {
|
||||
for (use = var->uses; use; use = use->varnext) {
|
||||
if (use->node != node && use->linear && !(use->linear->flags & IROLF_Assigned)) {
|
||||
if (Bv_IsBitSet(def->index, use->x18))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IROLinear *linear;
|
||||
IRONode *scan;
|
||||
for (scan = IRO_FirstNode; scan; scan = scan->nextnode) {
|
||||
if (scan != node) {
|
||||
linear = scan->first;
|
||||
while (1) {
|
||||
if (!linear)
|
||||
break;
|
||||
|
||||
if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
|
||||
if (IRO_FindVar(linear->u.diadic.left->u.node->data.objref, 0, 1) == var)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (linear == scan->last)
|
||||
break;
|
||||
linear = linear->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
IRO_CheckForUserBreak();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void GetExprUses(IROLinear *linear, Boolean isFirst) {
|
||||
if (isFirst && 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))) {
|
||||
VarRecord *var = IRO_FindVar(obj, 0, 1);
|
||||
if (var)
|
||||
Bv_SetBit(var->index, IRO_VarKills);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GetExprKills(IROLinear *linear, Boolean isFirst) {
|
||||
if (isFirst)
|
||||
IRO_GetKills(linear);
|
||||
}
|
||||
|
||||
static void CheckUnorderedRegionForDefs(IROLinear *linear, BitVector *a, BitVector *b, Boolean *flag) {
|
||||
Bv_Clear(a);
|
||||
Bv_Clear(IRO_VarKills);
|
||||
IRO_WalkTree(linear, GetExprKills);
|
||||
Bv_Or(IRO_VarKills, a);
|
||||
if (Bv_BitsInCommon(a, b))
|
||||
*flag = 1;
|
||||
}
|
||||
|
||||
static void CheckUnorderedRegionsForDefs(IROLinear *linear1, IROLinear *linear2, BitVector *a, BitVector *b, Boolean *flag) {
|
||||
int i;
|
||||
|
||||
switch (linear1->type) {
|
||||
case IROLinearOp2Arg:
|
||||
if (linear1->nodetype == ELAND) break;
|
||||
if (linear1->nodetype == ELOR) break;
|
||||
if (linear1->nodetype == ECOMMA) break;
|
||||
if (linear1->u.diadic.left != linear2)
|
||||
CheckUnorderedRegionForDefs(linear1->u.diadic.left, a, b, flag);
|
||||
if (linear1->u.diadic.right != linear2)
|
||||
CheckUnorderedRegionForDefs(linear1->u.diadic.right, a, b, flag);
|
||||
break;
|
||||
case IROLinearFunccall:
|
||||
if (linear1->u.funccall.linear8 != linear2)
|
||||
CheckUnorderedRegionForDefs(linear1->u.funccall.linear8, a, b, flag);
|
||||
for (i = 0; !*flag && i < linear1->u.funccall.argCount; i++) {
|
||||
if (linear1->u.funccall.args[i] != linear2)
|
||||
CheckUnorderedRegionForDefs(linear1->u.funccall.args[i], a, b, flag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static Boolean PropagationHasDefsInUnorderedRegions(IROLinear *a, IROLinear *b) {
|
||||
Boolean flag;
|
||||
IROLinear *father;
|
||||
BitVector *bv1;
|
||||
BitVector *bv2;
|
||||
VarRecord *var;
|
||||
|
||||
flag = 0;
|
||||
if ((father = IRO_LocateFather(a))) {
|
||||
Bv_AllocVector(&bv1, IRO_NumVars + 1);
|
||||
Bv_AllocVector(&bv2, IRO_NumVars + 1);
|
||||
Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
|
||||
IRO_WalkTree(b, GetExprUses);
|
||||
Bv_Or(IRO_VarKills, bv2);
|
||||
var = IRO_FindVar(a->u.diadic.left->u.node->data.objref, 0, 1);
|
||||
Bv_SetBit(var->index, bv2);
|
||||
while (father && !flag) {
|
||||
CheckUnorderedRegionsForDefs(father, a, bv1, bv2, &flag);
|
||||
a = father;
|
||||
father = IRO_LocateFather(father);
|
||||
}
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
int IRO_IsRegable(Object *obj) {
|
||||
if (obj->datatype == DLOCAL && obj->u.var.info)
|
||||
return obj->u.var.info->noregister == 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Boolean IsPropagatable(IROLinear *linear) {
|
||||
Object *obj;
|
||||
Object *obj2;
|
||||
|
||||
if (IS_LINEAR_DIADIC(linear, EASS) && (obj = IRO_IsVariable(linear->u.diadic.left)) && obj->type == linear->rtype && !is_volatile_object(obj)) {
|
||||
if (linear->u.diadic.left->flags & IROLF_BitfieldIndirect) {
|
||||
if (!IRO_IsConstant(linear->u.diadic.right))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (IRO_IsConstant(linear->u.diadic.right))
|
||||
return 1;
|
||||
|
||||
if ((obj2 = IRO_IsVariable(linear->u.diadic.right)) && !is_volatile_object(obj2) && IRO_TypesEqual(obj->type, linear->rtype)) {
|
||||
if (!Inline_IsObjectData(linear->u.diadic.right->u.monadic->u.node->data.objref)) {
|
||||
if (IRO_IsRegable(obj) && !IRO_IsRegable(obj2))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Boolean IsIntGenKillCandidate(IROLinear *linear) {
|
||||
if (linear->type == IROLinearFunccall)
|
||||
return 1;
|
||||
|
||||
if (IRO_IsAssignOp[linear->nodetype] && (linear->type == IROLinearOp1Arg || linear->type == IROLinearOp2Arg))
|
||||
return 1;
|
||||
|
||||
if (linear->type == IROLinearAsm)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Boolean IsPropagatableExpr(IROLinear *linear, IROList *list) {
|
||||
Object *obj;
|
||||
if (IS_LINEAR_DIADIC(linear, EASS) && !(linear->flags & IROLF_Reffed)) {
|
||||
if ((obj = IRO_IsVariable(linear->u.diadic.left)) && !is_volatile_object(obj) && !(linear->u.diadic.left->flags & IROLF_BitfieldIndirect)) {
|
||||
if (!IRO_IsRegable(obj))
|
||||
return 0;
|
||||
if (IS_LINEAR_ENODE(linear->u.diadic.right, ESTRINGCONST))
|
||||
return 0;
|
||||
|
||||
IRO_FindDepends(linear->u.diadic.right);
|
||||
if (!IRO_NotSubable)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ClearAvailibilityOnNode(IRONode *node, UInt32 bit) {
|
||||
IRONode *scan;
|
||||
|
||||
for (scan = node->nextnode; scan; scan = scan->nextnode)
|
||||
Bv_ClearBit(bit, scan->x16);
|
||||
}
|
||||
|
||||
Boolean IRO_CopyAndConstantPropagation(void) {
|
||||
IROAssign *ass2;
|
||||
IROAssign *ass;
|
||||
IROLinear *linear;
|
||||
IRONode *node;
|
||||
VarRecord *var;
|
||||
BitVector *bv;
|
||||
Boolean flag;
|
||||
Boolean result;
|
||||
|
||||
IRO_FirstAssign = NULL;
|
||||
IRO_NumAssign = 0;
|
||||
result = 0;
|
||||
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
linear = node->first;
|
||||
while (1) {
|
||||
if (!linear)
|
||||
break;
|
||||
|
||||
if (IsPropagatable(linear) && (var = IRO_FindAssigned(linear))) {
|
||||
IROAssign *newass;
|
||||
IRO_Dump("Found propagatable assignment at: %d\n", linear->index);
|
||||
newass = oalloc(sizeof(IROAssign));
|
||||
newass->linear = linear;
|
||||
newass->next = NULL;
|
||||
newass->index = ++IRO_NumAssign;
|
||||
newass->varIndex = var->index;
|
||||
newass->linear2 = linear->u.diadic.right;
|
||||
newass->var = NULL;
|
||||
newass->varObj = IRO_IsVariable(linear->u.diadic.right);
|
||||
newass->node = node;
|
||||
if (newass->varObj)
|
||||
newass->var = IRO_FindVar(newass->varObj, 0, 1);
|
||||
if (!IRO_FirstAssign)
|
||||
IRO_FirstAssign = newass;
|
||||
else
|
||||
IRO_LastAssign->next = newass;
|
||||
IRO_LastAssign = newass;
|
||||
}
|
||||
|
||||
if (linear == node->last)
|
||||
break;
|
||||
linear = linear->next;
|
||||
}
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
|
||||
node = IRO_FirstNode;
|
||||
ass = IRO_FirstAssign;
|
||||
Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
|
||||
while (node) {
|
||||
Bv_AllocVector(&node->x16, IRO_NumAssign);
|
||||
if (node != IRO_FirstNode)
|
||||
Bv_Set(node->x16);
|
||||
Bv_AllocVector(&node->x22, IRO_NumAssign);
|
||||
Bv_AllocVector(&node->x1E, IRO_NumAssign);
|
||||
Bv_AllocVector(&node->x2A, IRO_NumAssign);
|
||||
node->x1A = NULL;
|
||||
|
||||
linear = node->first;
|
||||
while (1) {
|
||||
if (!linear)
|
||||
break;
|
||||
|
||||
if (IsIntGenKillCandidate(linear)) {
|
||||
//IROAssign *ass2;
|
||||
Bv_Clear(IRO_VarKills);
|
||||
IRO_GetKills(linear);
|
||||
|
||||
for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
|
||||
if (Bv_IsBitSet(ass2->varIndex, IRO_VarKills)) {
|
||||
Bv_SetBit(ass2->index, node->x22);
|
||||
Bv_ClearBit(ass2->index, node->x1E);
|
||||
}
|
||||
if (ass2->var && Bv_IsBitSet(ass2->var->index, IRO_VarKills)) {
|
||||
Bv_SetBit(ass2->index, node->x22);
|
||||
Bv_ClearBit(ass2->index, node->x1E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (ass && ass->linear == linear) {
|
||||
Bv_SetBit(ass->index, node->x1E);
|
||||
ass = ass->next;
|
||||
}
|
||||
|
||||
if (linear == node->last)
|
||||
break;
|
||||
linear = linear->next;
|
||||
}
|
||||
|
||||
Bv_Copy(node->x16, node->x2A);
|
||||
Bv_Minus(node->x22, node->x2A);
|
||||
Bv_Or(node->x1E, node->x2A);
|
||||
node = node->nextnode;
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
|
||||
Bv_AllocVector(&bv, IRO_NumAssign);
|
||||
do {
|
||||
flag = 0;
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
if (node == IRO_FirstNode) {
|
||||
Bv_Clear(bv);
|
||||
} else {
|
||||
UInt16 i;
|
||||
Bv_Set(bv);
|
||||
for (i = 0; i < node->numpred; i++)
|
||||
Bv_And(IRO_NodeTable[node->pred[i]]->x2A, bv);
|
||||
}
|
||||
|
||||
if (!Bv_Compare(bv, node->x16)) {
|
||||
flag = 1;
|
||||
Bv_Copy(bv, node->x16);
|
||||
}
|
||||
|
||||
Bv_Copy(node->x16, node->x2A);
|
||||
Bv_Minus(node->x22, node->x2A);
|
||||
Bv_Or(node->x1E, node->x2A);
|
||||
}
|
||||
} while (flag);
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
|
||||
node = IRO_FirstNode;
|
||||
ass = IRO_FirstAssign;
|
||||
while (node) {
|
||||
IRO_Avail = node->x16;
|
||||
linear = node->first;
|
||||
while (1) {
|
||||
if (!linear)
|
||||
break;
|
||||
|
||||
if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
|
||||
if ((var = IRO_FindVar(linear->u.diadic.left->u.node->data.objref, 0, 1))) {
|
||||
//IROAssign *ass2;
|
||||
for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
|
||||
if (
|
||||
ass2->varIndex == var->index &&
|
||||
Bv_IsBitSet(ass2->index, IRO_Avail) &&
|
||||
(IRO_IsConstant(ass2->linear2) || node->loopdepth <= ass2->node->loopdepth) &&
|
||||
!PropagationHasDefsInUnorderedRegions(linear, ass2->linear2)
|
||||
) {
|
||||
if (ass2->linear2->type == IROLinearOperand && IRO_is_CPtypeequal(linear->rtype, ass2->linear->u.diadic.left->rtype)) {
|
||||
ENode *enode = IRO_NewENode(ass2->linear2->u.node->type);
|
||||
*enode = *ass2->linear2->u.node;
|
||||
if (enode->type == EINTCONST) {
|
||||
if (linear->flags & IROLF_BitfieldIndirect) {
|
||||
IRO_TruncateBitfieldValueToType(&enode->data.intval, linear->rtype, var->x1A);
|
||||
enode->rtype = linear->rtype;
|
||||
result = 1;
|
||||
} else {
|
||||
IRO_TruncateValueToType(&enode->data.intval, linear->rtype);
|
||||
enode->rtype = linear->rtype;
|
||||
}
|
||||
}
|
||||
linear->u.monadic->type = IROLinearNop;
|
||||
linear->type = IROLinearOperand;
|
||||
linear->u.node = enode;
|
||||
} else if (ass2->varObj && IRO_is_CPtypeequal(linear->rtype, ass2->linear->rtype)) {
|
||||
linear->u.diadic.left->u.node = create_objectrefnode(ass2->varObj);
|
||||
if (ass2->linear2->flags & IROLF_BitfieldIndirect)
|
||||
linear->flags |= IROLF_BitfieldIndirect;
|
||||
}
|
||||
IRO_Dump("Found propagation at %d from %d\n", linear->index, ass2->linear->index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (linear->type == IROLinearAsm) {
|
||||
IAEffects effects;
|
||||
int i;
|
||||
CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
|
||||
|
||||
for (i = 0; i < effects.numoperands; i++) {
|
||||
if (effects.operands[i].type == IAEffect_0 && effects.operands[i].offset == 0 && effects.operands[i].object->type->size == effects.operands[i].size) {
|
||||
if ((var = IRO_FindVar(effects.operands[i].object, 0, 1))) {
|
||||
//IROAssign *ass2;
|
||||
for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
|
||||
if (ass2->varIndex == var->index && Bv_IsBitSet(ass2->index, IRO_Avail) && ass2->linear->rtype->size == effects.operands[i].size) {
|
||||
ENode *enode;
|
||||
if (ass2->varObj) {
|
||||
enode = create_objectrefnode(ass2->varObj);
|
||||
} else if (ass2->linear2->type == IROLinearOperand) {
|
||||
enode = ass2->linear2->u.node;
|
||||
} else {
|
||||
#line 768
|
||||
CError_FATAL();
|
||||
}
|
||||
CodeGen_PropagateIntoAsm(linear->u.asm_stmt, effects.operands[i].object, enode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsIntGenKillCandidate(linear)) {
|
||||
//IROAssign *ass2;
|
||||
Bv_Clear(IRO_VarKills);
|
||||
IRO_GetKills(linear);
|
||||
|
||||
for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
|
||||
if (Bv_IsBitSet(ass2->varIndex, IRO_VarKills)) {
|
||||
Bv_ClearBit(ass2->index, IRO_Avail);
|
||||
}
|
||||
if (ass2->var && Bv_IsBitSet(ass2->var->index, IRO_VarKills)) {
|
||||
Bv_ClearBit(ass2->index, IRO_Avail);
|
||||
}
|
||||
}
|
||||
|
||||
while (ass && ass->linear == linear) {
|
||||
Bv_SetBit(ass->index, IRO_Avail);
|
||||
ass = ass->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (linear == node->last)
|
||||
break;
|
||||
linear = linear->next;
|
||||
}
|
||||
node = node->nextnode;
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IRO_ExpressionPropagation(void) {
|
||||
IRONode *node;
|
||||
IROLinear *linear;
|
||||
Object *obj;
|
||||
VarRecord *var;
|
||||
IROAssign *ass;
|
||||
|
||||
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
||||
IRO_FirstAssign = NULL;
|
||||
IRO_LastAssign = NULL;
|
||||
IRO_NumAssign = 0;
|
||||
|
||||
linear = node->first;
|
||||
while (1) {
|
||||
IROList list;
|
||||
if (!linear)
|
||||
break;
|
||||
|
||||
IRO_InitList(&list);
|
||||
if (IsPropagatableExpr(linear, &list)) {
|
||||
if ((var = IRO_FindAssigned(linear))) {
|
||||
IRO_Dump("Found propagatable expression assignment at: %d\n", linear->index);
|
||||
ass = oalloc(sizeof(IROAssign));
|
||||
ass->linear = linear;
|
||||
ass->next = NULL;
|
||||
ass->index = ++IRO_NumAssign;
|
||||
ass->varIndex = var->index;
|
||||
ass->linear2 = linear->u.diadic.right;
|
||||
ass->x20 = 0;
|
||||
ass->node = node;
|
||||
IRO_FindDepends(linear->u.diadic.right);
|
||||
ass->depends = IRO_Depends;
|
||||
if (!IRO_FirstAssign) {
|
||||
IRO_FirstAssign = ass;
|
||||
ass->prev = NULL;
|
||||
} else {
|
||||
IRO_LastAssign->next = ass;
|
||||
ass->prev = IRO_LastAssign;
|
||||
}
|
||||
IRO_LastAssign = ass;
|
||||
}
|
||||
}
|
||||
|
||||
if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
|
||||
if ((var = IRO_FindVar(linear->u.monadic->u.node->data.objref, 0, 1))) {
|
||||
for (ass = IRO_LastAssign; ass; ass = ass->prev) {
|
||||
if (ass->varIndex == var->index)
|
||||
ass->x20++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (linear == node->last)
|
||||
break;
|
||||
linear = linear->next;
|
||||
}
|
||||
|
||||
Bv_AllocVector(&IRO_Avail, IRO_NumAssign);
|
||||
|
||||
linear = node->first;
|
||||
while (1) {
|
||||
if (!linear)
|
||||
break;
|
||||
|
||||
if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
|
||||
if ((var = IRO_FindVar(linear->u.monadic->u.node->data.objref, 0, 1))) {
|
||||
for (ass = IRO_LastAssign; ass; ass = ass->next) {
|
||||
if (ass->varIndex == var->index && Bv_IsBitSet(ass->index, IRO_Avail) && !PropagationHasDefsInUnorderedRegions(linear, ass->linear2)) {
|
||||
if (ass->linear2->type == IROLinearOperand && IRO_is_CPtypeequal(linear->rtype, ass->linear->u.diadic.left->rtype)) {
|
||||
ENode *enode = IRO_NewENode(ass->linear2->u.node->type);
|
||||
*enode = *ass->linear2->u.node;
|
||||
if (enode->type == EINTCONST) {
|
||||
IRO_TruncateValueToType(&enode->data.intval, linear->rtype);
|
||||
enode->rtype = linear->rtype;
|
||||
} else if (enode->type == EOBJREF) {
|
||||
IROLinear *tmp = IRO_LocateFather(linear);
|
||||
if (tmp && (tmp->flags & IROLF_Assigned))
|
||||
linear->flags |= IROLF_Assigned;
|
||||
}
|
||||
linear->u.monadic->type = IROLinearNop;
|
||||
linear->type = IROLinearOperand;
|
||||
linear->u.node = enode;
|
||||
} else if (IRO_IsVariable(ass->linear2) && IRO_is_CPtypeequal(linear->rtype, ass->linear->rtype)) {
|
||||
linear->u.monadic->u.node = create_objectrefnode(ass->linear2->u.monadic->u.node->data.objref);
|
||||
if (ass->linear2->flags & IROLF_BitfieldIndirect)
|
||||
linear->flags |= IROLF_BitfieldIndirect;
|
||||
} else if (IRO_is_CPtypeequal(linear->rtype, ass->linear->rtype) && ass->x20 == 1 && !VarIsUsedInOtherFNodes(var, node)) {
|
||||
IROList list;
|
||||
IRO_InitList(&list);
|
||||
IRO_DuplicateExpr(ass->linear->u.diadic.right, &list);
|
||||
if (IS_TYPE_FLOAT(ass->linear->rtype)) {
|
||||
IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg);
|
||||
tmp->index = ++IRO_NumLinear;
|
||||
tmp->rtype = ass->linear->rtype;
|
||||
tmp->nodetype = ETYPCON;
|
||||
tmp->nodeflags = ENODE_FLAG_80;
|
||||
tmp->u.monadic = list.tail;
|
||||
IRO_AddToList(tmp, &list);
|
||||
}
|
||||
IRO_PasteAfter(list.head, list.tail, linear);
|
||||
IRO_LocateFather_Cut_And_Paste(linear, list.tail);
|
||||
linear = list.tail;
|
||||
}
|
||||
IRO_Dump("Found expression propagation at %d from %d\n", linear->index, ass->linear->index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (linear->type != IROLinearNop && IsIntGenKillCandidate(linear)) {
|
||||
Bv_Clear(IRO_VarKills);
|
||||
IRO_GetKills(linear);
|
||||
for (ass = IRO_FirstAssign; ass; ass = ass->next) {
|
||||
if (Bv_IsBitSet(ass->varIndex, IRO_VarKills))
|
||||
Bv_ClearBit(ass->index, IRO_Avail);
|
||||
if ((obj = IRO_IsVariable(ass->linear->u.diadic.right))) {
|
||||
if ((var = IRO_FindVar(obj, 0, 1))) {
|
||||
if (Bv_IsBitSet(var->index, IRO_VarKills))
|
||||
Bv_ClearBit(ass->index, IRO_Avail);
|
||||
}
|
||||
} else {
|
||||
IROList list;
|
||||
IRO_InitList(&list);
|
||||
IRO_Depends = ass->depends;
|
||||
IRO_FindDepends_NoAlloc(ass->linear->u.diadic.right);
|
||||
if (Bv_BitsInCommon(IRO_VarKills, ass->depends))
|
||||
Bv_ClearBit(ass->index, IRO_Avail);
|
||||
}
|
||||
}
|
||||
|
||||
for (ass = IRO_FirstAssign; ass; ass = ass->next) {
|
||||
IRO_Depends = ass->depends;
|
||||
IRO_FindDepends_NoAlloc(ass->linear->u.diadic.right);
|
||||
if (ass->linear == linear && !Bv_IsBitSet(ass->varIndex, ass->depends))
|
||||
Bv_SetBit(ass->index, IRO_Avail);
|
||||
}
|
||||
}
|
||||
|
||||
if (linear == node->last)
|
||||
break;
|
||||
linear = linear->next;
|
||||
}
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
}
|
||||
|
@ -0,0 +1,776 @@
|
||||
#include "compiler/IroRangePropagation.h"
|
||||
#include "compiler/IroDump.h"
|
||||
#include "compiler/IroFlowgraph.h"
|
||||
#include "compiler/IroLinearForm.h"
|
||||
#include "compiler/IroMalloc.h"
|
||||
#include "compiler/IroPointerAnalysis.h"
|
||||
#include "compiler/IroUtil.h"
|
||||
#include "compiler/IroVars.h"
|
||||
#include "compiler/CInt64.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/types.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef enum ERangeType {
|
||||
ERangeType0,
|
||||
ERangeType1,
|
||||
ERangeType2,
|
||||
ERangeType3
|
||||
} ERangeType;
|
||||
|
||||
typedef struct ERange {
|
||||
ERangeType type;
|
||||
CInt64 upper;
|
||||
CInt64 lower;
|
||||
} ERange;
|
||||
|
||||
typedef struct ERecord {
|
||||
Object *object;
|
||||
ERange *range;
|
||||
struct ERecord *next;
|
||||
} ERecord;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
static ERecord *ERangeFirst;
|
||||
static ERecord *ERangeLast;
|
||||
|
||||
static ERange *ERnewERange(ERangeType type) {
|
||||
ERange *range;
|
||||
|
||||
range = oalloc(sizeof(ERange));
|
||||
range->type = type;
|
||||
return range;
|
||||
}
|
||||
|
||||
static ERecord *ERnewRecord(Object *object, ERange *range) {
|
||||
ERecord *record;
|
||||
|
||||
record = oalloc(sizeof(ERecord));
|
||||
record->object = object;
|
||||
record->range = range;
|
||||
record->next = ERangeFirst;
|
||||
ERangeFirst = record;
|
||||
if (!ERangeLast)
|
||||
ERangeLast = record;
|
||||
return record;
|
||||
}
|
||||
|
||||
static ERecord *ERecordFound(Object *obj) {
|
||||
ERecord *scan;
|
||||
|
||||
scan = ERangeFirst;
|
||||
while (scan && obj != scan->object)
|
||||
scan = scan->next;
|
||||
|
||||
return scan;
|
||||
}
|
||||
|
||||
static Boolean EREandHasNoUse(ERange *range, CInt64 val) {
|
||||
UInt16 i;
|
||||
CInt64 v11;
|
||||
CInt64 work;
|
||||
|
||||
i = 0;
|
||||
work = range->upper;
|
||||
while (CInt64_NotEqual(work = CInt64_ShrU(work, cint64_one), cint64_zero))
|
||||
i++;
|
||||
|
||||
if (CInt64_NotEqual(range->upper, cint64_zero))
|
||||
i++;
|
||||
|
||||
CInt64_SetULong(&work, i);
|
||||
v11 = CInt64_Sub(CInt64_Shl(cint64_one, work), cint64_one);
|
||||
if (CInt64_NotEqual(cint64_zero, CInt64_And(CInt64_Inv(val), v11)))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ERcheckOverflow(ERange *range, Type *type) {
|
||||
CInt64 typeSize;
|
||||
CInt64 work;
|
||||
CInt64 work2;
|
||||
CInt64 value3;
|
||||
|
||||
if (!range)
|
||||
return;
|
||||
|
||||
if (!IS_TYPE_INT(type)) {
|
||||
range->type = ERangeType3;
|
||||
return;
|
||||
}
|
||||
|
||||
CInt64_SetLong(&typeSize, type->size);
|
||||
CInt64_SetLong(&value3, 3);
|
||||
|
||||
if (IRO_IsUnsignedType(type)) {
|
||||
if (type->size < 8) {
|
||||
work = CInt64_Sub(CInt64_Shl(cint64_one, CInt64_Shl(typeSize, value3)), cint64_one);
|
||||
if (CInt64_GreaterU(range->upper, work))
|
||||
range->type = ERangeType3;
|
||||
} else {
|
||||
range->type = ERangeType3;
|
||||
}
|
||||
} else {
|
||||
if (type->size < 8) {
|
||||
work = CInt64_Sub(CInt64_Shl(cint64_one, CInt64_Sub(CInt64_Shl(typeSize, value3), cint64_one)), cint64_one);
|
||||
work2 = CInt64_Shl(cint64_negone, CInt64_Sub(CInt64_Shl(typeSize, value3), cint64_one));
|
||||
if (CInt64_Greater(range->upper, work) || CInt64_Less(range->lower, work2))
|
||||
range->type = ERangeType3;
|
||||
} else {
|
||||
range->type = ERangeType3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ERinvalidAll(void) {
|
||||
ERecord *record;
|
||||
|
||||
for (record = ERangeFirst; record; record = record->next)
|
||||
record->range->type = ERangeType3;
|
||||
}
|
||||
|
||||
static void SetRangesForKillsByIndirectAssignment(IROLinear *nd) {
|
||||
IROListNode *list;
|
||||
IROListNode *scan;
|
||||
IROLinear *inner;
|
||||
Boolean failed;
|
||||
IROListNode *resultList;
|
||||
IROLinear *scannd;
|
||||
Boolean foundObjRef;
|
||||
ERecord *record;
|
||||
ERange *range;
|
||||
IROListNode *next;
|
||||
Object *obj;
|
||||
IROLinear *analysend;
|
||||
Object *proc;
|
||||
|
||||
failed = 0;
|
||||
if (nd->type == IROLinearOp2Arg)
|
||||
inner = nd->u.diadic.left;
|
||||
else
|
||||
inner = nd->u.monadic;
|
||||
|
||||
if (
|
||||
inner &&
|
||||
inner->type == IROLinearOp1Arg &&
|
||||
inner->nodetype == EINDIRECT &&
|
||||
(analysend = inner->u.monadic) &&
|
||||
copts.opt_pointer_analysis &&
|
||||
analysend->pointsToFunction &&
|
||||
(proc = FunctionName)
|
||||
) {
|
||||
resultList = NULL;
|
||||
PointerAnalysis_LookupLinearNodePointerExpr(proc, analysend, &resultList);
|
||||
|
||||
if ((list = resultList)) {
|
||||
for (scan = list; scan; scan = scan->nextList) {
|
||||
if (!scan->list.head || !scan->list.tail) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
foundObjRef = 0;
|
||||
for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
|
||||
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
|
||||
foundObjRef = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundObjRef) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!failed) {
|
||||
for (; list; list = list->nextList) {
|
||||
for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
|
||||
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
|
||||
obj = scannd->u.node->data.objref;
|
||||
#line 302
|
||||
CError_ASSERT(obj != NULL);
|
||||
|
||||
range = nd->x16;
|
||||
if (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC)
|
||||
range = inner->x16;
|
||||
|
||||
record = ERecordFound(obj);
|
||||
if (!record)
|
||||
ERnewRecord(obj, range);
|
||||
else
|
||||
record->range = range;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (resultList) {
|
||||
next = resultList->nextList;
|
||||
IRO_free(resultList);
|
||||
resultList = next;
|
||||
}
|
||||
} else {
|
||||
failed = 1;
|
||||
}
|
||||
} else {
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
ERinvalidAll();
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
}
|
||||
}
|
||||
|
||||
static void InvalidateRangesForKillsByFunctionCall(IROLinear *nd) {
|
||||
IROListNode *scan;
|
||||
IROLinear *scannd;
|
||||
Boolean failed;
|
||||
Boolean foundObjRef;
|
||||
IROListNode *list;
|
||||
IROListNode *resultList;
|
||||
ERecord *record;
|
||||
IROListNode *next;
|
||||
Object *obj;
|
||||
IROLinear *analysend;
|
||||
Object *proc;
|
||||
ObjectList *olist;
|
||||
ObjectList *killList;
|
||||
|
||||
failed = 0;
|
||||
|
||||
if (
|
||||
(analysend = nd->u.funccall.linear8) &&
|
||||
copts.opt_pointer_analysis &&
|
||||
analysend->pointsToFunction &&
|
||||
(proc = FunctionName)
|
||||
) {
|
||||
resultList = NULL;
|
||||
PointerAnalysis_LookupLinearNodePointerExpr(proc, analysend, &resultList);
|
||||
|
||||
if (resultList) {
|
||||
for (scan = resultList; scan; scan = scan->nextList) {
|
||||
if (!scan->list.head || !scan->list.tail) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
foundObjRef = 0;
|
||||
for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
|
||||
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
|
||||
foundObjRef = 1;
|
||||
obj = scannd->u.node->data.objref;
|
||||
#line 385
|
||||
CError_ASSERT(obj != NULL);
|
||||
|
||||
killList = NULL;
|
||||
PointerAnalysis_GetFunctionKills(obj, nd, &killList);
|
||||
|
||||
for (olist = killList; olist; olist = olist->next) {
|
||||
if (!olist->object) {
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (killList) {
|
||||
olist = killList->next;
|
||||
IRO_free(killList);
|
||||
killList = olist;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundObjRef)
|
||||
failed = 1;
|
||||
if (failed)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!failed) {
|
||||
for (list = resultList; list; list = list->nextList) {
|
||||
for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
|
||||
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
|
||||
obj = scannd->u.node->data.objref;
|
||||
killList = NULL;
|
||||
PointerAnalysis_GetFunctionKills(obj, nd, &killList);
|
||||
|
||||
for (olist = killList; olist; olist = olist->next) {
|
||||
if ((record = ERecordFound(olist->object)))
|
||||
record->range->type = ERangeType3;
|
||||
}
|
||||
|
||||
while (killList) {
|
||||
olist = killList->next;
|
||||
IRO_free(killList);
|
||||
killList = olist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (resultList) {
|
||||
next = resultList->nextList;
|
||||
IRO_free(resultList);
|
||||
resultList = next;
|
||||
}
|
||||
} else {
|
||||
failed = 1;
|
||||
}
|
||||
} else {
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
ERinvalidAll();
|
||||
}
|
||||
|
||||
static void ERfoldOperand(IROLinear *nd) {
|
||||
switch (nd->u.node->type) {
|
||||
case EOBJREF:
|
||||
nd->x16 = NULL;
|
||||
break;
|
||||
case EINTCONST:
|
||||
nd->x16 = ERnewERange(ERangeType0);
|
||||
nd->x16->upper = nd->x16->lower = nd->u.node->data.intval;
|
||||
break;
|
||||
case EFLOATCONST:
|
||||
case ESTRINGCONST:
|
||||
nd->x16 = ERnewERange(ERangeType0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static Boolean ERfoldExpr(IROLinear *nd) {
|
||||
ERecord *record;
|
||||
ERange *range;
|
||||
IROLinear *tmp;
|
||||
IROLinear *inner;
|
||||
Object *obj;
|
||||
|
||||
switch (nd->nodetype) {
|
||||
case EINDIRECT:
|
||||
inner = nd->u.monadic;
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF) {
|
||||
if (!inner->x16 && (obj = inner->u.node->data.objref)) {
|
||||
if ((record = ERecordFound(obj))) {
|
||||
inner->x16 = ERnewERange(ERangeType3);
|
||||
*inner->x16 = *record->range;
|
||||
} else {
|
||||
inner->x16 = ERnewERange(ERangeType3);
|
||||
inner->x16->upper = cint64_max;
|
||||
inner->x16->lower = cint64_min;
|
||||
ERnewRecord(obj, inner->x16);
|
||||
}
|
||||
}
|
||||
nd->x16 = inner->x16;
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
} else {
|
||||
if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF && !inner->x16)
|
||||
inner->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
}
|
||||
break;
|
||||
case EAND:
|
||||
case EANDASS:
|
||||
if (IRO_IsIntConstant(nd->u.diadic.right)) {
|
||||
CInt64 val = nd->u.diadic.right->u.node->data.intval;
|
||||
nd->x16 = ERnewERange(ERangeType1);
|
||||
nd->x16->upper = val;
|
||||
nd->x16->lower = cint64_zero;
|
||||
if (
|
||||
(range = nd->u.diadic.left->x16) &&
|
||||
range->type != ERangeType3 &&
|
||||
CInt64_LessEqualU(range->upper, val) &&
|
||||
CInt64_LessEqualU(range->lower, val) &&
|
||||
EREandHasNoUse(range, val) &&
|
||||
!IRO_HasSideEffect(nd->u.diadic.left)
|
||||
) {
|
||||
IRO_Dump("eliminating redundant EAND %ld; upperBound==0x%x, lowerBound==0x%x, Constant==0x%x\n",
|
||||
nd->index,
|
||||
CInt64_GetULong(&range->upper),
|
||||
CInt64_GetULong(&range->upper),
|
||||
CInt64_GetULong(&val)
|
||||
);
|
||||
IRO_NopOut(nd->u.diadic.right);
|
||||
nd->type = IROLinearNop;
|
||||
nd->expr = NULL;
|
||||
tmp = nd->u.diadic.left;
|
||||
nd->u.diadic.left = nd->u.diadic.right;
|
||||
if (!IRO_LocateFather_Cut_And_Paste(nd, tmp)) {
|
||||
tmp->flags &= ~IROLF_Reffed;
|
||||
if (IRO_IsVariable(tmp))
|
||||
IRO_NopOut(tmp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (nd->u.diadic.right->x16) {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
*nd->x16 = *nd->u.diadic.right->x16;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case ELOGNOT:
|
||||
case ELESS:
|
||||
case EGREATER:
|
||||
case ELESSEQU:
|
||||
case EGREATEREQU:
|
||||
case EEQU:
|
||||
case ENOTEQU:
|
||||
case ELAND:
|
||||
case ELOR:
|
||||
nd->x16 = ERnewERange(ERangeType1);
|
||||
nd->x16->upper = cint64_one;
|
||||
nd->x16->lower = cint64_zero;
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EBINNOT:
|
||||
case EFORCELOAD:
|
||||
case EXOR:
|
||||
case EOR:
|
||||
case EXORASS:
|
||||
case EORASS:
|
||||
case ECOMMA:
|
||||
case ETYPCON:
|
||||
case EBITFIELD:
|
||||
case ECOND:
|
||||
case ENULLCHECK:
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
break;
|
||||
case EASS:
|
||||
if (IS_TYPE_INT(nd->rtype))
|
||||
nd->x16 = nd->u.diadic.right->x16;
|
||||
break;
|
||||
case EMUL:
|
||||
case EMULV:
|
||||
case EMULASS:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
|
||||
nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
if (IRO_IsUnsignedType(nd->rtype)) {
|
||||
nd->x16->upper = CInt64_MulU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
|
||||
nd->x16->lower = CInt64_MulU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
|
||||
} else {
|
||||
nd->x16->upper = CInt64_Mul(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
|
||||
nd->x16->lower = CInt64_Mul(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
|
||||
}
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EDIV:
|
||||
case EDIVASS:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
|
||||
nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
if (!CInt64_IsZero(&nd->u.diadic.right->x16->lower) && !CInt64_IsZero(&nd->u.diadic.right->x16->upper)) {
|
||||
if (IRO_IsUnsignedType(nd->rtype)) {
|
||||
nd->x16->upper = CInt64_DivU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
|
||||
nd->x16->lower = CInt64_DivU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
|
||||
} else {
|
||||
nd->x16->upper = CInt64_Div(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
|
||||
nd->x16->lower = CInt64_Div(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
|
||||
}
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EMODULO:
|
||||
case EMODASS:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
|
||||
nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
if (!CInt64_IsZero(&nd->u.diadic.right->x16->lower) && !CInt64_IsZero(&nd->u.diadic.right->x16->upper)) {
|
||||
if (IRO_IsUnsignedType(nd->rtype)) {
|
||||
nd->x16->upper = CInt64_ModU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
|
||||
nd->x16->lower = CInt64_ModU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
|
||||
} else {
|
||||
nd->x16->upper = CInt64_Mod(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
|
||||
nd->x16->lower = CInt64_Mod(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
|
||||
}
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EADDV:
|
||||
case EADD:
|
||||
case EADDASS:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
|
||||
nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
nd->x16->upper = CInt64_Add(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
|
||||
nd->x16->lower = CInt64_Add(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case ESUBV:
|
||||
case ESUB:
|
||||
case ESUBASS:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
|
||||
nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
nd->x16->upper = CInt64_Sub(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
|
||||
nd->x16->lower = CInt64_Sub(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case ESHL:
|
||||
case ESHLASS:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
|
||||
nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
nd->x16->upper = CInt64_Shl(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
|
||||
nd->x16->lower = CInt64_Shl(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case ESHR:
|
||||
case ESHRASS:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
|
||||
nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
if (IRO_IsUnsignedType(nd->rtype)) {
|
||||
nd->x16->upper = CInt64_ShrU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
|
||||
nd->x16->lower = CInt64_ShrU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
|
||||
} else {
|
||||
nd->x16->upper = CInt64_Shr(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
|
||||
nd->x16->lower = CInt64_Shr(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
|
||||
}
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EPOSTINC:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
range = nd->u.monadic->x16;
|
||||
*nd->x16 = *range;
|
||||
range->upper = CInt64_Add(range->upper, cint64_one);
|
||||
range->lower = CInt64_Add(range->lower, cint64_one);
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EPOSTDEC:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
range = nd->u.monadic->x16;
|
||||
*nd->x16 = *range;
|
||||
range->upper = CInt64_Sub(range->upper, cint64_one);
|
||||
range->lower = CInt64_Sub(range->lower, cint64_one);
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EPREINC:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
range = nd->u.monadic->x16;
|
||||
nd->x16->upper = CInt64_Add(range->upper, cint64_one);
|
||||
nd->x16->lower = CInt64_Add(range->lower, cint64_one);
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EPREDEC:
|
||||
if (IS_TYPE_INT(nd->rtype)) {
|
||||
if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
|
||||
nd->x16 = ERnewERange(ERangeType2);
|
||||
range = nd->u.monadic->x16;
|
||||
nd->x16->upper = CInt64_Sub(range->upper, cint64_one);
|
||||
nd->x16->lower = CInt64_Sub(range->lower, cint64_one);
|
||||
} else {
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
}
|
||||
}
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
case EMONMIN:
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
break;
|
||||
case EPMODULO:
|
||||
case EROTL:
|
||||
case EROTR:
|
||||
case EBCLR:
|
||||
case EBTST:
|
||||
case EBSET:
|
||||
nd->x16 = ERnewERange(ERangeType3);
|
||||
nd->x16->upper = cint64_max;
|
||||
nd->x16->lower = cint64_min;
|
||||
break;
|
||||
default:
|
||||
ERcheckOverflow(nd->x16, nd->rtype);
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
(nd->type == IROLinearOp1Arg || nd->type == IROLinearOp2Arg) &&
|
||||
IRO_IsAssignOp[nd->nodetype] &&
|
||||
nd->x16 &&
|
||||
IS_TYPE_INT(nd->rtype)
|
||||
) {
|
||||
IROLinear *x = NULL;
|
||||
if (nd->type == IROLinearOp2Arg)
|
||||
x = nd->u.diadic.left;
|
||||
else if (nd->type == IROLinearOp1Arg)
|
||||
x = nd->u.monadic;
|
||||
|
||||
if (x->type == IROLinearOp1Arg &&
|
||||
x->nodetype == EINDIRECT &&
|
||||
(x->u.monadic->nodetype == EINDIRECT || x->u.monadic->nodetype == EADD)) {
|
||||
SetRangesForKillsByIndirectAssignment(nd);
|
||||
} else {
|
||||
obj = NULL;
|
||||
if (x)
|
||||
obj = IRO_IsVariable(x);
|
||||
if (!obj)
|
||||
return 0;
|
||||
|
||||
range = nd->x16;
|
||||
if (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC)
|
||||
range = x->x16;
|
||||
|
||||
record = ERecordFound(obj);
|
||||
if (!record)
|
||||
ERnewRecord(obj, range);
|
||||
else
|
||||
record->range = range;
|
||||
}
|
||||
}
|
||||
|
||||
return nd->x16 != NULL;
|
||||
}
|
||||
|
||||
static Boolean ERfoldLinear(IROLinear *nd) {
|
||||
nd->x16 = 0;
|
||||
|
||||
switch (nd->type) {
|
||||
case IROLinearNop:
|
||||
case IROLinearEnd:
|
||||
break;
|
||||
case IROLinearOperand:
|
||||
ERfoldOperand(nd);
|
||||
break;
|
||||
case IROLinearOp1Arg:
|
||||
case IROLinearOp2Arg:
|
||||
ERfoldExpr(nd);
|
||||
break;
|
||||
case IROLinearFunccall:
|
||||
InvalidateRangesForKillsByFunctionCall(nd);
|
||||
break;
|
||||
case IROLinearAsm:
|
||||
ERinvalidAll();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Boolean IRO_RangePropagateInFNode(void) {
|
||||
IRONode *fnode;
|
||||
IROLinear *nd;
|
||||
Boolean result;
|
||||
|
||||
result = 0;
|
||||
|
||||
for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
|
||||
ERangeFirst = ERangeLast = NULL;
|
||||
for (nd = fnode->first; nd != fnode->last; nd = nd->next)
|
||||
ERfoldLinear(nd);
|
||||
if (ERfoldLinear(nd))
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
IRO_ComputeSuccPred();
|
||||
IRO_ComputeDom();
|
||||
}
|
||||
|
||||
IRO_CheckForUserBreak();
|
||||
return result;
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
#include "compiler/IroSubable.h"
|
||||
#include "compiler/IroLinearForm.h"
|
||||
#include "compiler/IroPropagate.h"
|
||||
#include "compiler/IroUtil.h"
|
||||
#include "compiler/enode.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/types.h"
|
||||
|
||||
static Boolean IsSubableOp[MAXEXPR];
|
||||
|
||||
void IRO_InitializeIsSubableOpArray(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXEXPR; i++)
|
||||
IsSubableOp[i] = 0;
|
||||
|
||||
IsSubableOp[EPOSTINC] = 0;
|
||||
IsSubableOp[EPOSTDEC] = 0;
|
||||
IsSubableOp[EPREINC] = 0;
|
||||
IsSubableOp[EPREDEC] = 0;
|
||||
IsSubableOp[EINDIRECT] = 0;
|
||||
IsSubableOp[EMONMIN] = 1;
|
||||
IsSubableOp[EBINNOT] = 1;
|
||||
IsSubableOp[ELOGNOT] = 1;
|
||||
IsSubableOp[EFORCELOAD] = 0;
|
||||
IsSubableOp[EMUL] = 1;
|
||||
IsSubableOp[EMULV] = 1;
|
||||
IsSubableOp[EDIV] = 1;
|
||||
IsSubableOp[EMODULO] = 1;
|
||||
IsSubableOp[EADDV] = 1;
|
||||
IsSubableOp[ESUBV] = 1;
|
||||
IsSubableOp[EADD] = 1;
|
||||
IsSubableOp[ESUB] = 1;
|
||||
IsSubableOp[ESHL] = 1;
|
||||
IsSubableOp[ESHR] = 1;
|
||||
IsSubableOp[ELESS] = 0;
|
||||
IsSubableOp[EGREATER] = 0;
|
||||
IsSubableOp[ELESSEQU] = 0;
|
||||
IsSubableOp[EGREATEREQU] = 0;
|
||||
IsSubableOp[EEQU] = 0;
|
||||
IsSubableOp[ENOTEQU] = 0;
|
||||
IsSubableOp[EAND] = 1;
|
||||
IsSubableOp[EXOR] = 1;
|
||||
IsSubableOp[EOR] = 1;
|
||||
IsSubableOp[ELAND] = 0;
|
||||
IsSubableOp[ELOR] = 0;
|
||||
IsSubableOp[EASS] = 0;
|
||||
IsSubableOp[EMULASS] = 0;
|
||||
IsSubableOp[EDIVASS] = 0;
|
||||
IsSubableOp[EMODASS] = 0;
|
||||
IsSubableOp[EADDASS] = 0;
|
||||
IsSubableOp[ESUBASS] = 0;
|
||||
IsSubableOp[ESHLASS] = 0;
|
||||
IsSubableOp[ESHRASS] = 0;
|
||||
IsSubableOp[EANDASS] = 0;
|
||||
IsSubableOp[EXORASS] = 0;
|
||||
IsSubableOp[EORASS] = 0;
|
||||
IsSubableOp[ECOMMA] = 0;
|
||||
IsSubableOp[EPMODULO] = 0;
|
||||
IsSubableOp[EROTL] = 0;
|
||||
IsSubableOp[EROTR] = 0;
|
||||
IsSubableOp[EBCLR] = 0;
|
||||
IsSubableOp[EBTST] = 0;
|
||||
IsSubableOp[EBSET] = 0;
|
||||
IsSubableOp[ETYPCON] = 0;
|
||||
IsSubableOp[EBITFIELD] = 0;
|
||||
IsSubableOp[EINTCONST] = 0;
|
||||
IsSubableOp[EFLOATCONST] = 0;
|
||||
IsSubableOp[ESTRINGCONST] = 0;
|
||||
IsSubableOp[ECOND] = 0;
|
||||
IsSubableOp[EFUNCCALL] = 0;
|
||||
IsSubableOp[EFUNCCALLP] = 0;
|
||||
IsSubableOp[EOBJREF] = 0;
|
||||
IsSubableOp[EMFPOINTER] = 0;
|
||||
IsSubableOp[ENULLCHECK] = 0;
|
||||
IsSubableOp[EPRECOMP] = 0;
|
||||
IsSubableOp[ETEMP] = 0;
|
||||
IsSubableOp[EARGOBJ] = 0;
|
||||
IsSubableOp[ELOCOBJ] = 0;
|
||||
IsSubableOp[ELABEL] = 0;
|
||||
IsSubableOp[ESETCONST] = 0;
|
||||
IsSubableOp[ENEWEXCEPTION] = 0;
|
||||
IsSubableOp[ENEWEXCEPTIONARRAY] = 0;
|
||||
IsSubableOp[EOBJLIST] = 0;
|
||||
IsSubableOp[EMEMBER] = 0;
|
||||
IsSubableOp[ETEMPLDEP] = 0;
|
||||
IsSubableOp[EINSTRUCTION] = 0;
|
||||
IsSubableOp[EDEFINE] = 0;
|
||||
IsSubableOp[EREUSE] = 0;
|
||||
IsSubableOp[EASSBLK] = 0;
|
||||
IsSubableOp[EVECTOR128CONST] = 0;
|
||||
IsSubableOp[ECONDASS] = 0;
|
||||
}
|
||||
|
||||
static int IsSubscript(IROLinear *nd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Boolean IRO_IsSubableExpression(IROLinear *nd) {
|
||||
Object *varobj;
|
||||
Boolean result;
|
||||
|
||||
switch (nd->type) {
|
||||
case IROLinearOp2Arg:
|
||||
if (nd->nodetype == EADD || nd->nodetype == ESUB) {
|
||||
if (
|
||||
IRO_IsConstant(nd->u.diadic.right) &&
|
||||
(varobj = IRO_IsVariable(nd->u.diadic.left)) &&
|
||||
varobj->datatype == DLOCAL &&
|
||||
varobj->u.var.info &&
|
||||
!varobj->u.var.info->noregister)
|
||||
return 0;
|
||||
|
||||
}
|
||||
result = IsSubableOp[nd->nodetype] && !IsSubscript(nd);
|
||||
return result;
|
||||
case IROLinearOp1Arg:
|
||||
if (IsSubableOp[nd->nodetype] && !IsSubscript(nd))
|
||||
return 1;
|
||||
|
||||
if (nd->nodetype == EINDIRECT && !(nd->flags & IROLF_Assigned)) {
|
||||
if (nd->flags & IROLF_Ind) {
|
||||
nd = nd->u.monadic;
|
||||
if (nd->type == IROLinearOperand &&
|
||||
nd->u.node->type == EOBJREF &&
|
||||
nd->u.node->data.objref->datatype == DLOCAL &&
|
||||
nd->u.node->data.objref->u.var.info &&
|
||||
!nd->u.node->data.objref->u.var.info->noregister
|
||||
)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (IRO_IsVariable(nd) && IRO_IsRegable(nd->u.monadic->u.node->data.objref))
|
||||
return 0;
|
||||
return 1;
|
||||
} else if (nd->nodetype == ETYPCON && IS_TYPE_INT(nd->rtype) && nd->rtype->size >= nd->u.monadic->rtype->size) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
case IROLinearOperand:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Boolean IRO_IsVectorTempCandidate(IROLinear *nd) {
|
||||
return
|
||||
(
|
||||
nd->type == IROLinearOp1Arg ||
|
||||
nd->type == IROLinearOp2Arg ||
|
||||
nd->type == IROLinearOp3Arg ||
|
||||
nd->type == IROLinearOperand ||
|
||||
nd->type == IROLinearFunccall
|
||||
) && (
|
||||
(nd->flags & IROLF_LoopInvariant) &&
|
||||
!(nd->flags & IROLF_Ind)
|
||||
);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
#include "compiler/IroTransform.h"
|
||||
|
||||
// TODO
|
@ -0,0 +1,95 @@
|
||||
#include "compiler/IroUnrollLoop.h"
|
||||
#include "compiler/IroUtil.h"
|
||||
|
||||
// forward decls
|
||||
static void IRO_FindLoops_Unroll(void);
|
||||
|
||||
void IRO_LoopUnroller(void) {
|
||||
VectorPhaseCalledFromUnroll = 1;
|
||||
IRO_FindLoops_Unroll();
|
||||
IRO_CheckForUserBreak();
|
||||
}
|
||||
|
||||
static void IRO_FindLoops_Unroll(void) {
|
||||
}
|
||||
|
||||
static void CheckConstant() {
|
||||
}
|
||||
|
||||
static void UnrollWhileLoopBody() {
|
||||
}
|
||||
|
||||
static void PatternMatchLoop() {
|
||||
}
|
||||
|
||||
static void UnrollWhileLoop() {
|
||||
}
|
||||
|
||||
void IRO_IterateForLoopBody() {
|
||||
}
|
||||
|
||||
void IRO_LinearizeForLoopPostLoop() {
|
||||
}
|
||||
|
||||
static void UnrollForLoop() {
|
||||
}
|
||||
|
||||
static void UnrollStandardLoop() {
|
||||
}
|
||||
|
||||
static void LoopUnroll() {
|
||||
}
|
||||
|
||||
static void IsLoopUnrollable() {
|
||||
}
|
||||
|
||||
void BuildEarlyLoopExitTest() {
|
||||
}
|
||||
|
||||
void BuildLoopExitTest() {
|
||||
}
|
||||
|
||||
void IsIterationCountConstant() {
|
||||
}
|
||||
|
||||
static void IsDifferenceOfTermsConstant() {
|
||||
}
|
||||
|
||||
void NoOpBlock() {
|
||||
}
|
||||
|
||||
void IRO_TestConstantIterationCount() {
|
||||
}
|
||||
|
||||
void BuildOrigIterationCount() {
|
||||
}
|
||||
|
||||
static void BuildOrigIterationCount_DoWhile() {
|
||||
}
|
||||
|
||||
void BuildNewFinalvalue() {
|
||||
}
|
||||
|
||||
static void BuildPreAlignTemp() {
|
||||
}
|
||||
|
||||
static void BuildNewFinalvalue_DoWhile() {
|
||||
}
|
||||
|
||||
static void BuildUnrolledFinalvalue_DoWhile() {
|
||||
}
|
||||
|
||||
void BuildUnrolledBodyEntryTest() {
|
||||
}
|
||||
|
||||
void ChangeInductionReference() {
|
||||
}
|
||||
|
||||
void UpdateInductionIncrement() {
|
||||
}
|
||||
|
||||
void GenInitialAssignment() {
|
||||
}
|
||||
|
||||
void GenNewInduction() {
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
167
compiler_and_linker/unsorted/LiveInfo.c
Normal file
167
compiler_and_linker/unsorted/LiveInfo.c
Normal file
@ -0,0 +1,167 @@
|
||||
#include "compiler/LiveInfo.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/Coloring.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/Registers.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/types.h"
|
||||
#include "compiler/CParser.h"
|
||||
|
||||
LiveInfo *liveinfo;
|
||||
|
||||
static void allocateliveinfo(void) {
|
||||
UInt32 regs;
|
||||
LiveInfo *info;
|
||||
int i;
|
||||
|
||||
regs = used_virtual_registers[coloring_class];
|
||||
|
||||
liveinfo = oalloc(sizeof(LiveInfo) * pcblockcount);
|
||||
for (i = 0, info = liveinfo; i < pcblockcount; i++, info++) {
|
||||
bitvectorinitialize(info->vec0 = oalloc(4 * ((regs + 31) >> 5)), regs, 0);
|
||||
bitvectorinitialize(info->vec4 = oalloc(4 * ((regs + 31) >> 5)), regs, 0);
|
||||
bitvectorinitialize(info->vec8 = oalloc(4 * ((regs + 31) >> 5)), regs, 0);
|
||||
bitvectorinitialize(info->vecC = oalloc(4 * ((regs + 31) >> 5)), regs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void computelocalusedef(void) {
|
||||
LiveInfo *info;
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
UInt32 *vec0;
|
||||
UInt32 *vec4;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
info = &liveinfo[block->blockIndex];
|
||||
vec0 = info->vec0;
|
||||
vec4 = info->vec4;
|
||||
|
||||
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == coloring_class &&
|
||||
(op->data.reg.effect & EffectRead) &&
|
||||
!bitvectorgetbit(op->data.reg.reg, vec4)
|
||||
)
|
||||
bitvectorsetbit(op->data.reg.reg, vec0);
|
||||
op++;
|
||||
}
|
||||
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == coloring_class &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
!bitvectorgetbit(op->data.reg.reg, vec0)
|
||||
)
|
||||
bitvectorsetbit(op->data.reg.reg, vec4);
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void computeglobalinout(void) {
|
||||
UInt32 regs;
|
||||
LiveInfo *info;
|
||||
UInt32 *vec0;
|
||||
UInt32 *vec4;
|
||||
UInt32 *vec8;
|
||||
UInt32 *vecC;
|
||||
int bitvecsize;
|
||||
int blockIndex;
|
||||
int i;
|
||||
int flag;
|
||||
PCodeBlock *block;
|
||||
PCLink *link;
|
||||
UInt32 val;
|
||||
|
||||
regs = used_virtual_registers[coloring_class];
|
||||
bitvecsize = (regs + 31) >> 5;
|
||||
flag = 1;
|
||||
while (flag) {
|
||||
flag = 0;
|
||||
blockIndex = pcblockcount;
|
||||
while (blockIndex) {
|
||||
if ((block = depthfirstordering[--blockIndex])) {
|
||||
info = &liveinfo[block->blockIndex];
|
||||
if ((link = block->successors)) {
|
||||
vecC = info->vecC;
|
||||
bitvectorcopy(vecC, liveinfo[link->block->blockIndex].vec8, regs);
|
||||
for (link = link->nextLink; link; link = link->nextLink)
|
||||
bitvectorunion(vecC, liveinfo[link->block->blockIndex].vec8, regs);
|
||||
}
|
||||
|
||||
vecC = info->vecC;
|
||||
vec8 = info->vec8;
|
||||
vec0 = info->vec0;
|
||||
vec4 = info->vec4;
|
||||
for (i = 0; i < bitvecsize; i++) {
|
||||
val = *vec0 | (*vecC & ~*vec4);
|
||||
if (val != *vec8) {
|
||||
*vec8 = val;
|
||||
flag = 1;
|
||||
}
|
||||
vec8++;
|
||||
vecC++;
|
||||
vec0++;
|
||||
vec4++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void computelivevariables(Object *proc) {
|
||||
Type *returnType;
|
||||
|
||||
returnType = TYPE_FUNC(proc->type)->functype;
|
||||
computedepthfirstordering();
|
||||
allocateliveinfo();
|
||||
computelocalusedef();
|
||||
|
||||
if (coloring_class == RegClass_GPR && TYPE_FITS_IN_REGISTER(returnType)) {
|
||||
bitvectorsetbit(3, liveinfo[epilogue->blockIndex].vec0);
|
||||
if (TYPE_IS_8BYTES(returnType))
|
||||
bitvectorsetbit(4, liveinfo[pclastblock->blockIndex].vec0);
|
||||
} else if (coloring_class == RegClass_FPR && IS_TYPE_FLOAT(returnType)) {
|
||||
bitvectorsetbit(1, liveinfo[epilogue->blockIndex].vec0);
|
||||
} else if (coloring_class == RegClass_VR && IS_TYPE_VECTOR(returnType)) {
|
||||
bitvectorsetbit(2, liveinfo[epilogue->blockIndex].vec0);
|
||||
}
|
||||
|
||||
computeglobalinout();
|
||||
}
|
||||
|
||||
int dead(PCode *instr, char rclass, UInt32 *vec) {
|
||||
int i;
|
||||
PCodeArg *op;
|
||||
|
||||
if (instr->flags & (fPCodeFlag1 | fPCodeFlag4 | fPCodeFlag8 | fIsVolatile | fSideEffects))
|
||||
return 0;
|
||||
if (instr->block->flags & (fPCBlockFlag1 | fPCBlockFlag2))
|
||||
return 0;
|
||||
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
(rclass != (char) op->arg || bitvectorgetbit(op->data.reg.reg, vec))
|
||||
)
|
||||
return 0;
|
||||
op++;
|
||||
}
|
||||
|
||||
return copts.optimizationlevel > 0;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
#include "compiler/LoadDeletion.h"
|
||||
#include "compiler/CopyPropagation.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeInfo.h"
|
||||
|
||||
int deletedloads;
|
||||
|
||||
static int is_load(PCode *instr) {
|
||||
return
|
||||
(instr->op == PC_LI || instr->op == PC_VSPLTISB || instr->op == PC_VSPLTISH || instr->op == PC_VSPLTISW)
|
||||
&&
|
||||
instr->args[0].data.reg.reg >= n_real_registers[(char) instr->args[0].arg];
|
||||
}
|
||||
|
||||
static int loadpropagatestouse(int candidateID, int useID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void deleteload(int id) {
|
||||
Candidate *candidate;
|
||||
|
||||
candidate = Candidates + id;
|
||||
if (candidate->list || (candidate->pcode->flags & fSideEffects))
|
||||
return;
|
||||
if (candidate->pcode->args[0].data.reg.reg < n_real_registers[(char) candidate->pcode->args[0].arg])
|
||||
return;
|
||||
|
||||
deletepcode(candidate->pcode);
|
||||
deletedloads = 1;
|
||||
}
|
||||
|
||||
static Propagation load_immediate_prop = {
|
||||
&is_load,
|
||||
&loadpropagatestouse,
|
||||
&deleteload,
|
||||
"LOAD IMMEDIATE",
|
||||
"LOAD_IMMEDIATES",
|
||||
"l%ld",
|
||||
0
|
||||
};
|
||||
|
||||
void deletedeadloads(Object *proc) {
|
||||
propagateinstructions(proc, &load_immediate_prop, (copts.optimizationlevel >= 4) ? 4 : 1, 0);
|
||||
deletedloads = propagated_instructions;
|
||||
}
|
@ -0,0 +1,889 @@
|
||||
#include "compiler/LoopDetection.h"
|
||||
#include "compiler/CFunc.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/TOC.h"
|
||||
#include "compiler/UseDefChains.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/enode.h"
|
||||
#include "compiler/objects.h"
|
||||
|
||||
Loop *loopsinflowgraph;
|
||||
int loopdetection_nblocks;
|
||||
static UInt32 **dominators;
|
||||
static BlockList *loopheaders;
|
||||
static int nloopheaders;
|
||||
static PCodeBlock **loopstack;
|
||||
BitVector *LoopTemp;
|
||||
void *LoopList_First;
|
||||
|
||||
static void computedominators(void) {
|
||||
int i;
|
||||
PCodeBlock *block;
|
||||
int blockCount;
|
||||
int flag;
|
||||
UInt32 *myvec;
|
||||
PCLink *link;
|
||||
|
||||
blockCount = pcblockcount;
|
||||
flag = 1;
|
||||
|
||||
dominators = oalloc(sizeof(UInt32 *) * pcblockcount);
|
||||
for (i = 0; i < pcblockcount; i++)
|
||||
dominators[i] = oalloc(4 * ((blockCount + 31) >> 5));
|
||||
|
||||
myvec = oalloc(4 * ((blockCount + 31) >> 5));
|
||||
|
||||
bitvectorinitialize(dominators[pcbasicblocks->blockIndex], blockCount, 0);
|
||||
//dominators[pcbasicblocks->blockIndex][0] |= 1;
|
||||
bitvectorsetbit(0, dominators[pcbasicblocks->blockIndex]);
|
||||
|
||||
for (block = pcbasicblocks->nextBlock; block; block = block->nextBlock)
|
||||
bitvectorinitialize(dominators[block->blockIndex], blockCount, 0xFFFFFFFF);
|
||||
|
||||
computedepthfirstordering();
|
||||
|
||||
while (flag) {
|
||||
flag = 0;
|
||||
for (i = 0; i < pcblockcount; i++) {
|
||||
block = depthfirstordering[i];
|
||||
if (block && block->blockIndex != pcbasicblocks->blockIndex) {
|
||||
bitvectorcopy(myvec, dominators[block->predecessors->block->blockIndex], blockCount);
|
||||
for (link = block->predecessors->nextLink; link; link = link->nextLink)
|
||||
bitvectorintersect(myvec, dominators[link->block->blockIndex], blockCount);
|
||||
//myvec[block->blockIndex >> 5] |= 1 << (block->blockIndex & 31);
|
||||
bitvectorsetbit(block->blockIndex, myvec);
|
||||
|
||||
if (bitvectorchanged(dominators[block->blockIndex], myvec, blockCount))
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BlockList *findloopheaders(void) {
|
||||
PCodeBlock *block;
|
||||
PCLink *link;
|
||||
BlockList *list;
|
||||
|
||||
loopheaders = NULL;
|
||||
nloopheaders = 0;
|
||||
|
||||
for (block = pcbasicblocks->nextBlock; block; block = block->nextBlock) {
|
||||
for (link = block->predecessors; link; link = link->nextLink) {
|
||||
//if ((1 << (block->blockIndex & 31)) & dominators[link->block->blockIndex][block->blockIndex >> 5])
|
||||
if (bitvectorgetbit(block->blockIndex, dominators[link->block->blockIndex]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (link) {
|
||||
list = oalloc(sizeof(BlockList));
|
||||
list->block = block;
|
||||
list->next = loopheaders;
|
||||
loopheaders = list;
|
||||
nloopheaders++;
|
||||
}
|
||||
}
|
||||
|
||||
return loopheaders;
|
||||
}
|
||||
|
||||
void addblocktoloop(Loop *loop, PCodeBlock *block) {
|
||||
BlockList *list = lalloc(sizeof(BlockList));
|
||||
|
||||
//loop->memberblocks[block->blockIndex >> 5] |= 1 << (block->blockIndex & 31);
|
||||
bitvectorsetbit(block->blockIndex, loop->memberblocks);
|
||||
|
||||
list->block = block;
|
||||
list->next = loop->blocks;
|
||||
loop->blocks = list;
|
||||
}
|
||||
|
||||
static void findnaturalloop(Loop *loop) {
|
||||
BlockList *list;
|
||||
BlockList *list2;
|
||||
PCLink *link;
|
||||
PCodeBlock *block;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
addblocktoloop(loop, loop->body);
|
||||
for (link = loop->body->predecessors; link; link = link->nextLink) {
|
||||
if (bitvectorgetbit(loop->body->blockIndex, dominators[link->block->blockIndex]) && link->block != loop->body) {
|
||||
addblocktoloop(loop, link->block);
|
||||
loopstack[i++] = link->block;
|
||||
}
|
||||
}
|
||||
|
||||
while (i) {
|
||||
link = loopstack[--i]->predecessors;
|
||||
while (link) {
|
||||
if (!bitvectorgetbit(link->block->blockIndex, loop->memberblocks)) {
|
||||
addblocktoloop(loop, link->block);
|
||||
loopstack[i++] = link->block;
|
||||
}
|
||||
link = link->nextLink;
|
||||
}
|
||||
}
|
||||
|
||||
for (list = loop->blocks; list; list = list->next) {
|
||||
block = list->block;
|
||||
for (link = block->successors; link; link = link->nextLink) {
|
||||
if (!bitvectorgetbit(link->block->blockIndex, loop->memberblocks)) {
|
||||
bitvectorsetbit(block->blockIndex, loop->vec24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (list = loop->blocks; list; list = list->next) {
|
||||
for (list2 = loop->blocks; list2; list2 = list2->next) {
|
||||
if (bitvectorgetbit(list2->block->blockIndex, loop->vec24) &&
|
||||
!bitvectorgetbit(list->block->blockIndex, dominators[list2->block->blockIndex]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!list2)
|
||||
bitvectorsetbit(list->block->blockIndex, loop->vec28);
|
||||
}
|
||||
|
||||
for (list = loop->blocks; list; list = list->next) {
|
||||
for (link = loop->body->predecessors; link; link = link->nextLink) {
|
||||
if (bitvectorgetbit(link->block->blockIndex, loop->memberblocks) &&
|
||||
!bitvectorgetbit(list->block->blockIndex, dominators[link->block->blockIndex]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!link)
|
||||
bitvectorsetbit(list->block->blockIndex, loop->vec2C);
|
||||
}
|
||||
}
|
||||
|
||||
static void addlooptolist(Loop *loop, Loop **list) {
|
||||
Loop **scan;
|
||||
Loop *scanloop;
|
||||
|
||||
scan = list;
|
||||
while ((scanloop = *scan)) {
|
||||
if (bitvectorgetbit(loop->body->blockIndex, scanloop->memberblocks)) {
|
||||
loop->parent = scanloop;
|
||||
addlooptolist(loop, &scanloop->children);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bitvectorgetbit(scanloop->body->blockIndex, loop->memberblocks)) {
|
||||
*scan = scanloop->nextSibling;
|
||||
scanloop->parent = loop;
|
||||
scanloop->nextSibling = loop->children;
|
||||
loop->children = scanloop;
|
||||
} else {
|
||||
scan = &scanloop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
loop->nextSibling = *list;
|
||||
*list = loop;
|
||||
}
|
||||
|
||||
static void findnaturalloops(void) {
|
||||
Loop *loop;
|
||||
int size;
|
||||
|
||||
loopdetection_nblocks = pcblockcount + 5 * nloopheaders;
|
||||
loopstack = oalloc(sizeof(PCodeBlock *) * pcblockcount);
|
||||
while (loopheaders) {
|
||||
loop = lalloc(sizeof(Loop));
|
||||
loop->parent = loop->nextSibling = loop->children = NULL;
|
||||
loop->body = loopheaders->block;
|
||||
loop->preheader = NULL;
|
||||
loop->blocks = NULL;
|
||||
loop->basicInductionVars = NULL;
|
||||
loop->footer = NULL;
|
||||
loop->pc18 = NULL;
|
||||
loop->loopWeight = loop->body->loopWeight;
|
||||
|
||||
bitvectorinitialize(loop->memberblocks = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
||||
bitvectorinitialize(loop->vec24 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
||||
bitvectorinitialize(loop->vec28 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
||||
bitvectorinitialize(loop->vec2C = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
||||
|
||||
findnaturalloop(loop);
|
||||
addlooptolist(loop, &loopsinflowgraph);
|
||||
|
||||
loopheaders = loopheaders->next;
|
||||
}
|
||||
}
|
||||
|
||||
static PCodeBlock *makepreheaderblock(void) {
|
||||
PCodeLabel *label;
|
||||
PCodeBlock *block;
|
||||
|
||||
label = makepclabel();
|
||||
block = lalloc(sizeof(PCodeBlock));
|
||||
block->nextBlock = NULL;
|
||||
block->prevBlock = NULL;
|
||||
block->labels = NULL;
|
||||
block->successors = NULL;
|
||||
block->predecessors = NULL;
|
||||
block->firstPCode = block->lastPCode = NULL;
|
||||
block->pcodeCount = 0;
|
||||
block->flags = 0;
|
||||
block->blockIndex = pcblockcount++;
|
||||
pclabel(block, label);
|
||||
return block;
|
||||
}
|
||||
|
||||
static void insertpreheaderbefore(PCodeBlock *a, PCodeBlock *b) {
|
||||
a->nextBlock = b;
|
||||
a->prevBlock = b->prevBlock;
|
||||
b->prevBlock->nextBlock = a;
|
||||
b->prevBlock = a;
|
||||
}
|
||||
|
||||
void insertpreheaderblock(Loop *loop) {
|
||||
PCodeBlock *preheader;
|
||||
PCodeBlock *block29;
|
||||
PCodeBlock *block28;
|
||||
PCode *pcode27;
|
||||
PCLink *link; // r26
|
||||
PCLink **linkptr; // r25
|
||||
PCodeLabel *newlabel; // r23
|
||||
PCLink *innerlink;
|
||||
PCodeBlock *block;
|
||||
PCodeArg *arg;
|
||||
int i;
|
||||
|
||||
preheader = loop->preheader = makepreheaderblock();
|
||||
block29 = NULL;
|
||||
block28 = loop->body;
|
||||
|
||||
if (!block28->labels)
|
||||
pclabel(block28, makepclabel());
|
||||
|
||||
appendpcode(preheader, makepcode(PC_B, block28->labels));
|
||||
preheader->loopWeight = loop->parent ? loop->parent->loopWeight : 1;
|
||||
|
||||
linkptr = &block28->predecessors;
|
||||
while ((link = *linkptr)) {
|
||||
if (bitvectorgetbit(link->block->blockIndex, loop->memberblocks)) {
|
||||
linkptr = &link->nextLink;
|
||||
} else {
|
||||
if (link->block->pcodeCount) {
|
||||
pcode27 = link->block->lastPCode;
|
||||
if (pcode27->op == PC_B) {
|
||||
#line 462
|
||||
CError_ASSERT(pcode27->args[0].kind == PCOp_LABEL);
|
||||
if (pcode27->args[0].data.label.label->block == block28)
|
||||
pcode27->args[0].data.label.label = preheader->labels;
|
||||
} else if (pcode27->op == PC_BT || pcode27->op == PC_BF) {
|
||||
#line 474
|
||||
CError_ASSERT(pcode27->args[2].kind == PCOp_LABEL);
|
||||
if (pcode27->args[2].data.label.label->block == block28)
|
||||
pcode27->args[2].data.label.label = preheader->labels;
|
||||
} else if (pcode27->op == PC_BCTR) {
|
||||
if (pcode27->argCount > 1 && pcode27->args[1].kind == PCOp_MEMORY) {
|
||||
Object *obj = pcode27->args[1].data.mem.obj;
|
||||
PCodeLabel **array = (PCodeLabel **) obj->u.data.u.switchtable.data;
|
||||
int i;
|
||||
for (i = 0; i < obj->u.data.u.switchtable.size; i++) {
|
||||
if (array[i]->block == block28)
|
||||
array[i] = preheader->labels;
|
||||
}
|
||||
} else {
|
||||
CodeLabelList *cll;
|
||||
for (cll = codelabellist; cll; cll = cll->next) {
|
||||
if (cll->label->pclabel->block == block28)
|
||||
cll->label->pclabel = preheader->labels;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#line 505
|
||||
CError_ASSERT(link->block->nextBlock == block28);
|
||||
}
|
||||
}
|
||||
|
||||
for (innerlink = link->block->successors; innerlink; innerlink = innerlink->nextLink) {
|
||||
if (innerlink->block == block28)
|
||||
innerlink->block = preheader;
|
||||
}
|
||||
|
||||
*linkptr = link->nextLink;;
|
||||
link->nextLink = preheader->predecessors;
|
||||
preheader->predecessors = link;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bitvectorgetbit(block28->prevBlock->blockIndex, loop->memberblocks)) {
|
||||
insertpreheaderbefore(preheader, block28);
|
||||
|
||||
if (
|
||||
(!block28->nextBlock || !bitvectorgetbit(block28->nextBlock->blockIndex, loop->memberblocks)) &&
|
||||
block28->lastPCode &&
|
||||
(block28->lastPCode->flags & fPCodeFlag1) &&
|
||||
block28->lastPCode->op != PC_BDNZ
|
||||
) {
|
||||
i = block28->lastPCode->argCount;
|
||||
arg = block28->lastPCode->args;
|
||||
while (i && arg->kind != PCOp_LABEL) {
|
||||
arg++;
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i && arg->kind == PCOp_LABEL && arg->data.label.label->block == block28) {
|
||||
block29 = makepreheaderblock();
|
||||
insertpreheaderbefore(block29, block28);
|
||||
newlabel = makepclabel();
|
||||
pclabel(block29, newlabel);
|
||||
arg->data.label.label = newlabel;
|
||||
|
||||
link = lalloc(sizeof(PCLink));
|
||||
link->block = block28;
|
||||
link->nextLink = block29->predecessors;
|
||||
block29->predecessors = link;
|
||||
|
||||
link = lalloc(sizeof(PCLink));
|
||||
link->block = block28;
|
||||
link->nextLink = block29->successors;
|
||||
block29->successors = link;
|
||||
|
||||
for (link = block28->successors; link; link = link->nextLink) {
|
||||
if (link->block == block28)
|
||||
link->block = block29;
|
||||
}
|
||||
for (link = block28->predecessors; link; link = link->nextLink) {
|
||||
if (link->block == block28)
|
||||
link->block = block29;
|
||||
}
|
||||
|
||||
bitvectorsetbit(block29->blockIndex, loop->vec2C);
|
||||
addblocktoloop(loop, block29);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
if (bitvectorgetbit(block->blockIndex, loop->memberblocks))
|
||||
break;
|
||||
}
|
||||
insertpreheaderbefore(preheader, block);
|
||||
}
|
||||
|
||||
link = lalloc(sizeof(PCLink));
|
||||
link->block = preheader;
|
||||
link->nextLink = block28->predecessors;
|
||||
block28->predecessors = link;
|
||||
|
||||
link = lalloc(sizeof(PCLink));
|
||||
link->block = block28;
|
||||
link->nextLink = preheader->successors;
|
||||
preheader->successors = link;
|
||||
|
||||
for (loop = loop->parent; loop; loop = loop->parent) {
|
||||
addblocktoloop(loop, preheader);
|
||||
if (bitvectorgetbit(block28->blockIndex, loop->vec28)) {
|
||||
bitvectorsetbit(preheader->blockIndex, loop->vec28);
|
||||
if (block29)
|
||||
bitvectorsetbit(block29->blockIndex, loop->vec28);
|
||||
}
|
||||
if (bitvectorgetbit(block28->blockIndex, loop->vec2C)) {
|
||||
bitvectorsetbit(preheader->blockIndex, loop->vec2C);
|
||||
if (block29)
|
||||
bitvectorsetbit(block29->blockIndex, loop->vec2C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void insertpreheaderblocks(Loop *loop) {
|
||||
while (loop) {
|
||||
if (loop->children)
|
||||
insertpreheaderblocks(loop->children);
|
||||
insertpreheaderblock(loop);
|
||||
loop = loop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
void findloopsinflowgraph(void) {
|
||||
loopsinflowgraph = NULL;
|
||||
computedominators();
|
||||
if (findloopheaders()) {
|
||||
findnaturalloops();
|
||||
insertpreheaderblocks(loopsinflowgraph);
|
||||
}
|
||||
freeoheap();
|
||||
}
|
||||
|
||||
static int checklooplimits(SInt32 opcode, SInt32 condition, SInt32 c, SInt32 d, SInt32 addend, SInt32 *result) {
|
||||
if (opcode == PC_BT) {
|
||||
if (condition == 0) {
|
||||
if (addend <= 0)
|
||||
return 0;
|
||||
if (c < d)
|
||||
*result = (d - c + addend - 1) / addend;
|
||||
else
|
||||
*result = 0;
|
||||
} else if (condition == 1) {
|
||||
if (addend >= 0)
|
||||
return 0;
|
||||
if (c > d)
|
||||
*result = (c - d - addend - 1) / -addend;
|
||||
else
|
||||
*result = 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (condition == 0) {
|
||||
if (addend >= 0)
|
||||
return 0;
|
||||
if (c >= d)
|
||||
*result = (c - d - addend) / -addend;
|
||||
else
|
||||
*result = 0;
|
||||
} else if (condition == 1) {
|
||||
if (addend <= 0)
|
||||
return 0;
|
||||
if (c <= d)
|
||||
*result = (d - c + addend) / addend;
|
||||
else
|
||||
*result = 0;
|
||||
} else if (c < d) {
|
||||
if (addend <= 0)
|
||||
return 0;
|
||||
if ((d - c) % addend)
|
||||
return 0;
|
||||
*result = (d - c) / addend;
|
||||
} else if (c > d) {
|
||||
if (addend >= 0)
|
||||
return 0;
|
||||
if ((c - d) % -addend)
|
||||
return 0;
|
||||
*result = (c - d) / -addend;
|
||||
} else {
|
||||
*result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int checkunsignedlooplimits(SInt32 opcode, SInt32 condition, UInt32 c, UInt32 d, SInt32 addend, UInt32 *result) {
|
||||
if (opcode == PC_BT) {
|
||||
if (condition == 0) {
|
||||
if (addend <= 0)
|
||||
return 0;
|
||||
if (c < d)
|
||||
*result = (d - c + addend - 1) / addend;
|
||||
else
|
||||
*result = 0;
|
||||
} else if (condition == 1) {
|
||||
if (addend >= 0)
|
||||
return 0;
|
||||
if (c > d)
|
||||
*result = (c - d - addend - 1) / -addend;
|
||||
else
|
||||
*result = 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (condition == 0) {
|
||||
if (addend >= 0)
|
||||
return 0;
|
||||
if (c >= d)
|
||||
*result = (c - d - addend) / -addend;
|
||||
else
|
||||
*result = 0;
|
||||
} else if (condition == 1) {
|
||||
if (addend <= 0)
|
||||
return 0;
|
||||
if (c <= d)
|
||||
*result = (d - c + addend) / addend;
|
||||
else
|
||||
*result = 0;
|
||||
} else if (c < d) {
|
||||
if (addend <= 0)
|
||||
return 0;
|
||||
if ((d - c) % addend)
|
||||
return 0;
|
||||
*result = (d - c) / addend;
|
||||
} else if (c > d) {
|
||||
if (addend >= 0)
|
||||
return 0;
|
||||
if ((c - d) % -addend)
|
||||
return 0;
|
||||
*result = (c - d) / -addend;
|
||||
} else {
|
||||
*result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (*result & 0x80000000) == 0;
|
||||
}
|
||||
|
||||
static int checkunknownloop(int a, int b, int c, unsigned char *op) {
|
||||
if (a == PC_BT) {
|
||||
if (b == 0) {
|
||||
if (c <= 0)
|
||||
return 0;
|
||||
*op = ELESS;
|
||||
} else if (b == 1) {
|
||||
if (c >= 0)
|
||||
return 0;
|
||||
*op = EGREATER;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (b == 0) {
|
||||
if (c >= 0)
|
||||
return 0;
|
||||
*op = EGREATEREQU;
|
||||
} else if (b == 1) {
|
||||
if (c <= 0)
|
||||
return 0;
|
||||
*op = ELESSEQU;
|
||||
} else if (c == 1) {
|
||||
*op = ENOTEQU;
|
||||
} else if (c == -1) {
|
||||
*op = ENOTEQU;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void checkcountingloop(Loop *loop) {
|
||||
RegUseOrDef *list;
|
||||
PCode *lastpcode;
|
||||
PCode *prevpcode;
|
||||
PCode *pc8;
|
||||
PCode *check;
|
||||
short op12;
|
||||
short reg11;
|
||||
SInt16 reg4;
|
||||
short reg11b;
|
||||
Loop *child;
|
||||
|
||||
if (!(lastpcode = loop->body->lastPCode))
|
||||
return;
|
||||
if (lastpcode->op != PC_BT && lastpcode->op != PC_BF)
|
||||
return;
|
||||
if (lastpcode->args[2].kind != PCOp_LABEL)
|
||||
return;
|
||||
|
||||
if (!bitvectorgetbit(lastpcode->args[2].data.label.label->block->blockIndex, loop->memberblocks))
|
||||
return;
|
||||
if (bitvectorgetbit(loop->body->nextBlock->blockIndex, loop->memberblocks))
|
||||
return;
|
||||
|
||||
reg11 = lastpcode->args[0].data.reg.reg;
|
||||
reg4 = lastpcode->args[1].data.imm.value;
|
||||
prevpcode = lastpcode->prevPCode;
|
||||
if (!prevpcode)
|
||||
return;
|
||||
|
||||
op12 = prevpcode->op;
|
||||
if (op12 == PC_ADDI && prevpcode->args[2].kind == PCOp_IMMEDIATE) {
|
||||
pc8 = prevpcode;
|
||||
prevpcode = prevpcode->prevPCode;
|
||||
if (!prevpcode)
|
||||
return;
|
||||
|
||||
op12 = prevpcode->op;
|
||||
if (pc8->args[0].data.reg.reg != pc8->args[1].data.reg.reg)
|
||||
return;
|
||||
if (op12 != PC_CMP && op12 != PC_CMPL && op12 != PC_CMPI && op12 != PC_CMPLI)
|
||||
return;
|
||||
if (prevpcode->args[1].data.reg.reg == pc8->args[0].data.reg.reg)
|
||||
return;
|
||||
if ((loop->step = pc8->args[2].data.imm.value) == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (op12 != PC_CMP && op12 != PC_CMPL && op12 != PC_CMPI && op12 != PC_CMPLI)
|
||||
return;
|
||||
|
||||
if (prevpcode->args[0].data.reg.reg != reg11)
|
||||
return;
|
||||
|
||||
reg11b = prevpcode->args[1].data.reg.reg;
|
||||
if (reg11b < 32)
|
||||
return;
|
||||
|
||||
if (loop->preheader->nextBlock != lastpcode->args[2].data.label.label->block)
|
||||
return;
|
||||
|
||||
if (op12 == PC_CMPI) {
|
||||
if (prevpcode->prevPCode)
|
||||
return;
|
||||
loop->upper = prevpcode->args[2].data.imm.value;
|
||||
loop->upperType = LOOP_BOUND_CONSTANT;
|
||||
} else if (op12 == PC_CMPLI) {
|
||||
if (prevpcode->prevPCode)
|
||||
return;
|
||||
loop->upper = prevpcode->args[2].data.imm.value & 0xFFFF;
|
||||
loop->upperType = LOOP_BOUND_CONSTANT;
|
||||
} else if (op12 == PC_CMP || op12 == PC_CMPL) {
|
||||
if (prevpcode->prevPCode) {
|
||||
if (
|
||||
prevpcode->prevPCode->op == PC_LI &&
|
||||
prevpcode->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
|
||||
prevpcode->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg &&
|
||||
!prevpcode->prevPCode->prevPCode
|
||||
) {
|
||||
loop->upper = prevpcode->prevPCode->args[1].data.imm.value;
|
||||
loop->upperType = LOOP_BOUND_CONSTANT;
|
||||
} else if (
|
||||
prevpcode->prevPCode->op == PC_LIS &&
|
||||
prevpcode->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
|
||||
prevpcode->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg &&
|
||||
!prevpcode->prevPCode->prevPCode
|
||||
) {
|
||||
loop->upper = prevpcode->prevPCode->args[1].data.imm.value << 16;
|
||||
loop->upperType = LOOP_BOUND_CONSTANT;
|
||||
} else if (
|
||||
prevpcode->prevPCode->op == PC_ADDI &&
|
||||
prevpcode->prevPCode->args[2].kind == PCOp_IMMEDIATE &&
|
||||
prevpcode->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg &&
|
||||
prevpcode->prevPCode->args[1].data.reg.reg == prevpcode->args[2].data.reg.reg &&
|
||||
prevpcode->prevPCode->prevPCode &&
|
||||
prevpcode->prevPCode->prevPCode->op == PC_LIS &&
|
||||
prevpcode->prevPCode->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
|
||||
prevpcode->prevPCode->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg &&
|
||||
!prevpcode->prevPCode->prevPCode->prevPCode
|
||||
) {
|
||||
loop->upper = prevpcode->prevPCode->args[2].data.imm.value +
|
||||
(prevpcode->prevPCode->prevPCode->args[1].data.imm.value << 16);
|
||||
loop->upperType = LOOP_BOUND_CONSTANT;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
pc8 = NULL;
|
||||
for (list = reg_Defs[RegClass_GPR][prevpcode->args[2].data.reg.reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks))
|
||||
return;
|
||||
}
|
||||
for (list = reg_Defs[RegClass_GPR][prevpcode->args[2].data.reg.reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].defvec8)) {
|
||||
if (!pc8) {
|
||||
pc8 = Defs[list->id].pcode;
|
||||
if (
|
||||
pc8->op == PC_LI &&
|
||||
pc8->args[1].kind == PCOp_IMMEDIATE
|
||||
) {
|
||||
loop->upper = pc8->args[1].data.imm.value;
|
||||
loop->upperType = LOOP_BOUND_CONSTANT;
|
||||
} else if (
|
||||
pc8->op == PC_LIS &&
|
||||
pc8->args[1].kind == PCOp_IMMEDIATE
|
||||
) {
|
||||
loop->upper = pc8->args[1].data.imm.value << 16;
|
||||
loop->upperType = LOOP_BOUND_CONSTANT;
|
||||
} else if (
|
||||
pc8->op == PC_ADDI &&
|
||||
pc8->args[2].kind == PCOp_IMMEDIATE &&
|
||||
pc8->args[1].data.reg.reg == prevpcode->args[2].data.reg.reg &&
|
||||
pc8->prevPCode &&
|
||||
pc8->prevPCode->op == PC_LIS &&
|
||||
pc8->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
|
||||
pc8->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg
|
||||
) {
|
||||
loop->upper = pc8->args[2].data.imm.value +
|
||||
(pc8->prevPCode->args[1].data.imm.value << 16);
|
||||
loop->upperType = LOOP_BOUND_CONSTANT;
|
||||
} else {
|
||||
loop->upperType = LOOP_BOUND_VARIABLE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
loop->upperType = LOOP_BOUND_VARIABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loop->upperType == LOOP_BOUND_INDETERMINATE)
|
||||
loop->upperType = LOOP_BOUND_VARIABLE;
|
||||
}
|
||||
}
|
||||
|
||||
pc8 = NULL;
|
||||
|
||||
for (list = reg_Defs[RegClass_GPR][reg11b]; list; list = list->next) {
|
||||
check = Defs[list->id].pcode;
|
||||
if (bitvectorgetbit(check->block->blockIndex, loop->memberblocks)) {
|
||||
if (!pc8) {
|
||||
pc8 = check;
|
||||
if (check->op != PC_ADDI)
|
||||
return;
|
||||
if (check->args[1].data.reg.reg != reg11b)
|
||||
return;
|
||||
if (check->args[2].kind != PCOp_IMMEDIATE)
|
||||
return;
|
||||
if ((loop->step = check->args[2].data.imm.value) == 0)
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pc8)
|
||||
return;
|
||||
|
||||
if (pc8->block != prevpcode->block && !bitvectorgetbit(prevpcode->block->blockIndex, loop->vec2C))
|
||||
return;
|
||||
|
||||
if (loop->children) {
|
||||
for (child = loop->children; child; child = child->nextSibling) {
|
||||
if (bitvectorgetbit(pc8->block->blockIndex, child->memberblocks))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
loop->pc18 = pc8;
|
||||
|
||||
pc8 = NULL;
|
||||
|
||||
for (list = reg_Defs[RegClass_GPR][reg11b]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].defvec8)) {
|
||||
if (!pc8) {
|
||||
pc8 = Defs[list->id].pcode;
|
||||
if (
|
||||
pc8->op == PC_LI &&
|
||||
pc8->args[1].kind == PCOp_IMMEDIATE
|
||||
) {
|
||||
loop->lower = pc8->args[1].data.imm.value;
|
||||
loop->lowerType = LOOP_BOUND_CONSTANT;
|
||||
} else if (
|
||||
pc8->op == PC_LIS &&
|
||||
pc8->args[1].kind == PCOp_IMMEDIATE
|
||||
) {
|
||||
loop->lower = pc8->args[1].data.imm.value << 16;
|
||||
loop->lowerType = LOOP_BOUND_CONSTANT;
|
||||
} else if (
|
||||
pc8->op == PC_ADDI &&
|
||||
pc8->args[2].kind == PCOp_IMMEDIATE &&
|
||||
pc8->args[1].data.reg.reg == reg11b &&
|
||||
pc8->prevPCode &&
|
||||
pc8->prevPCode->op == PC_LIS &&
|
||||
pc8->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
|
||||
pc8->prevPCode->args[0].data.reg.reg == reg11b
|
||||
) {
|
||||
loop->lower = pc8->args[2].data.imm.value +
|
||||
(pc8->prevPCode->args[1].data.imm.value << 16);
|
||||
loop->lowerType = LOOP_BOUND_CONSTANT;
|
||||
} else {
|
||||
loop->lowerType = LOOP_BOUND_VARIABLE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
loop->lowerType = LOOP_BOUND_INDETERMINATE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loop->lowerType == LOOP_BOUND_INDETERMINATE)
|
||||
loop->lowerType = LOOP_BOUND_VARIABLE;
|
||||
|
||||
if (loop->lowerType == LOOP_BOUND_CONSTANT && loop->upperType == LOOP_BOUND_CONSTANT) {
|
||||
if (op12 == PC_CMP || op12 == PC_CMPI) {
|
||||
if (!checklooplimits(lastpcode->op, reg4, loop->lower, loop->upper, loop->step, &loop->iterationCount))
|
||||
return;
|
||||
} else {
|
||||
if (!checkunsignedlooplimits(lastpcode->op, reg4, loop->lower, loop->upper, loop->step, (UInt32 *) &loop->iterationCount))
|
||||
return;
|
||||
}
|
||||
loop->isKnownCountingLoop = 1;
|
||||
} else if (loop->lowerType != LOOP_BOUND_INDETERMINATE || loop->upperType != LOOP_BOUND_INDETERMINATE) {
|
||||
if (!checkunknownloop(lastpcode->op, reg4, loop->step, &loop->unknownCondition))
|
||||
return;
|
||||
loop->isUnknownCountingLoop = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void analyzeForCountableLoops(Loop *loop) {
|
||||
if (!loop)
|
||||
return;
|
||||
|
||||
while (loop) {
|
||||
if (loop->children)
|
||||
analyzeForCountableLoops(loop->children);
|
||||
checkcountingloop(loop);
|
||||
loop = loop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
void analyzeloop(Loop *loop) {
|
||||
BlockList *list;
|
||||
PCodeBlock *block;
|
||||
PCode *pcode;
|
||||
|
||||
loop->bodySize = 0;
|
||||
loop->x4D = 0;
|
||||
loop->x4E = 0;
|
||||
loop->x4F = 1;
|
||||
loop->isKnownCountingLoop = 0;
|
||||
loop->isUnknownCountingLoop = 0;
|
||||
loop->lowerType = LOOP_BOUND_INDETERMINATE;
|
||||
loop->upperType = LOOP_BOUND_INDETERMINATE;
|
||||
loop->iterationCount = -1;
|
||||
loop->x57 = 0;
|
||||
loop->x52 = 0;
|
||||
|
||||
for (list = loop->blocks; list; list = list->next) {
|
||||
block = list->block;
|
||||
if (!loop->children)
|
||||
block->flags |= fPCBlockFlag2000;
|
||||
loop->bodySize += block->pcodeCount;
|
||||
|
||||
if (block != loop->body) {
|
||||
if (!block->successors || !block->predecessors || block->successors->nextLink || block->predecessors->nextLink)
|
||||
loop->x4F = 0;
|
||||
}
|
||||
|
||||
if ((block->flags & fPCBlockFlag4000) == fPCBlockFlag4000)
|
||||
loop->x52 = 1;
|
||||
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (PCODE_FLAG_SET_T(pcode) & fLink)
|
||||
loop->x4D = 1;
|
||||
|
||||
if (pcode->op == PC_BCTRL || pcode->op == PC_BCTR || pcode->op == PC_BCCTR || pcode->op == PC_MTCTR || pcode->op == PC_MFCTR) {
|
||||
loop->x4E = 1;
|
||||
} else if (pcode->flags & fPCodeFlag2) {
|
||||
if (pcode->op == PC_LBZX || pcode->op == PC_LHZX || pcode->op == PC_LHAX || pcode->op == PC_LWZX || pcode->op == PC_LFSX || pcode->op == PC_LFDX)
|
||||
loop->x53 = 1;
|
||||
} else if (pcode->flags & fPCodeFlag4) {
|
||||
if (pcode->op == PC_STBX || pcode->op == PC_STHX || pcode->op == PC_STWX || pcode->op == PC_STFSX || pcode->op == PC_STFDX)
|
||||
loop->x54 = 1;
|
||||
} else {
|
||||
if (pcode->op == PC_EIEIO || pcode->op == PC_SYNC || pcode->op == PC_ISYNC)
|
||||
loop->x57 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loop->children && !loop->x4D && loop->bodySize < 32) {
|
||||
for (list = loop->blocks; list; list = list->next)
|
||||
list->block->flags |= fPCBlockFlag2000;
|
||||
}
|
||||
}
|
||||
|
||||
static void analyzeloops(Loop *loop) {
|
||||
while (loop) {
|
||||
if (loop->children)
|
||||
analyzeloops(loop->children);
|
||||
analyzeloop(loop);
|
||||
loop = loop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
void analyzeloopsinflowgraph(void) {
|
||||
if (loopsinflowgraph)
|
||||
analyzeloops(loopsinflowgraph);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -60,7 +60,7 @@ PCode *copypcode(PCode *pcode) {
|
||||
newpc->op = pcode->op;
|
||||
newpc->flags = pcode->flags;
|
||||
newpc->argCount = pcode->argCount;
|
||||
newpc->_18 = pcode->_18;
|
||||
newpc->alias = pcode->alias;
|
||||
for (i = 0; i < pcode->argCount; i++) {
|
||||
newpc->args[i] = pcode->args[i];
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
#include "compiler/PCodeAssembly.h"
|
||||
|
||||
static UInt32 codebase;
|
||||
|
||||
static void pcode_update_mem_labeldiff_imm() {
|
||||
}
|
||||
|
||||
UInt32 assemblepcode(PCode *instr, UInt32 offset, PCodeArg *dummyArg) {
|
||||
}
|
||||
|
||||
static void targetinstruction() {
|
||||
}
|
||||
|
||||
static void invertybit() {
|
||||
}
|
||||
|
||||
static void insertlongbranches() {
|
||||
}
|
||||
|
||||
void optimizefinalbranches() {
|
||||
}
|
||||
|
||||
static void insert_align_nops() {
|
||||
}
|
||||
|
||||
void assemblefunction() {
|
||||
}
|
@ -0,0 +1,527 @@
|
||||
#include "compiler/PCodeListing.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CMangler.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/Alias.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/InterferenceGraph.h"
|
||||
#include "compiler/LiveInfo.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeAssembly.h"
|
||||
#include "compiler/Registers.h"
|
||||
#include "compiler/Scheduler.h"
|
||||
#include "compiler/objects.h"
|
||||
|
||||
static FILE *pcfile;
|
||||
static int ptime;
|
||||
static int sourcetext;
|
||||
static int sourcetext_is_main;
|
||||
static int sourcelength;
|
||||
int pclist_bad_operand;
|
||||
|
||||
static void formatdataflowset(char *name, UInt32 *vec, UInt32 size, char *format) {
|
||||
UInt32 i;
|
||||
UInt32 counter;
|
||||
char *separator;
|
||||
|
||||
separator = "";
|
||||
fprintf(pcfile, "%s = {", name);
|
||||
|
||||
for (i = 0, counter = 0; i < size; i++) {
|
||||
if (bitvectorgetbit(i, vec)) {
|
||||
if (i)
|
||||
fprintf(pcfile, separator);
|
||||
if (counter++ == 10) {
|
||||
fprintf(pcfile, "\n\t\t");
|
||||
counter = 0;
|
||||
}
|
||||
fprintf(pcfile, format, i);
|
||||
separator = ",";
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(pcfile, "}\n");
|
||||
}
|
||||
|
||||
static void pclistblock(PCodeBlock *block, char *format, UInt32 vecSize) {
|
||||
PCLink *link;
|
||||
PCodeLabel *label;
|
||||
int cpu;
|
||||
int chr; // r21
|
||||
PCode *instr; // r20
|
||||
int offset; // r19
|
||||
int latency; // r18
|
||||
UInt32 opcode;
|
||||
MachineInfo *mi;
|
||||
char buf[500];
|
||||
PCodeArg dummyArg;
|
||||
|
||||
fprintf(pcfile, ":{%4.4x}::::::::::::::::::::::::::::::::::::::::LOOPWEIGHT=%ld\n", block->flags, block->loopWeight);
|
||||
fprintf(pcfile, "B%ld: ", block->blockIndex);
|
||||
|
||||
fprintf(pcfile, "Successors = { ");
|
||||
for (link = block->successors; link; link = link->nextLink) {
|
||||
if (link->block)
|
||||
fprintf(pcfile, "B%ld ", link->block->blockIndex);
|
||||
}
|
||||
fprintf(pcfile, "} ");
|
||||
|
||||
fprintf(pcfile, "Predecessors = { ");
|
||||
for (link = block->predecessors; link; link = link->nextLink) {
|
||||
if (link->block)
|
||||
fprintf(pcfile, "B%ld ", link->block->blockIndex);
|
||||
}
|
||||
|
||||
if (block->labels) {
|
||||
fprintf(pcfile, "} Labels = { ");
|
||||
for (label = block->labels; label; label = label->nextLabel)
|
||||
fprintf(pcfile, "L%ld ", label->index);
|
||||
}
|
||||
|
||||
fprintf(pcfile, "}\n\n");
|
||||
|
||||
cpu = copts.schedule_cpu;
|
||||
if (cpu == 10) {
|
||||
mi = &machine7450;
|
||||
} else if (copts.altivec_model != 0 || cpu == 7) {
|
||||
mi = &machine7400;
|
||||
} else if (cpu == 2) {
|
||||
mi = &machine603;
|
||||
} else if (cpu == 5) {
|
||||
mi = &machine603e;
|
||||
} else if (cpu == 3) {
|
||||
mi = &machine604;
|
||||
} else if (cpu == 6) {
|
||||
mi = &machine604;
|
||||
} else if (cpu == 4) {
|
||||
mi = &machine750;
|
||||
} else if (cpu == 1) {
|
||||
mi = &machine601;
|
||||
} else if (cpu == 9) {
|
||||
mi = &machine821;
|
||||
} else {
|
||||
mi = &machine603;
|
||||
}
|
||||
|
||||
for (offset = block->codeOffset, instr = block->firstPCode; instr; instr = instr->nextPCode, offset += 4) {
|
||||
latency = mi->latency(instr);
|
||||
formatoperands(instr, buf, 1);
|
||||
chr = (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000) ? '.' : ' ';
|
||||
if (coloring)
|
||||
opcode = 0;
|
||||
else
|
||||
opcode = assemblepcode(instr, offset, &dummyArg);
|
||||
|
||||
fprintf(
|
||||
pcfile,
|
||||
" %.8lX %.8lX %4ld %-7s%c %s\n",
|
||||
offset, opcode, latency,
|
||||
opcodeinfo[instr->op].name, chr, buf
|
||||
);
|
||||
|
||||
if (instr->alias)
|
||||
dumpalias(instr->alias, 0, 1, 0);
|
||||
}
|
||||
|
||||
if (vecSize) {
|
||||
fprintf(pcfile, "............................................................\n");
|
||||
formatdataflowset("use", liveinfo[block->blockIndex].vec0, vecSize, format);
|
||||
formatdataflowset("def", liveinfo[block->blockIndex].vec4, vecSize, format);
|
||||
formatdataflowset("in ", liveinfo[block->blockIndex].vec8, vecSize, format);
|
||||
formatdataflowset("out", liveinfo[block->blockIndex].vecC, vecSize, format);
|
||||
}
|
||||
|
||||
fflush(pcfile);
|
||||
|
||||
if (pclist_bad_operand) {
|
||||
#line 252
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
static void pclistonoff(int flag) {
|
||||
if (flag)
|
||||
fprintf(pcfile, "On\n");
|
||||
else
|
||||
fprintf(pcfile, "Off\n");
|
||||
}
|
||||
|
||||
void pcinitlisting(void) {
|
||||
// unknown args, etc
|
||||
}
|
||||
|
||||
void pccleanuplisting(void) {
|
||||
}
|
||||
|
||||
void pclistblocks(char *name1, char *name2) {
|
||||
}
|
||||
|
||||
void pclistdataflow(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistinterferences(char *class_format, int regcount) {
|
||||
}
|
||||
|
||||
void pclistspill(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistcopypropitem(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistcoalesce(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistusedefs(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistpropinfo(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
static void listloop(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
static void listloops(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistloops(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
static void listswitchtables(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistswitchtables(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistdominators(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistbackedge(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
static char *GetInterferenceFlags(IGNode *node) {
|
||||
char *buf;
|
||||
Boolean first;
|
||||
|
||||
first = 1;
|
||||
buf = oalloc(512);
|
||||
buf[0] = 0;
|
||||
|
||||
if (node->flags & fSpilled) {
|
||||
strcat(buf, "fSpilled");
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (node->flags & fPushed) {
|
||||
if (!first)
|
||||
strcat(buf, "|");
|
||||
strcat(buf, "fPushed");
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (node->flags & fCoalesced) {
|
||||
if (!first)
|
||||
strcat(buf, "|");
|
||||
strcat(buf, "fCoalesced");
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (node->flags & fCoalescedInto) {
|
||||
if (!first)
|
||||
strcat(buf, "|");
|
||||
strcat(buf, "fCoalescedInto");
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (node->flags & fPairHigh) {
|
||||
if (!first)
|
||||
strcat(buf, "|");
|
||||
strcat(buf, "fPairHigh");
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (node->flags & fPairLow) {
|
||||
if (!first)
|
||||
strcat(buf, "|");
|
||||
strcat(buf, "fPairLow");
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (!*buf)
|
||||
strcat(buf, "no_flags");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void pclistinterferencegraphnode(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistinterferencegraph(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistblock_scheduler(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pclistblocks_start_scheduler(char *str1, char *str2) {
|
||||
}
|
||||
|
||||
void pclistblocks_end_scheduler(void) {
|
||||
if (pclist_bad_operand) {
|
||||
#line 1318
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
static void printheapsize(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pctotalheap(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pctotalmemory(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
void pcmessage(char *probably_a_string, ...) {
|
||||
}
|
||||
|
||||
int formatalias(Alias *alias, char *buf, int bufSize) {
|
||||
char *name;
|
||||
char *typestr;
|
||||
int len;
|
||||
int len2;
|
||||
|
||||
if (bufSize < 16)
|
||||
return sprintf(buf, "...");
|
||||
|
||||
switch (alias->type) {
|
||||
case AliasType0:
|
||||
case AliasType1:
|
||||
name = CMangler_GetLinkName(alias->object)->name;
|
||||
if (!strlen(name) || name[0] < 0) {
|
||||
#line 1458
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
if (strlen(name) + 16 > bufSize)
|
||||
return sprintf(buf, "...");
|
||||
|
||||
switch (alias->object->datatype) {
|
||||
case DNONLAZYPTR:
|
||||
typestr = "{NL}";
|
||||
break;
|
||||
case DDATA:
|
||||
typestr = "{RW}";
|
||||
break;
|
||||
case DLOCAL:
|
||||
typestr = "{SP}";
|
||||
break;
|
||||
default:
|
||||
typestr = "";
|
||||
}
|
||||
|
||||
len = sprintf(buf, "%0.*s%s", bufSize - 20, name, typestr, alias->size);
|
||||
buf += len;
|
||||
if (alias->type == AliasType0)
|
||||
return len;
|
||||
|
||||
if (alias->offset == 0)
|
||||
len2 = sprintf(buf, ":%d", alias->size);
|
||||
else if (alias->offset > 0)
|
||||
len2 = sprintf(buf, "+%d:%d", alias->offset, alias->size);
|
||||
else
|
||||
len2 = sprintf(buf, "-%d:%d", -alias->offset, alias->size);
|
||||
|
||||
return len + len2;
|
||||
|
||||
case AliasType2:
|
||||
len = 0;
|
||||
|
||||
len2 = sprintf(buf, "{");
|
||||
buf += len2;
|
||||
len += len2;
|
||||
|
||||
len2 = sprintf(buf, "*");
|
||||
buf += len2;
|
||||
len += len2;
|
||||
|
||||
len2 = sprintf(buf, "}");
|
||||
buf += len2;
|
||||
len += len2;
|
||||
return len;
|
||||
|
||||
default:
|
||||
#line 1543
|
||||
CError_FATAL();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int dumpalias(Alias *alias, int len, Boolean flag1, Boolean flag2) {
|
||||
char *name;
|
||||
char *typestr;
|
||||
AliasMember *member;
|
||||
Boolean notFirst;
|
||||
|
||||
if (!flag2 && alias == worst_case) {
|
||||
fprintf(pcfile, " ALIAS = {worst_case}");
|
||||
if (flag1)
|
||||
fprintf(pcfile, "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flag1) {
|
||||
if (alias == worst_case)
|
||||
fprintf(pcfile, "ALIAS worst_case = ");
|
||||
else
|
||||
fprintf(pcfile, " ALIAS = ");
|
||||
}
|
||||
|
||||
switch (alias->type) {
|
||||
case AliasType0:
|
||||
case AliasType1:
|
||||
name = CMangler_GetLinkName(alias->object)->name;
|
||||
if (!strlen(name) || name[0] < 0) {
|
||||
#line 1581
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
switch (alias->object->datatype) {
|
||||
case DNONLAZYPTR:
|
||||
typestr = "{NL}";
|
||||
break;
|
||||
case DDATA:
|
||||
typestr = "{RW}";
|
||||
break;
|
||||
case DLOCAL:
|
||||
typestr = "{SP}";
|
||||
break;
|
||||
default:
|
||||
typestr = "";
|
||||
}
|
||||
|
||||
len += fprintf(pcfile, "%0.80s%s", name, typestr);
|
||||
|
||||
if (alias->type == AliasType0) {
|
||||
if (flag1)
|
||||
fprintf(pcfile, "\n");
|
||||
return len;
|
||||
}
|
||||
|
||||
if (alias->offset == 0)
|
||||
len += fprintf(pcfile, ":%d", alias->size);
|
||||
else if (alias->offset > 0)
|
||||
len += fprintf(pcfile, "+%d:%d", alias->offset, alias->size);
|
||||
else
|
||||
len += fprintf(pcfile, "-%d:%d", -alias->offset, alias->size);
|
||||
|
||||
if (flag1)
|
||||
fprintf(pcfile, "\n");
|
||||
|
||||
return len;
|
||||
|
||||
case AliasType2:
|
||||
len += fprintf(pcfile, "{");
|
||||
notFirst = 0;
|
||||
for (member = alias->parents; member; member = member->nextParent) {
|
||||
if (member->child->type == AliasType0) {
|
||||
if (notFirst)
|
||||
len += fprintf(pcfile, ",");
|
||||
if (len > 60) {
|
||||
fprintf(pcfile, "\n ");
|
||||
len = 0;
|
||||
}
|
||||
len = dumpalias(member->child, len, 0, 0);
|
||||
notFirst = 1;
|
||||
}
|
||||
}
|
||||
for (member = alias->parents; member; member = member->nextParent) {
|
||||
if (member->child->type != AliasType0) {
|
||||
if (notFirst)
|
||||
len += fprintf(pcfile, ",");
|
||||
if (len > 60) {
|
||||
fprintf(pcfile, "\n ");
|
||||
len = 0;
|
||||
}
|
||||
len = dumpalias(member->child, len, 0, 0);
|
||||
notFirst = 1;
|
||||
}
|
||||
}
|
||||
|
||||
len += fprintf(pcfile, "}");
|
||||
if (flag1)
|
||||
fprintf(pcfile, "\n");
|
||||
return len;
|
||||
|
||||
default:
|
||||
#line 1661
|
||||
CError_FATAL();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void pcformatset(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
int GetLineEndOffset(char *str, int lineNum, int len) {
|
||||
int offset;
|
||||
char *work;
|
||||
|
||||
offset = GetLineOffset(str, lineNum, len);
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
work = str + offset;
|
||||
while (*work) {
|
||||
if (*work == '\n')
|
||||
return work - str - 1;
|
||||
work++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GetLineOffset(char *str, int lineNum, int len) {
|
||||
char *work = str;
|
||||
char *end;
|
||||
|
||||
if (lineNum < 0)
|
||||
return -1;
|
||||
|
||||
end = str + len;
|
||||
while (work < end) {
|
||||
if (*work == '\n' && --lineNum <= 0)
|
||||
return work - str;
|
||||
work++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DumpSourceCode(void) {
|
||||
// unknown args
|
||||
}
|
||||
|
||||
int DumpIR_SrcBreak(void) {
|
||||
// unknown args
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,548 @@
|
||||
#include "compiler/Scheduler.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/Alias.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/Registers.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct DGNode {
|
||||
struct DGNode *x0;
|
||||
struct DGNode *x4;
|
||||
struct DGSuccessor *successors;
|
||||
PCode *instr;
|
||||
UInt16 x10;
|
||||
UInt16 x12;
|
||||
UInt16 x14;
|
||||
UInt16 x16;
|
||||
short predCount;
|
||||
} DGNode;
|
||||
|
||||
typedef struct DGSuccessor {
|
||||
struct DGSuccessor *next;
|
||||
DGNode *node;
|
||||
UInt16 x8;
|
||||
} DGSuccessor;
|
||||
|
||||
typedef struct DGNodeList {
|
||||
struct DGNodeList *next;
|
||||
DGNode *node;
|
||||
} DGNodeList;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
static DGNodeList **register_uses[RegClassMax];
|
||||
static DGNodeList **register_defs[RegClassMax];
|
||||
static DGNodeList *memory_uses;
|
||||
static DGNodeList *memory_defs;
|
||||
static DGNodeList *side_effects;
|
||||
static DGNodeList *volatile_refs;
|
||||
static DGNode *defaultsuccessor;
|
||||
static UInt16 criticalpath;
|
||||
static MachineInfo *MI;
|
||||
|
||||
static void initresources(void) {
|
||||
int rclass;
|
||||
int i;
|
||||
|
||||
for (rclass = 0; (char) rclass < RegClassMax; rclass++) {
|
||||
register_uses[(char) rclass] = oalloc(sizeof(DGNodeList *) * used_virtual_registers[(char) rclass]);
|
||||
register_defs[(char) rclass] = oalloc(sizeof(DGNodeList *) * used_virtual_registers[(char) rclass]);
|
||||
for (i = 0; i < used_virtual_registers[(char) rclass]; i++) {
|
||||
register_uses[(char) rclass][i] = register_defs[(char) rclass][i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
memory_uses = memory_defs = NULL;
|
||||
side_effects = NULL;
|
||||
volatile_refs = NULL;
|
||||
criticalpath = 0;
|
||||
}
|
||||
|
||||
static DGNode *makedgnode(PCode *instr) {
|
||||
DGNode *node;
|
||||
|
||||
node = oalloc(sizeof(DGNode));
|
||||
node->x0 = NULL;
|
||||
node->x4 = NULL;
|
||||
node->successors = NULL;
|
||||
node->instr = instr;
|
||||
node->x10 = node->x16 = MI->latency(instr);
|
||||
node->x12 = 0;
|
||||
node->x14 = 0;
|
||||
node->predCount = 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
static DGNode *adddgnode(DGNode *head, DGNode *node) {
|
||||
if (head)
|
||||
head->x4 = node;
|
||||
node->x0 = head;
|
||||
return node;
|
||||
}
|
||||
|
||||
static DGNode *removedgnode(DGNode *head, DGNode *node) {
|
||||
if (node->x4)
|
||||
node->x4->x0 = node->x0;
|
||||
else
|
||||
head = node->x0;
|
||||
|
||||
if (node->x0)
|
||||
node->x0->x4 = node->x4;
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static void addtolist(DGNodeList **list, DGNode *node) {
|
||||
DGNodeList *entry = oalloc(sizeof(DGNodeList));
|
||||
entry->node = node;
|
||||
entry->next = *list;
|
||||
*list = entry;
|
||||
}
|
||||
|
||||
static DGNodeList *makedglistnode(DGNode *node) {
|
||||
DGNodeList *list = oalloc(sizeof(DGNodeList));
|
||||
list->next = NULL;
|
||||
list->node = node;
|
||||
return list;
|
||||
}
|
||||
|
||||
int is_same_operand(PCodeArg *a, PCodeArg *b) {
|
||||
if (a->kind != b->kind)
|
||||
return 0;
|
||||
|
||||
switch (a->kind) {
|
||||
case PCOp_IMMEDIATE:
|
||||
if (a->data.imm.value != b->data.imm.value)
|
||||
return 0;
|
||||
break;
|
||||
case PCOp_REGISTER:
|
||||
if ((char) a->arg != (char) b->arg)
|
||||
return 0;
|
||||
if (a->data.reg.reg != b->data.reg.reg)
|
||||
return 0;
|
||||
break;
|
||||
case PCOp_MEMORY:
|
||||
if (a->data.mem.offset != b->data.mem.offset)
|
||||
return 0;
|
||||
if (a->data.mem.obj != b->data.mem.obj)
|
||||
return 0;
|
||||
break;
|
||||
case PCOp_LABEL:
|
||||
if (a->data.label.label != b->data.label.label)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void addsuccessor(DGNode *a, DGNode *b, Boolean flag) {
|
||||
int v6;
|
||||
int r29;
|
||||
DGSuccessor *succ;
|
||||
|
||||
if (flag)
|
||||
v6 = a->x10;
|
||||
else
|
||||
v6 = 0;
|
||||
|
||||
if (a != b) {
|
||||
r29 = (v6 > 0) ? v6 : 0;
|
||||
for (succ = a->successors; succ; succ = succ->next) {
|
||||
if (succ->node == b) {
|
||||
if (succ->x8 < r29) {
|
||||
succ->x8 = r29;
|
||||
if (b->x16 + succ->x8 > a->x16)
|
||||
a->x16 = b->x16 + succ->x8;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
succ = oalloc(sizeof(DGSuccessor));
|
||||
succ->node = b;
|
||||
succ->next = a->successors;
|
||||
a->successors = succ;
|
||||
succ->x8 = r29;
|
||||
|
||||
if (flag && (succ->node->instr->flags & fPCodeFlag1))
|
||||
succ->x8 += MI->x8;
|
||||
|
||||
b->predCount++;
|
||||
|
||||
if (b->x16 + succ->x8 > a->x16)
|
||||
a->x16 = b->x16 + succ->x8;
|
||||
}
|
||||
}
|
||||
|
||||
static void serializeall(DGNode *nodes, DGNode *node) {
|
||||
DGNode *scan;
|
||||
|
||||
for (scan = nodes; scan; scan = scan->x0)
|
||||
addsuccessor(node, scan, 0);
|
||||
}
|
||||
|
||||
static void serializelist(DGNode *node, DGNodeList *list) {
|
||||
while (list) {
|
||||
if (list->node != node)
|
||||
addsuccessor(node, list->node, 0);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void serializeregister(int rclass, DGNode *node, DGNodeList **defs, DGNodeList **uses, int isWrite) {
|
||||
DGNodeList *list;
|
||||
|
||||
if (isWrite) {
|
||||
for (list = *uses; list; list = list->next) {
|
||||
if (list->node != node)
|
||||
addsuccessor(node, list->node, 1);
|
||||
}
|
||||
for (list = *defs; list; list = list->next) {
|
||||
if (list->node != node)
|
||||
addsuccessor(node, list->node, ((char) rclass == RegClass_SPR) || (MI->x4 == 0));
|
||||
}
|
||||
|
||||
list = makedglistnode(node);
|
||||
list->next = *defs;
|
||||
*defs = list;
|
||||
} else {
|
||||
for (list = *defs; list; list = list->next) {
|
||||
if (list->node != node)
|
||||
addsuccessor(node, list->node, ((char) rclass == RegClass_SPR) || (MI->x4 == 0));
|
||||
}
|
||||
|
||||
list = makedglistnode(node);
|
||||
list->next = *uses;
|
||||
*uses = list;
|
||||
}
|
||||
}
|
||||
|
||||
static void serialize_load(DGNode *node) {
|
||||
DGNodeList *list;
|
||||
|
||||
for (list = memory_defs; list; list = list->next) {
|
||||
if (may_alias(node->instr, list->node->instr))
|
||||
addsuccessor(node, list->node, 1);
|
||||
}
|
||||
|
||||
addtolist(&memory_uses, node);
|
||||
}
|
||||
|
||||
static void serialize_store(DGNode *node) {
|
||||
DGNodeList *list;
|
||||
|
||||
for (list = memory_uses; list; list = list->next) {
|
||||
if (may_alias(node->instr, list->node->instr))
|
||||
addsuccessor(node, list->node, 1);
|
||||
}
|
||||
for (list = memory_defs; list; list = list->next) {
|
||||
if (may_alias(node->instr, list->node->instr))
|
||||
addsuccessor(node, list->node, 1);
|
||||
}
|
||||
|
||||
addtolist(&memory_defs, node);
|
||||
if (node->instr->flags & fPCodeFlag40000)
|
||||
addtolist(&memory_uses, node);
|
||||
}
|
||||
|
||||
static void findsuccessors(DGNode *nodes, DGNode *node) {
|
||||
PCode *instr;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
instr = node->instr;
|
||||
for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
|
||||
switch (op->kind) {
|
||||
case PCOp_IMMEDIATE:
|
||||
case PCOp_MEMORY:
|
||||
break;
|
||||
case PCOp_REGISTER:
|
||||
if (
|
||||
op->data.reg.reg < 0 ||
|
||||
op->data.reg.reg > used_virtual_registers[(char) op->arg]
|
||||
)
|
||||
{
|
||||
#line 491
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
|
||||
if (op->data.reg.reg == Register2)
|
||||
break;
|
||||
if (op->data.reg.reg == Register0 && !(op->data.reg.effect & (EffectRead | EffectWrite)))
|
||||
break;
|
||||
}
|
||||
|
||||
serializeregister(
|
||||
op->arg,
|
||||
node,
|
||||
®ister_defs[(char) op->arg][op->data.reg.reg],
|
||||
®ister_uses[(char) op->arg][op->data.reg.reg],
|
||||
op->data.reg.effect & EffectWrite
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (instr->flags & (fPCodeFlag2 | fPCodeFlag20000))
|
||||
serialize_load(node);
|
||||
else if (instr->flags & (fPCodeFlag4 | fPCodeFlag40000))
|
||||
serialize_store(node);
|
||||
|
||||
if (instr->flags & fIsVolatile) {
|
||||
serializelist(node, volatile_refs);
|
||||
addtolist(&volatile_refs, node);
|
||||
}
|
||||
|
||||
if (
|
||||
((instr->flags & fPCodeFlag8 | fPCodeFlag1) && (instr->flags & fLink)) ||
|
||||
(instr->flags & fSideEffects) ||
|
||||
MI->serializes(instr)
|
||||
)
|
||||
{
|
||||
serializeall(nodes, node);
|
||||
addtolist(&side_effects, node);
|
||||
}
|
||||
|
||||
if (side_effects)
|
||||
serializelist(node, side_effects);
|
||||
|
||||
if (!node->successors && defaultsuccessor)
|
||||
addsuccessor(node, defaultsuccessor, 0);
|
||||
|
||||
if (node->x16 > criticalpath)
|
||||
criticalpath = node->x16;
|
||||
}
|
||||
|
||||
static void computedeadlines(DGNode *nodes) {
|
||||
while (nodes) {
|
||||
nodes->x14 = criticalpath - nodes->x16;
|
||||
nodes = nodes->x0;
|
||||
}
|
||||
}
|
||||
|
||||
static int uncovering(DGNode *node) {
|
||||
int counter;
|
||||
DGSuccessor *succ;
|
||||
|
||||
counter = 0;
|
||||
for (succ = node->successors; succ; succ = succ->next) {
|
||||
if (succ->node->predCount == 1)
|
||||
counter++;
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
static DGNode *selectinstruction(DGNode *nodes, UInt16 counter) {
|
||||
DGNode *node;
|
||||
DGNode *node2;
|
||||
int a;
|
||||
int b;
|
||||
|
||||
node = nodes;
|
||||
while (node) {
|
||||
if (node->predCount == 0 && node->x12 <= counter && MI->can_issue(node->instr))
|
||||
break;
|
||||
node = node->x0;
|
||||
}
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
for (node2 = node->x0; node2; node2 = node2->x0) {
|
||||
if (
|
||||
node2->predCount == 0 &&
|
||||
node2->x12 <= counter &&
|
||||
MI->can_issue(node2->instr) &&
|
||||
(node->x14 > counter || node2->x14 <= counter)
|
||||
)
|
||||
{
|
||||
if (node->x14 > counter && node2->x14 <= counter) {
|
||||
node = node2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((a = uncovering(node)) > (b = uncovering(node2)))
|
||||
continue;
|
||||
|
||||
if (a < b) {
|
||||
node = node2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node->x16 > node2->x16)
|
||||
continue;
|
||||
|
||||
if (node->x16 < node2->x16) {
|
||||
node = node2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (coloring) {
|
||||
if (opcodeinfo[node->instr->op].x9 < opcodeinfo[node2->instr->op].x9)
|
||||
continue;
|
||||
|
||||
if (opcodeinfo[node->instr->op].x9 > opcodeinfo[node2->instr->op].x9)
|
||||
node = node2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void holdoffsuccessors(DGNode *node, UInt16 counter) {
|
||||
DGSuccessor *succ;
|
||||
DGNode *n;
|
||||
|
||||
for (succ = node->successors; succ; succ = succ->next) {
|
||||
n = succ->node;
|
||||
n->predCount--;
|
||||
if (n->x12 < counter + succ->x8)
|
||||
n->x12 = counter + succ->x8;
|
||||
}
|
||||
}
|
||||
|
||||
static void scheduleblock(PCodeBlock *block) {
|
||||
DGNode *node;
|
||||
UInt16 counter;
|
||||
PCode *instr;
|
||||
UInt16 i;
|
||||
DGNode *head;
|
||||
|
||||
initresources();
|
||||
defaultsuccessor = NULL;
|
||||
head = NULL;
|
||||
|
||||
for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
|
||||
DGNode *n = makedgnode(instr);
|
||||
findsuccessors(head, n);
|
||||
if (instr->flags & fPCodeFlag1)
|
||||
defaultsuccessor = n;
|
||||
head = adddgnode(head, n);
|
||||
}
|
||||
|
||||
computedeadlines(head);
|
||||
block->firstPCode = block->lastPCode = NULL;
|
||||
block->pcodeCount = 0;
|
||||
|
||||
MI->initialize();
|
||||
counter = 0;
|
||||
while (head != NULL) {
|
||||
for (i = 0; i < MI->x0; i++) {
|
||||
if (head == NULL)
|
||||
break;
|
||||
|
||||
node = selectinstruction(head, counter);
|
||||
if (!node)
|
||||
break;
|
||||
|
||||
instr = node->instr;
|
||||
if (node->successors)
|
||||
holdoffsuccessors(node, counter);
|
||||
|
||||
appendpcode(block, instr);
|
||||
MI->issue(instr);
|
||||
head = removedgnode(head, node);
|
||||
}
|
||||
|
||||
MI->advance_clock();
|
||||
counter++;
|
||||
}
|
||||
|
||||
freeoheap();
|
||||
}
|
||||
|
||||
void scheduleinstructions(Boolean flag) {
|
||||
PCodeBlock *block;
|
||||
int cpu;
|
||||
|
||||
cpu = copts.schedule_cpu;
|
||||
if (cpu == 10) {
|
||||
MI = &machine7450;
|
||||
} else if (copts.altivec_model != 0 || cpu == 7) {
|
||||
MI = &machine7400;
|
||||
} else if (cpu == 2) {
|
||||
MI = &machine603;
|
||||
} else if (cpu == 5) {
|
||||
MI = &machine603e;
|
||||
} else if (cpu == 3) {
|
||||
MI = &machine604;
|
||||
} else if (cpu == 6) {
|
||||
MI = &machine604;
|
||||
} else if (cpu == 4) {
|
||||
MI = &machine750;
|
||||
} else if (cpu == 1) {
|
||||
MI = &machine601;
|
||||
} else if (cpu == 9) {
|
||||
MI = &machine821;
|
||||
} else {
|
||||
MI = &machine603;
|
||||
}
|
||||
|
||||
gather_alias_info();
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
if (
|
||||
block->pcodeCount > 2 &&
|
||||
(flag || !(block->flags & (fPCBlockFlag1 | fPCBlockFlag2))) &&
|
||||
!(block->flags & fPCBlockFlag8)
|
||||
)
|
||||
{
|
||||
scheduleblock(block);
|
||||
block->flags |= fPCBlockFlag8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int is_dependent(PCode *a, PCode *b, char rclass) {
|
||||
int i;
|
||||
int reg;
|
||||
PCodeArg *op;
|
||||
|
||||
if (
|
||||
b &&
|
||||
b->argCount >= 1 &&
|
||||
b->args[0].kind == PCOp_REGISTER &&
|
||||
(char) b->args[0].arg == rclass &&
|
||||
(b->args[0].data.reg.effect & EffectWrite)
|
||||
)
|
||||
{
|
||||
reg = b->args[0].data.reg.reg;
|
||||
for (i = 0; i < a->argCount; i++) {
|
||||
op = &a->args[i];
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(char) op->arg == rclass &&
|
||||
(op->data.reg.effect & (EffectRead | EffectWrite)) &&
|
||||
op->data.reg.reg == reg
|
||||
)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uses_vpermute_unit(PCode *instr) {
|
||||
int cpu;
|
||||
|
||||
cpu = copts.schedule_cpu;
|
||||
if (cpu == 10)
|
||||
return machine7450.uses_vpermute_unit(instr);
|
||||
if (copts.altivec_model != 0 || cpu == 7)
|
||||
return machine7400.uses_vpermute_unit(instr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int default_uses_vpermute_unit(PCode *instr) {
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,464 @@
|
||||
#include "compiler/SpillCode.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CMachine.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/CodeGen.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/Coloring.h"
|
||||
#include "compiler/InterferenceGraph.h"
|
||||
#include "compiler/Operands.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeUtilities.h"
|
||||
#include "compiler/Registers.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
#include "compiler/StackFrame.h"
|
||||
#include "compiler/objects.h"
|
||||
|
||||
static int last_unused_vreg_before_spilling;
|
||||
static short rTEMP_for_VR_spill;
|
||||
|
||||
void estimatespillcosts(void) {
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
IGNode *node;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
int weight;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
if (copts.optimize_for_size)
|
||||
weight = 1;
|
||||
else
|
||||
weight = block->loopWeight;
|
||||
|
||||
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (PC_OP_IS_READ_ANY_REGISTER(op, coloring_class)) {
|
||||
node = interferencegraph[op->data.reg.reg];
|
||||
if (node->instr8 || copts.optimize_for_size)
|
||||
node->spillCost += weight;
|
||||
else
|
||||
node->spillCost += weight * 2;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class)) {
|
||||
node = interferencegraph[op->data.reg.reg];
|
||||
if (node->instr8 || (instr->flags & fPCodeFlag8000))
|
||||
node->spillCost -= weight;
|
||||
else
|
||||
node->spillCost += weight;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Object *makespilltemporary(Type *type) {
|
||||
Object *obj = lalloc(sizeof(Object));
|
||||
memclrw(obj, sizeof(Object));
|
||||
|
||||
obj->otype = OT_OBJECT;
|
||||
obj->access = ACCESSPUBLIC;
|
||||
obj->datatype = DLOCAL;
|
||||
obj->type = type;
|
||||
obj->name = CParser_GetUniqueName();
|
||||
obj->u.var.info = CodeGen_GetNewVarInfo();
|
||||
obj->u.var.uid = 0;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static PCode *rematerialize_spilled_register(short reg, IGNode *node) {
|
||||
PCode *instr = copypcode(node->instr8);
|
||||
|
||||
#line 128
|
||||
CError_ASSERT(instr->args[0].kind == PCOp_REGISTER);
|
||||
|
||||
instr->args[0].data.reg.reg = reg;
|
||||
return instr;
|
||||
}
|
||||
|
||||
static void insert_load_spilled_register(PCode *instr, short reg, IGNode *node) {
|
||||
Type *type;
|
||||
Opcode opcode;
|
||||
Object *object;
|
||||
PCode *newInstr;
|
||||
PCode *newInstr2;
|
||||
SInt32 offset;
|
||||
Operand operand;
|
||||
|
||||
type = node->spillTemporary->type;
|
||||
switch (coloring_class) {
|
||||
case RegClass_CRFIELD:
|
||||
case RegClass_GPR:
|
||||
switch (type->size) {
|
||||
case 1:
|
||||
opcode = PC_LBZ;
|
||||
break;
|
||||
case 2:
|
||||
opcode = is_unsigned(type) ? PC_LHZ : PC_LHA;
|
||||
break;
|
||||
case 4:
|
||||
opcode = PC_LWZ;
|
||||
break;
|
||||
case 8:
|
||||
opcode = PC_LWZ;
|
||||
break;
|
||||
default:
|
||||
#line 187
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
memclrw(&operand, sizeof(Operand));
|
||||
operand.optype = OpndType_Symbol;
|
||||
operand.object = node->spillTemporary;
|
||||
#line 222
|
||||
CError_ASSERT(node->spillTemporary->datatype == DLOCAL);
|
||||
|
||||
coerce_to_addressable(&operand);
|
||||
|
||||
#line 233
|
||||
CError_ASSERT(operand.optype == OpndType_GPR_ImmOffset);
|
||||
|
||||
#line 237
|
||||
CError_ASSERT(node->spillTemporary->datatype == DLOCAL);
|
||||
|
||||
if (node->flags & fPairLow)
|
||||
offset = low_offset;
|
||||
else if (node->flags & fPairHigh)
|
||||
offset = high_offset;
|
||||
else
|
||||
offset = 0;
|
||||
insertpcodebefore(instr, makepcode(opcode, reg, operand.reg, operand.object, operand.immOffset + offset));
|
||||
break;
|
||||
|
||||
case RegClass_FPR:
|
||||
#line 253
|
||||
CError_ASSERT(node->spillTemporary->datatype == DLOCAL);
|
||||
|
||||
if (node->flags & fPairLow)
|
||||
offset = low_offset;
|
||||
else if (node->flags & fPairHigh)
|
||||
offset = high_offset;
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
object = node->spillTemporary;
|
||||
insertpcodebefore(
|
||||
instr,
|
||||
makepcode(
|
||||
(type->size == 8) ? PC_LFD : PC_LFS,
|
||||
reg,
|
||||
local_base_register(object),
|
||||
object,
|
||||
offset
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
case RegClass_VR:
|
||||
#line 320
|
||||
CError_ASSERT(node->spillTemporary->datatype == DLOCAL);
|
||||
|
||||
object = node->spillTemporary;
|
||||
newInstr = makepcode(PC_ADDI, rTEMP_for_VR_spill, local_base_register(object), object, 0);
|
||||
newInstr2 = makepcode(PC_LVX, reg, 0, rTEMP_for_VR_spill);
|
||||
insertpcodebefore(instr, newInstr);
|
||||
insertpcodeafter(newInstr, newInstr2);
|
||||
break;
|
||||
|
||||
default:
|
||||
#line 333
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_store_spilled_register(PCode *instr, Boolean flag, short reg, IGNode *node) {
|
||||
Object *object; // r31
|
||||
Opcode opcode; // r30
|
||||
SInt32 offset; // r26
|
||||
PCode *newInstr2; // r26
|
||||
PCode *newInstr; // r25
|
||||
Type *type; // r25
|
||||
|
||||
object = node->spillTemporary;
|
||||
type = object->type;
|
||||
|
||||
switch (coloring_class) {
|
||||
case RegClass_CRFIELD:
|
||||
case RegClass_GPR:
|
||||
switch (type->size) {
|
||||
case 1:
|
||||
opcode = PC_STB;
|
||||
break;
|
||||
case 2:
|
||||
opcode = PC_STH;
|
||||
break;
|
||||
case 4:
|
||||
opcode = PC_STW;
|
||||
break;
|
||||
case 8:
|
||||
opcode = PC_STW;
|
||||
break;
|
||||
default:
|
||||
#line 391
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
if (node->flags & fPairLow)
|
||||
offset = low_offset;
|
||||
else if (node->flags & fPairHigh)
|
||||
offset = high_offset;
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
newInstr = makepcode(opcode, reg, local_base_register(object), object, offset);
|
||||
if (flag)
|
||||
insertpcodebefore(instr, newInstr);
|
||||
else
|
||||
insertpcodeafter(instr, newInstr);
|
||||
|
||||
break;
|
||||
|
||||
case RegClass_FPR:
|
||||
newInstr = makepcode((type->size == 8) ? PC_STFD : PC_STFS, reg, local_base_register(object), object, 0);
|
||||
if (flag)
|
||||
insertpcodebefore(instr, newInstr);
|
||||
else
|
||||
insertpcodeafter(instr, newInstr);
|
||||
|
||||
break;
|
||||
|
||||
case RegClass_VR:
|
||||
newInstr = makepcode(PC_ADDI, rTEMP_for_VR_spill, local_base_register(object), object, 0);
|
||||
newInstr2 = makepcode(PC_STVX, reg, 0, rTEMP_for_VR_spill);
|
||||
if (flag)
|
||||
insertpcodebefore(instr, newInstr);
|
||||
else
|
||||
insertpcodeafter(instr, newInstr);
|
||||
insertpcodeafter(newInstr, newInstr2);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
#line 527
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
static void spillinstruction(PCodeBlock *block, PCode *instr) {
|
||||
int reg;
|
||||
int reg2;
|
||||
int regs;
|
||||
IGNode *node;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
PCodeArg *op2;
|
||||
int j;
|
||||
int readCounter;
|
||||
int writeCounter;
|
||||
Boolean flag;
|
||||
|
||||
regs = used_virtual_registers[coloring_class];
|
||||
flag = 0;
|
||||
for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
|
||||
#line 563
|
||||
CError_ASSERT(instr->block != NULL);
|
||||
|
||||
if (
|
||||
PC_OP_IS_ANY_REGISTER(op, coloring_class) &&
|
||||
(reg = op->data.reg.reg) < regs &&
|
||||
((node = interferencegraph[op->data.reg.reg])->flags & fSpilled)
|
||||
)
|
||||
{
|
||||
reg2 = used_virtual_registers[coloring_class]++;
|
||||
readCounter = 0;
|
||||
writeCounter = 0;
|
||||
|
||||
for (j = i, op2 = op; j < instr->argCount; j++, op2++) {
|
||||
if (PC_OP_IS_REGISTER(op2, coloring_class, reg)) {
|
||||
if (op2->data.reg.effect & EffectRead)
|
||||
readCounter++;
|
||||
if (op2->data.reg.effect & EffectWrite)
|
||||
writeCounter++;
|
||||
op2->data.reg.reg = reg2;
|
||||
op2->data.reg.effect |= Effect40;
|
||||
}
|
||||
}
|
||||
|
||||
if (readCounter) {
|
||||
if (node->instr8)
|
||||
insertpcodebefore(instr, rematerialize_spilled_register(reg2, node));
|
||||
else
|
||||
insert_load_spilled_register(instr, reg2, node);
|
||||
}
|
||||
|
||||
if (writeCounter) {
|
||||
if (node->instr8 || (instr->flags & fPCodeFlag8000))
|
||||
flag = 1;
|
||||
else
|
||||
insert_store_spilled_register(instr, 0, reg2, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
deletepcode(instr);
|
||||
}
|
||||
|
||||
static void spillcopy(PCodeBlock *block, PCode *instr) {
|
||||
IGNode *node1;
|
||||
IGNode *node2;
|
||||
int reg;
|
||||
|
||||
node1 = interferencegraph[instr->args[1].data.reg.reg];
|
||||
node2 = interferencegraph[instr->args[0].data.reg.reg];
|
||||
|
||||
if (node1->flags & fSpilled) {
|
||||
if (node2->flags & fSpilled) {
|
||||
reg = used_virtual_registers[coloring_class]++;
|
||||
if (node1->instr8)
|
||||
insertpcodebefore(instr, rematerialize_spilled_register(reg, node1));
|
||||
else
|
||||
insert_load_spilled_register(instr, reg, node1);
|
||||
insert_store_spilled_register(instr, 1, reg, node2);
|
||||
} else {
|
||||
if (node1->instr8)
|
||||
insertpcodebefore(instr, rematerialize_spilled_register(instr->args[0].data.reg.reg, node1));
|
||||
else
|
||||
insert_load_spilled_register(instr, instr->args[0].data.reg.reg, node1);
|
||||
}
|
||||
} else {
|
||||
insert_store_spilled_register(instr, 1, instr->args[1].data.reg.reg, node2);
|
||||
}
|
||||
|
||||
deletepcode(instr);
|
||||
}
|
||||
|
||||
static void spillcall(PCodeBlock *block, PCode *instr) {
|
||||
PCodeArg *opSrc;
|
||||
PCodeArg *opDst;
|
||||
int opCount;
|
||||
int volatileCount;
|
||||
int i;
|
||||
|
||||
opCount = instr->argCount;
|
||||
volatileCount = branch_count_volatiles();
|
||||
|
||||
opDst = instr->args + volatileCount;
|
||||
opSrc = instr->args + volatileCount;
|
||||
for (i = volatileCount; i < opCount; i++) {
|
||||
if (
|
||||
PC_OP_IS_ANY_REGISTER(opSrc, coloring_class) &&
|
||||
opSrc->data.reg.reg >= n_real_registers[coloring_class] &&
|
||||
(interferencegraph[opSrc->data.reg.reg]->flags & fSpilled)
|
||||
)
|
||||
{
|
||||
instr->argCount--;
|
||||
} else {
|
||||
*opDst = *opSrc;
|
||||
opDst++;
|
||||
}
|
||||
opSrc++;
|
||||
}
|
||||
|
||||
spillinstruction(block, instr);
|
||||
}
|
||||
|
||||
static void assign_spill_locations(void) {
|
||||
UInt32 i;
|
||||
IGNode *node;
|
||||
Type *type;
|
||||
|
||||
last_unused_vreg_before_spilling = used_virtual_registers[coloring_class];
|
||||
for (i = n_real_registers[coloring_class]; i < last_unused_vreg_before_spilling; i++) {
|
||||
node = interferencegraph[i];
|
||||
if (node->flags & fCoalesced)
|
||||
continue;
|
||||
if (!(node->flags & fSpilled))
|
||||
continue;
|
||||
|
||||
if (!node->spillTemporary) {
|
||||
switch (coloring_class) {
|
||||
case RegClass_GPR:
|
||||
type = TYPE(&stunsignedlong);
|
||||
break;
|
||||
case RegClass_CRFIELD:
|
||||
type = TYPE(&stunsignedlong);
|
||||
break;
|
||||
case RegClass_FPR:
|
||||
type = TYPE(&stunsignedlong);
|
||||
break;
|
||||
case RegClass_VR:
|
||||
type = TYPE(&stvectorunsignedchar);
|
||||
break;
|
||||
default:
|
||||
#line 771
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
node->spillTemporary = makespilltemporary(type);
|
||||
}
|
||||
|
||||
if (node->spillTemporary->datatype == DLOCAL && !(node->spillTemporary->u.var.info->flags & VarInfoFlag1))
|
||||
assign_local_memory(node->spillTemporary);
|
||||
|
||||
if (node->flags & fPairHigh)
|
||||
Registers_GetVarInfo(node->spillTemporary)->regHi = Register0;
|
||||
else
|
||||
Registers_GetVarInfo(node->spillTemporary)->reg = Register0;
|
||||
}
|
||||
}
|
||||
|
||||
void insertspillcode(void) {
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
PCode *nextInstr;
|
||||
PCodeArg *op;
|
||||
UInt32 i;
|
||||
int flag;
|
||||
|
||||
rTEMP_for_VR_spill = 0;
|
||||
assign_spill_locations();
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (instr = block->firstPCode; instr; instr = nextInstr) {
|
||||
nextInstr = instr->nextPCode;
|
||||
flag = 0;
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
PC_OP_IS_ANY_REGISTER(op, coloring_class) &&
|
||||
op->data.reg.reg < last_unused_vreg_before_spilling &&
|
||||
(interferencegraph[op->data.reg.reg]->flags & fSpilled)
|
||||
)
|
||||
{
|
||||
flag = 1;
|
||||
break;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
if (coloring_class == RegClass_VR && rTEMP_for_VR_spill == 0)
|
||||
rTEMP_for_VR_spill = used_virtual_registers[RegClass_GPR]++;
|
||||
|
||||
if (instr->flags & fPCodeFlag10)
|
||||
spillcopy(block, instr);
|
||||
else if (instr->flags & fPCodeFlag8)
|
||||
spillcall(block, instr);
|
||||
else
|
||||
spillinstruction(block, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,752 @@
|
||||
#include "compiler/StrengthReduction.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/LoopDetection.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeInfo.h"
|
||||
#include "compiler/UseDefChains.h"
|
||||
|
||||
int strengthreducedloops;
|
||||
|
||||
static PCode *findinitializer(Loop *loop, short reg) {
|
||||
UInt32 *vec;
|
||||
PCode *best;
|
||||
RegUseOrDef *list;
|
||||
|
||||
vec = usedefinfo[loop->body->blockIndex].defvec8;
|
||||
best = NULL;
|
||||
|
||||
for (list = reg_Defs[RegClass_GPR][reg]; list; list = list->next) {
|
||||
if (
|
||||
!(bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)) &&
|
||||
bitvectorgetbit(list->id, vec)
|
||||
)
|
||||
{
|
||||
if (best)
|
||||
return NULL;
|
||||
best = Defs[list->id].pcode;
|
||||
}
|
||||
}
|
||||
|
||||
if (best) {
|
||||
if (best->op == PC_LI || best->op == PC_ADDI || best->op == PC_ADD)
|
||||
return best;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int isbasicinductionvariable(Loop *loop, short reg, SInt32 step) {
|
||||
RegUseOrDef *list;
|
||||
PCode *instr;
|
||||
|
||||
for (list = reg_Defs[RegClass_GPR][reg]; list; list = list->next) {
|
||||
instr = Defs[list->id].pcode;
|
||||
if (bitvectorgetbit(instr->block->blockIndex, loop->memberblocks)) {
|
||||
if (instr->op != PC_ADDI)
|
||||
return 0;
|
||||
if (instr->args[1].data.reg.reg != reg)
|
||||
return 0;
|
||||
if (instr->args[2].data.imm.value != step)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void addbasicinductionvariable(Loop *loop, short reg, SInt32 step) {
|
||||
BasicInductionVar *biv;
|
||||
RegUseOrDef *list;
|
||||
PCode *instr;
|
||||
InstrList *instrList;
|
||||
|
||||
for (biv = loop->basicInductionVars; biv; biv = biv->next) {
|
||||
if (biv->reg == reg)
|
||||
return;
|
||||
}
|
||||
|
||||
biv = oalloc(sizeof(BasicInductionVar));
|
||||
biv->next = loop->basicInductionVars;
|
||||
loop->basicInductionVars = biv;
|
||||
|
||||
biv->loop = loop;
|
||||
biv->inductionVars = NULL;
|
||||
biv->instrsC = NULL;
|
||||
biv->step = step;
|
||||
biv->reg = reg;
|
||||
|
||||
for (list = reg_Defs[RegClass_GPR][reg]; list; list = list->next) {
|
||||
instr = Defs[list->id].pcode;
|
||||
if (bitvectorgetbit(instr->block->blockIndex, loop->memberblocks)) {
|
||||
instrList = oalloc(sizeof(InstrList));
|
||||
instrList->next = biv->instrsC;
|
||||
biv->instrsC = instrList;
|
||||
instrList->instr = instr;
|
||||
}
|
||||
}
|
||||
|
||||
biv->initializer = findinitializer(loop, reg);
|
||||
}
|
||||
|
||||
static void findbasicinductionvariables(Loop *loop) {
|
||||
SInt16 step;
|
||||
BlockList *block;
|
||||
PCode *instr;
|
||||
short reg;
|
||||
|
||||
for (block = loop->blocks; block; block = block->next) {
|
||||
for (instr = block->block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
if (instr->op == PC_ADDI) {
|
||||
if (
|
||||
(reg = instr->args[0].data.reg.reg) >= 32 &&
|
||||
instr->args[1].data.reg.reg == reg &&
|
||||
isbasicinductionvariable(loop, reg, step = instr->args[2].data.imm.value)
|
||||
)
|
||||
addbasicinductionvariable(loop, reg, step);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void findallbasicinductionvariables(Loop *loop) {
|
||||
while (loop) {
|
||||
if (loop->children)
|
||||
findallbasicinductionvariables(loop->children);
|
||||
findbasicinductionvariables(loop);
|
||||
loop = loop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
static int isinductionvariable(BasicInductionVar *biv, int useID, SInt32 *result1, short *result2, short *result3, Loop **result4) {
|
||||
RegUseOrDef *list;
|
||||
int counter;
|
||||
Loop *loop;
|
||||
Loop *scanloop;
|
||||
PCode *instr;
|
||||
|
||||
instr = Uses[useID].pcode;
|
||||
*result2 = 0;
|
||||
*result3 = 0;
|
||||
*result4 = NULL;
|
||||
|
||||
switch (instr->op) {
|
||||
case PC_MULLI:
|
||||
*result1 = instr->args[2].data.imm.value;
|
||||
break;
|
||||
|
||||
case PC_RLWINM:
|
||||
if (instr->args[3].data.imm.value)
|
||||
return 0;
|
||||
if (instr->args[2].data.imm.value > 15)
|
||||
return 0;
|
||||
if (instr->args[4].data.imm.value != (31 - instr->args[2].data.imm.value))
|
||||
return 0;
|
||||
if (PCODE_FLAG_SET_F(instr) & fPCodeFlag20000000)
|
||||
return 0;
|
||||
*result1 = 1 << instr->args[2].data.imm.value;
|
||||
break;
|
||||
|
||||
case PC_LBZX:
|
||||
case PC_LHZX:
|
||||
case PC_LHAX:
|
||||
case PC_LWZX:
|
||||
case PC_STBX:
|
||||
case PC_STHX:
|
||||
case PC_STWX:
|
||||
case PC_LFSX:
|
||||
case PC_LFDX:
|
||||
case PC_STFSX:
|
||||
case PC_STFDX:
|
||||
*result2 = 0;
|
||||
*result3 = 0;
|
||||
if (instr->args[1].data.reg.reg == biv->reg) {
|
||||
*result2 = 1;
|
||||
*result3 = 2;
|
||||
} else if (instr->args[2].data.reg.reg == biv->reg) {
|
||||
*result2 = 2;
|
||||
*result3 = 1;
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
for (list = reg_Defs[RegClass_GPR][instr->args[*result3].data.reg.reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, biv->loop->memberblocks))
|
||||
counter++;
|
||||
}
|
||||
if (counter)
|
||||
return 0;
|
||||
|
||||
loop = biv->loop;
|
||||
for (scanloop = loop->parent; scanloop; scanloop = scanloop->parent) {
|
||||
counter = 0;
|
||||
for (list = reg_Defs[RegClass_GPR][instr->args[*result3].data.reg.reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, scanloop->memberblocks))
|
||||
counter++;
|
||||
}
|
||||
if (!biv->initializer || bitvectorgetbit(biv->initializer->block->blockIndex, scanloop->memberblocks))
|
||||
counter++;
|
||||
if (counter)
|
||||
break;
|
||||
loop = scanloop;
|
||||
}
|
||||
|
||||
*result4 = loop;
|
||||
*result1 = 1;
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
for (list = reg_Defs[RegClass_GPR][instr->args[0].data.reg.reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, biv->loop->memberblocks))
|
||||
counter++;
|
||||
}
|
||||
|
||||
return counter == 1;
|
||||
}
|
||||
|
||||
static void addinductionvariable(BasicInductionVar *biv, PCode *instr, SInt32 val1, short val2, short val3, Loop *val4) {
|
||||
InductionVar *iv;
|
||||
|
||||
iv = oalloc(sizeof(InductionVar));
|
||||
iv->next = biv->inductionVars;
|
||||
biv->inductionVars = iv;
|
||||
|
||||
iv->basicVar = biv;
|
||||
iv->instr = instr;
|
||||
iv->instrC = NULL;
|
||||
iv->step = val1;
|
||||
iv->x18 = val2;
|
||||
iv->x1A = val3;
|
||||
iv->someloop = val4;
|
||||
if (instr->flags & (fPCodeFlag2 | fPCodeFlag4))
|
||||
iv->x1C = -1;
|
||||
else
|
||||
iv->x1C = instr->args[0].data.reg.reg;
|
||||
iv->x1E = -1;
|
||||
}
|
||||
|
||||
static void findnonbasicinductionvariables(Loop *loop) {
|
||||
BasicInductionVar *biv;
|
||||
RegUseOrDef *list;
|
||||
SInt32 result1;
|
||||
short result2;
|
||||
short result3;
|
||||
Loop *result4;
|
||||
|
||||
for (biv = loop->basicInductionVars; biv; biv = biv->next) {
|
||||
for (list = reg_Uses[RegClass_GPR][biv->reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)) {
|
||||
if (isinductionvariable(biv, list->id, &result1, &result2, &result3, &result4))
|
||||
addinductionvariable(biv, Uses[list->id].pcode, result1, result2, result3, result4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void findallnonbasicinductionvariables(Loop *loop) {
|
||||
while (loop) {
|
||||
if (loop->children)
|
||||
findallnonbasicinductionvariables(loop->children);
|
||||
if (loop->basicInductionVars)
|
||||
findnonbasicinductionvariables(loop);
|
||||
loop = loop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
static void initializeinductionvariable(InductionVar *iv) {
|
||||
BasicInductionVar *biv; // r31
|
||||
PCode *instr; // r27
|
||||
PCodeBlock *preheader; // r30
|
||||
SInt32 value30; // r30
|
||||
short reg29; // r29
|
||||
short reg26; // r26
|
||||
|
||||
biv = iv->basicVar;
|
||||
preheader = biv->loop->preheader;
|
||||
|
||||
if (iv->x1A) {
|
||||
reg29 = iv->instr->args[iv->x1A].data.reg.reg;
|
||||
reg26 = iv->instr->args[iv->x18].data.reg.reg;
|
||||
instr = NULL;
|
||||
|
||||
if (
|
||||
biv->initializer &&
|
||||
biv->initializer->op == PC_LI &&
|
||||
biv->initializer->block == preheader
|
||||
)
|
||||
{
|
||||
if (biv->initializer->args[1].data.imm.value == 0)
|
||||
instr = makepcode(PC_MR, iv->x1E, reg29);
|
||||
else if (FITS_IN_SHORT(biv->initializer->args[1].data.imm.value))
|
||||
instr = makepcode(PC_ADDI, iv->x1E, reg29, 0, biv->initializer->args[1].data.imm.value);
|
||||
}
|
||||
|
||||
if (!instr)
|
||||
instr = makepcode(PC_ADD, iv->x1E, reg29, reg26);
|
||||
|
||||
if (biv->initializer && instr->op != PC_ADD)
|
||||
insertpcodeafter(biv->initializer, instr);
|
||||
else if (iv->someloop && iv->someloop->preheader->lastPCode)
|
||||
insertpcodebefore(iv->someloop->preheader->lastPCode, instr);
|
||||
else
|
||||
insertpcodebefore(preheader->lastPCode, instr);
|
||||
|
||||
iv->instrC = instr;
|
||||
iv->x1C = reg29;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!biv->initializer || biv->initializer->op != PC_LI) {
|
||||
instr = copypcode(iv->instr);
|
||||
instr->args[0].data.reg.reg = iv->x1E;
|
||||
insertpcodebefore(preheader->lastPCode, instr);
|
||||
} else {
|
||||
value30 = biv->initializer->args[1].data.imm.value * iv->step;
|
||||
if (!FITS_IN_SHORT(value30)) {
|
||||
instr = makepcode(PC_LIS, iv->x1E, 0, HIGH_PART(value30));
|
||||
insertpcodeafter(biv->initializer, instr);
|
||||
if (value30 != 0)
|
||||
insertpcodeafter(instr, makepcode(PC_ADDI, iv->x1E, iv->x1E, 0, LOW_PART(value30)));
|
||||
} else {
|
||||
instr = makepcode(PC_LI, iv->x1E, value30);
|
||||
insertpcodeafter(biv->initializer, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void incrementinductionvariable(InductionVar *iv) {
|
||||
SInt32 value;
|
||||
BasicInductionVar *biv;
|
||||
PCode *instr;
|
||||
InstrList *list;
|
||||
|
||||
biv = iv->basicVar;
|
||||
value = iv->step * biv->step;
|
||||
for (list = biv->instrsC; list; list = list->next) {
|
||||
if (!FITS_IN_SHORT(value)) {
|
||||
instr = makepcode(PC_ADDIS, iv->x1E, iv->x1E, 0, HIGH_PART(value));
|
||||
insertpcodeafter(list->instr, instr);
|
||||
|
||||
if (value != 0) {
|
||||
instr = makepcode(PC_ADDI, iv->x1E, iv->x1E, 0, LOW_PART(value));
|
||||
insertpcodeafter(list->instr->nextPCode, instr);
|
||||
}
|
||||
} else {
|
||||
instr = makepcode(PC_ADDI, iv->x1E, iv->x1E, 0, value);
|
||||
insertpcodeafter(list->instr, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void copyinductionvariable(InductionVar *iv) {
|
||||
if (iv->instr->flags & (fPCodeFlag2 | fPCodeFlag4)) {
|
||||
iv->instr->op -= 2;
|
||||
iv->instr->args[1].data.reg.reg = iv->x1E;
|
||||
iv->instr->args[2].kind = PCOp_IMMEDIATE;
|
||||
iv->instr->args[2].data.imm.value = 0;
|
||||
iv->instr->args[2].data.imm.obj = NULL;
|
||||
} else {
|
||||
insertpcodeafter(iv->instr, makepcode(PC_MR, iv->x1C, iv->x1E));
|
||||
deletepcode(iv->instr);
|
||||
}
|
||||
}
|
||||
|
||||
static int testnestediv(InductionVar *iv, SInt32 step1, int reg, SInt32 step2, Loop *loop1, Loop *loop2) {
|
||||
SInt32 addend;
|
||||
BlockList *list;
|
||||
PCode *instr;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
if (iv->instrC && iv->x1C == reg) {
|
||||
if (iv->instrC->op == PC_MR)
|
||||
addend = 0;
|
||||
else if (iv->instrC->op == PC_ADDI)
|
||||
addend = iv->instrC->args[2].data.imm.value;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (step2 == (addend + (step1 * iv->step * loop2->iterationCount))) {
|
||||
for (list = loop1->blocks; list && list->block != loop2->blocks->block; list = list->next) {
|
||||
for (instr = list->block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
op->data.reg.reg == reg
|
||||
)
|
||||
return 0;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void strengthreducenestediv(short reg, SInt32 step, PCode *initializer, Loop *loop) {
|
||||
Loop *scanloop;
|
||||
BasicInductionVar *biv;
|
||||
InductionVar *iv;
|
||||
PCode *instr;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
for (scanloop = loop->children; scanloop; scanloop = scanloop->nextSibling) {
|
||||
if (
|
||||
scanloop->isKnownCountingLoop &&
|
||||
scanloop->x4F &&
|
||||
bitvectorgetbit(scanloop->body->blockIndex, loop->vec2C)
|
||||
)
|
||||
{
|
||||
for (biv = scanloop->basicInductionVars; biv; biv = biv->next) {
|
||||
for (iv = biv->inductionVars; iv; iv = iv->next) {
|
||||
if (testnestediv(iv, biv->step, reg, step, loop, scanloop)) {
|
||||
deletepcode(iv->instrC);
|
||||
if (initializer) {
|
||||
insertpcodeafter(initializer, iv->instrC);
|
||||
} else if (loop->body->lastPCode) {
|
||||
for (instr = loop->body->lastPCode; instr; instr = instr->prevPCode) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
op->data.reg.reg == reg
|
||||
)
|
||||
break;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
|
||||
if (instr)
|
||||
insertpcodeafter(instr, iv->instrC);
|
||||
else
|
||||
insertpcodebefore(loop->body->firstPCode, iv->instrC);
|
||||
} else {
|
||||
appendpcode(loop->body, iv->instrC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void strengthreducenestedbiv(BasicInductionVar *biv) {
|
||||
Loop *loop;
|
||||
InductionVar *iv;
|
||||
|
||||
loop = biv->loop;
|
||||
for (iv = biv->inductionVars; iv; iv = iv->next)
|
||||
strengthreducenestediv(iv->x1E, iv->step * biv->step, iv->instrC, loop);
|
||||
|
||||
strengthreducenestediv(biv->reg, biv->step, biv->initializer, loop);
|
||||
}
|
||||
|
||||
static void strengthreduceinductionvariable(BasicInductionVar *biv) {
|
||||
int counter;
|
||||
InductionVar *iv;
|
||||
InductionVar *otherIv;
|
||||
short reg;
|
||||
|
||||
counter = 0;
|
||||
for (iv = biv->inductionVars; iv; iv = iv->next) {
|
||||
if (iv->step == 1)
|
||||
counter++;
|
||||
}
|
||||
|
||||
for (iv = biv->inductionVars; iv; iv = iv->next) {
|
||||
if (
|
||||
(counter <= 4 || iv->step != 1) &&
|
||||
iv->instr->block &&
|
||||
(iv->x1A == 0 || iv->instr->args[2].kind != PCOp_IMMEDIATE)
|
||||
)
|
||||
{
|
||||
if (iv->x1E == -1) {
|
||||
iv->x1E = used_virtual_registers[RegClass_GPR]++;
|
||||
initializeinductionvariable(iv);
|
||||
incrementinductionvariable(iv);
|
||||
if (iv->step == 1) {
|
||||
reg = iv->instr->args[iv->x1A].data.reg.reg;
|
||||
for (otherIv = iv->next; otherIv; otherIv = otherIv->next) {
|
||||
if (otherIv->x1A != 0 && otherIv->instr->args[otherIv->x1A].data.reg.reg == reg)
|
||||
otherIv->x1E = iv->x1E;
|
||||
}
|
||||
} else {
|
||||
for (otherIv = iv->next; otherIv; otherIv = otherIv->next) {
|
||||
if (otherIv->step == iv->step)
|
||||
otherIv->x1E = iv->x1E;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copyinductionvariable(iv);
|
||||
strengthreducedloops = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct BivInit {
|
||||
SInt32 x0;
|
||||
short x4;
|
||||
short x6;
|
||||
short x8;
|
||||
Object *xA;
|
||||
} BivInit;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
static void calc_biv_init(BasicInductionVar *biv, BivInit *init) {
|
||||
PCode *instr;
|
||||
PCode *scan;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
instr = biv->initializer;
|
||||
init->x0 = 0;
|
||||
init->x4 = -1;
|
||||
init->x6 = -1;
|
||||
init->x8 = 0;
|
||||
init->xA = NULL;
|
||||
|
||||
if (!biv->initializer || (biv->initializer->op != PC_ADDI && biv->initializer->op != PC_ADD))
|
||||
return;
|
||||
|
||||
if (instr->op == PC_ADDI) {
|
||||
if (instr->args[1].data.reg.reg == biv->reg) {
|
||||
init->x0 = instr->args[2].data.imm.value;
|
||||
for (scan = instr->prevPCode; scan; scan = scan->prevPCode) {
|
||||
op = scan->args;
|
||||
i = scan->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
op->data.reg.reg == biv->reg &&
|
||||
(op->data.reg.effect & EffectWrite)
|
||||
)
|
||||
{
|
||||
if (scan->op == PC_ADD) {
|
||||
init->x4 = scan->args[1].data.reg.reg;
|
||||
init->x6 = scan->args[2].data.reg.reg;
|
||||
} else if (scan->op == PC_ADDI) {
|
||||
if (scan->args[2].kind == PCOp_IMMEDIATE) {
|
||||
init->x4 = scan->args[1].data.reg.reg;
|
||||
init->x8 = scan->args[2].data.imm.value;
|
||||
} else if (scan->args[2].kind == PCOp_MEMORY) {
|
||||
init->x4 = scan->args[1].data.reg.reg;
|
||||
init->x8 = scan->args[2].data.mem.offset;
|
||||
init->xA = scan->args[2].data.mem.obj;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (instr->args[2].kind == PCOp_IMMEDIATE) {
|
||||
init->x4 = instr->args[1].data.reg.reg;
|
||||
init->x8 = instr->args[2].data.imm.value;
|
||||
} else if (instr->args[2].kind == PCOp_MEMORY) {
|
||||
init->x4 = instr->args[1].data.reg.reg;
|
||||
init->x8 = instr->args[2].data.mem.offset;
|
||||
init->xA = instr->args[2].data.mem.obj;
|
||||
}
|
||||
}
|
||||
} else if (instr->op == PC_ADD) {
|
||||
if (instr->args[1].data.reg.reg == biv->reg) {
|
||||
init->x6 = instr->args[2].data.reg.reg;
|
||||
for (scan = instr->prevPCode; scan; scan = scan->prevPCode) {
|
||||
op = scan->args;
|
||||
i = scan->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
op->data.reg.reg == biv->reg &&
|
||||
(op->data.reg.effect & EffectWrite) &&
|
||||
scan->op == PC_ADDI
|
||||
)
|
||||
{
|
||||
if (scan->args[2].kind == PCOp_IMMEDIATE) {
|
||||
init->x4 = scan->args[1].data.reg.reg;
|
||||
init->x8 = scan->args[2].data.imm.value;
|
||||
} else if (scan->args[2].kind == PCOp_MEMORY) {
|
||||
init->x4 = scan->args[1].data.reg.reg;
|
||||
init->x8 = scan->args[2].data.mem.offset;
|
||||
init->xA = scan->args[2].data.mem.obj;
|
||||
}
|
||||
return;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
init->x4 = instr->args[1].data.reg.reg;
|
||||
init->x6 = instr->args[2].data.reg.reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void combineinductionvariables(Loop *loop, BasicInductionVar *biv1, BasicInductionVar *biv2, SInt32 difference) {
|
||||
PCode *instr1; // r31
|
||||
int reg1; // r30
|
||||
int reg2; // r29
|
||||
PCode *instr2; // r24
|
||||
PCodeBlock *nextBlock; // r24
|
||||
BlockList *list;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
PCode *instr;
|
||||
|
||||
instr1 = NULL;
|
||||
instr2 = NULL;
|
||||
|
||||
reg1 = biv1->reg;
|
||||
#line 930
|
||||
CError_ASSERT(reg1 >= 0);
|
||||
|
||||
reg2 = biv2->reg;
|
||||
#line 934
|
||||
CError_ASSERT(reg2 >= 0);
|
||||
|
||||
if (!FITS_IN_SHORT(difference))
|
||||
return;
|
||||
|
||||
for (list = loop->blocks; list; list = list->next) {
|
||||
for (instr = list->block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
if (instr1) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
op->arg == RegClass_GPR &&
|
||||
op->data.reg.reg == reg1
|
||||
)
|
||||
return;
|
||||
op++;
|
||||
}
|
||||
}
|
||||
|
||||
if (instr->op == PC_ADDI) {
|
||||
if (instr->args[0].data.reg.reg == reg1) {
|
||||
if (instr1)
|
||||
return;
|
||||
instr1 = instr;
|
||||
} else if (instr->args[0].data.reg.reg == reg2) {
|
||||
if (instr2)
|
||||
return;
|
||||
instr2 = instr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loop->body->lastPCode->flags & fPCodeFlag1) {
|
||||
nextBlock = NULL;
|
||||
|
||||
for (i = 0; i < loop->body->lastPCode->argCount; i++) {
|
||||
if (loop->body->lastPCode->args[i].kind == PCOp_LABEL) {
|
||||
nextBlock = loop->body->lastPCode->args[i].data.label.label->block;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nextBlock)
|
||||
return;
|
||||
} else {
|
||||
nextBlock = loop->body->nextBlock;
|
||||
}
|
||||
|
||||
deletepcode(instr1);
|
||||
instr1->args[1].data.reg.reg = reg2;
|
||||
instr1->args[2].data.imm.value = difference;
|
||||
|
||||
if (nextBlock->firstPCode)
|
||||
insertpcodebefore(nextBlock->firstPCode, instr1);
|
||||
else
|
||||
appendpcode(nextBlock, instr1);
|
||||
|
||||
biv1->reg = -1;
|
||||
strengthreducedloops = 1;
|
||||
}
|
||||
|
||||
static void strengthreduceinductionvariables(Loop *loop) {
|
||||
BasicInductionVar *biv1;
|
||||
BasicInductionVar *biv2;
|
||||
BivInit init1;
|
||||
BivInit init2;
|
||||
|
||||
for (biv1 = loop->basicInductionVars; biv1; biv1 = biv1->next) {
|
||||
if (biv1->inductionVars)
|
||||
strengthreduceinductionvariable(biv1);
|
||||
strengthreducenestedbiv(biv1);
|
||||
}
|
||||
|
||||
for (biv1 = loop->basicInductionVars; biv1; biv1 = biv1->next) {
|
||||
if (biv1->reg != -1) {
|
||||
calc_biv_init(biv1, &init1);
|
||||
if (init1.x4 != -1) {
|
||||
for (biv2 = loop->basicInductionVars; biv2; biv2 = biv2->next) {
|
||||
if (biv2->reg != -1 && biv2 != biv1) {
|
||||
calc_biv_init(biv2, &init2);
|
||||
if (
|
||||
init2.x4 != -1 &&
|
||||
init1.x4 == init2.x4 &&
|
||||
init1.x6 == init2.x6 &&
|
||||
init1.x8 == init2.x8 &&
|
||||
init1.xA == init2.xA &&
|
||||
biv1->step == biv2->step
|
||||
)
|
||||
{
|
||||
if (init1.x0 < init2.x0) {
|
||||
combineinductionvariables(loop, biv2, biv1, init2.x0 - init1.x0);
|
||||
} else {
|
||||
combineinductionvariables(loop, biv1, biv2, init1.x0 - init2.x0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void strengthreduceallinductionvariables(Loop *loop) {
|
||||
while (loop) {
|
||||
if (loop->children)
|
||||
strengthreduceallinductionvariables(loop->children);
|
||||
if (loop->basicInductionVars)
|
||||
strengthreduceinductionvariables(loop);
|
||||
loop = loop->nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
void strengthreduceloops(void) {
|
||||
strengthreducedloops = 0;
|
||||
if (loopsinflowgraph) {
|
||||
computeusedefchains(0);
|
||||
findallbasicinductionvariables(loopsinflowgraph);
|
||||
findallnonbasicinductionvariables(loopsinflowgraph);
|
||||
strengthreduceallinductionvariables(loopsinflowgraph);
|
||||
freeoheap();
|
||||
}
|
||||
}
|
@ -2,13 +2,20 @@
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CFunc.h"
|
||||
#include "compiler/CInt64.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/InstrSelection.h"
|
||||
#include "compiler/ObjGenMachO.h"
|
||||
#include "compiler/Operands.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeUtilities.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
#include "compiler/TOC.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/objects.h"
|
||||
|
||||
ObjectList *switchtables;
|
||||
static void *caselabels;
|
||||
static void *caseranges;
|
||||
static SwitchCase **caselabels;
|
||||
static CaseRange *caseranges;
|
||||
static SInt32 ncases;
|
||||
static SInt32 nranges_minus1;
|
||||
static CInt64 min;
|
||||
@ -20,25 +27,446 @@ static Type *selector_type;
|
||||
static PCodeLabel *defaultlabel;
|
||||
static CInt64 range;
|
||||
|
||||
static void compare_cases() {
|
||||
static int compare_cases(const void *a, const void *b) {
|
||||
const SwitchCase **casea = (const SwitchCase **) a;
|
||||
const SwitchCase **caseb = (const SwitchCase **) b;
|
||||
|
||||
if (CInt64_Less((*casea)->min, (*caseb)->min))
|
||||
return -1;
|
||||
if (CInt64_Greater((*casea)->min, (*caseb)->min))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void build_case_ranges(Type *type, SwitchCase *cases, CLabel *label) {
|
||||
SwitchCase **caseptr;
|
||||
SInt32 i;
|
||||
SwitchCase *curcase;
|
||||
CaseRange *currange;
|
||||
|
||||
if (type->size == 8) {
|
||||
min.lo = 0;
|
||||
min.hi = 0x80000000;
|
||||
max.lo = 0xFFFFFFFF;
|
||||
max.hi = 0x7FFFFFFF;
|
||||
} else if (type->size == 4) {
|
||||
CInt64_SetLong(&min, 0x80000000);
|
||||
CInt64_SetLong(&max, 0x7FFFFFFF);
|
||||
} else if (is_unsigned(type)) {
|
||||
min.hi = 0;
|
||||
min.lo = 0;
|
||||
max.hi = 0;
|
||||
max.lo = 0xFFFF;
|
||||
} else {
|
||||
CInt64_SetLong(&min, -0x8000);
|
||||
CInt64_SetLong(&max, 0x7FFF);
|
||||
}
|
||||
|
||||
static void treecompare() {
|
||||
caselabels = lalloc(sizeof(SwitchCase *) * ncases);
|
||||
caseptr = caselabels;
|
||||
while (cases) {
|
||||
*caseptr = cases;
|
||||
cases = cases->next;
|
||||
++caseptr;
|
||||
}
|
||||
|
||||
static void I8_treecompare() {
|
||||
caseranges = lalloc(((ncases * 2) + 2) * sizeof(CaseRange));
|
||||
if (type->size < 8) {
|
||||
for (i = 0; i < ncases; i++)
|
||||
CInt64_SetLong(&caselabels[i]->min, caselabels[i]->min.lo);
|
||||
}
|
||||
|
||||
qsort(caselabels, ncases, sizeof(SwitchCase *), &compare_cases);
|
||||
|
||||
currange = caseranges;
|
||||
currange->min = min;
|
||||
currange->range = CInt64_Sub(max, min);
|
||||
currange->label = label->pclabel;
|
||||
|
||||
for (i = 0; i < ncases; i++) {
|
||||
curcase = caselabels[i];
|
||||
if (CInt64_GreaterEqual(curcase->min, min) && CInt64_LessEqual(curcase->min, max)) {
|
||||
if (CInt64_Equal(currange->min, min))
|
||||
first = curcase->min;
|
||||
range = CInt64_Sub(curcase->min, first);
|
||||
|
||||
if (CInt64_Greater(curcase->min, currange->min)) {
|
||||
currange->range = CInt64_Sub(CInt64_Sub(curcase->min, currange->min), cint64_one);
|
||||
(++currange)->min = curcase->min;
|
||||
} else if (CInt64_Greater(currange->min, min) && curcase->label->pclabel == currange[-1].label) {
|
||||
currange[-1].range = CInt64_Add(currange[-1].range, cint64_one);
|
||||
if (CInt64_Equal(currange->range, cint64_zero)) {
|
||||
currange--;
|
||||
} else {
|
||||
currange->min = CInt64_Add(currange->min, cint64_one);
|
||||
currange->range = CInt64_Sub(currange->range, cint64_one);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
currange->range = cint64_zero;
|
||||
currange->label = curcase->label->pclabel;
|
||||
|
||||
if (CInt64_Less(curcase->min, max)) {
|
||||
currange++;
|
||||
currange->min = CInt64_Add(curcase->min, cint64_one);
|
||||
currange->range = CInt64_Sub(max, currange->min);
|
||||
currange->label = label->pclabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nranges_minus1 = currange - caseranges;
|
||||
}
|
||||
|
||||
static void treecompare(SInt32 start, SInt32 end) {
|
||||
SInt32 r30;
|
||||
SInt32 r29;
|
||||
CaseRange *currange;
|
||||
int count;
|
||||
|
||||
count = end - start;
|
||||
#line 175
|
||||
CError_ASSERT(selector_type->size <= 4);
|
||||
|
||||
r29 = start + (count >> 1) + 1;
|
||||
currange = caseranges + r29;
|
||||
|
||||
if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) {
|
||||
currange--;
|
||||
r29--;
|
||||
}
|
||||
|
||||
r30 = r29 - 1;
|
||||
|
||||
if (selector_type->size < 4 && is_unsigned(selector_type)) {
|
||||
emitpcode(PC_CMPLI, 0, selector_gpr, CInt64_GetULong(&currange->min));
|
||||
} else if (FITS_IN_SHORT((SInt32) CInt64_GetULong(&currange->min))) {
|
||||
emitpcode(PC_CMPI, 0, selector_gpr, CInt64_GetULong(&currange->min));
|
||||
} else {
|
||||
SInt32 value = CInt64_GetULong(&currange->min);
|
||||
int reg = ALLOC_GPR();
|
||||
load_immediate(reg, value);
|
||||
emitpcode(PC_CMP, 0, selector_gpr, reg);
|
||||
}
|
||||
|
||||
if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) {
|
||||
branch_conditional(0, EEQU, 1, currange->label);
|
||||
r29++;
|
||||
}
|
||||
|
||||
if (r29 == end) {
|
||||
if (start == r30) {
|
||||
if (caseranges[start].label == caseranges[end].label) {
|
||||
branch_always(caseranges[start].label);
|
||||
} else {
|
||||
branch_conditional(0, EGREATEREQU, 1, caseranges[end].label);
|
||||
branch_always(caseranges[start].label);
|
||||
}
|
||||
} else {
|
||||
branch_conditional(0, EGREATEREQU, 1, caseranges[end].label);
|
||||
treecompare(start, r30);
|
||||
}
|
||||
} else {
|
||||
if (start == r30) {
|
||||
branch_conditional(0, ELESS, 1, caseranges[start].label);
|
||||
treecompare(r29, end);
|
||||
} else {
|
||||
PCodeLabel *label = makepclabel();
|
||||
branch_conditional(0, EGREATEREQU, 1, label);
|
||||
treecompare(start, r30);
|
||||
branch_label(label);
|
||||
treecompare(r29, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void I8_treecompare(SInt32 start, SInt32 end) {
|
||||
SInt32 r30;
|
||||
SInt32 r29;
|
||||
CaseRange *currange;
|
||||
int count;
|
||||
|
||||
count = end - start;
|
||||
|
||||
r29 = start + (count >> 1) + 1;
|
||||
currange = caseranges + r29;
|
||||
|
||||
if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) {
|
||||
currange--;
|
||||
r29--;
|
||||
}
|
||||
|
||||
r30 = r29 - 1;
|
||||
|
||||
if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) {
|
||||
short a = ALLOC_GPR();
|
||||
short b = ALLOC_GPR();
|
||||
load_immediate(a, currange->min.lo);
|
||||
load_immediate(b, currange->min.hi);
|
||||
emitpcode(PC_XOR, a, selector_gpr, a);
|
||||
emitpcode(PC_XOR, b, selector_gprHi, b);
|
||||
emitpcode(PC_OR, b, a, b);
|
||||
emitpcode(PC_CMPI, 0, b, 0);
|
||||
branch_conditional(0, EEQU, 1, currange->label);
|
||||
r29++;
|
||||
}
|
||||
|
||||
if (r29 == end) {
|
||||
if (start == r30) {
|
||||
if (caseranges[start].label == caseranges[end].label) {
|
||||
branch_always(caseranges[start].label);
|
||||
} else {
|
||||
short a = ALLOC_GPR();
|
||||
short b = ALLOC_GPR();
|
||||
short c = ALLOC_GPR();
|
||||
short d = ALLOC_GPR();
|
||||
load_immediate(a, currange->min.lo);
|
||||
load_immediate(b, currange->min.hi);
|
||||
if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
|
||||
emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
|
||||
emitpcode(PC_XORIS, d, b, 0x8000);
|
||||
} else {
|
||||
c = selector_gprHi;
|
||||
d = b;
|
||||
}
|
||||
emitpcode(PC_SUBFC, a, a, selector_gpr);
|
||||
emitpcode(PC_SUBFE, b, d, c);
|
||||
emitpcode(PC_SUBFE, b, a, a);
|
||||
emitpcode(PC_NEG, b, b);
|
||||
emitpcode(PC_CMPI, 0, b, 0);
|
||||
branch_conditional(0, EEQU, 1, caseranges[end].label);
|
||||
branch_always(caseranges[start].label);
|
||||
}
|
||||
} else {
|
||||
short a = ALLOC_GPR();
|
||||
short b = ALLOC_GPR();
|
||||
short c = ALLOC_GPR();
|
||||
short d = ALLOC_GPR();
|
||||
load_immediate(a, currange->min.lo);
|
||||
load_immediate(b, currange->min.hi);
|
||||
if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
|
||||
emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
|
||||
emitpcode(PC_XORIS, d, b, 0x8000);
|
||||
} else {
|
||||
c = selector_gprHi;
|
||||
d = b;
|
||||
}
|
||||
emitpcode(PC_SUBFC, a, a, selector_gpr);
|
||||
emitpcode(PC_SUBFE, b, d, c);
|
||||
emitpcode(PC_SUBFE, b, a, a);
|
||||
emitpcode(PC_NEG, b, b);
|
||||
emitpcode(PC_CMPI, 0, b, 0);
|
||||
branch_conditional(0, EEQU, 1, caseranges[end].label);
|
||||
I8_treecompare(start, r30);
|
||||
}
|
||||
} else {
|
||||
if (start == r30) {
|
||||
short a = ALLOC_GPR();
|
||||
short b = ALLOC_GPR();
|
||||
short c = ALLOC_GPR();
|
||||
short d = ALLOC_GPR();
|
||||
load_immediate(a, currange->min.lo);
|
||||
load_immediate(b, currange->min.hi);
|
||||
if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
|
||||
emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
|
||||
emitpcode(PC_XORIS, d, b, 0x8000);
|
||||
} else {
|
||||
c = selector_gprHi;
|
||||
d = b;
|
||||
}
|
||||
emitpcode(PC_SUBFC, a, selector_gpr, a);
|
||||
emitpcode(PC_SUBFE, b, c, d);
|
||||
emitpcode(PC_SUBFE, b, a, a);
|
||||
emitpcode(PC_NEG, b, b);
|
||||
emitpcode(PC_CMPI, 0, b, 0);
|
||||
branch_conditional(0, ENOTEQU, 1, caseranges[end].label);
|
||||
I8_treecompare(r29, end);
|
||||
} else {
|
||||
PCodeLabel *label;
|
||||
short a = ALLOC_GPR();
|
||||
short b = ALLOC_GPR();
|
||||
short c = ALLOC_GPR();
|
||||
short d = ALLOC_GPR();
|
||||
load_immediate(a, currange->min.lo);
|
||||
load_immediate(b, currange->min.hi);
|
||||
if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
|
||||
emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
|
||||
emitpcode(PC_XORIS, d, b, 0x8000);
|
||||
} else {
|
||||
c = selector_gprHi;
|
||||
d = b;
|
||||
}
|
||||
emitpcode(PC_SUBFC, a, a, selector_gpr);
|
||||
emitpcode(PC_SUBFE, b, d, b);
|
||||
emitpcode(PC_SUBFE, b, a, a);
|
||||
emitpcode(PC_NEG, b, b);
|
||||
emitpcode(PC_CMPI, 0, b, 0);
|
||||
label = makepclabel();
|
||||
branch_conditional(0, EEQU, 1, label);
|
||||
I8_treecompare(start, r30);
|
||||
branch_label(label);
|
||||
I8_treecompare(r29, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_tree(ENode *expr) {
|
||||
Operand op;
|
||||
|
||||
memclrw(&op, sizeof(Operand));
|
||||
if (TYPE_IS_8BYTES(expr->rtype)) {
|
||||
GEN_NODE(expr, &op);
|
||||
coerce_to_register_pair(&op, expr->rtype, 0, 0);
|
||||
selector_type = expr->rtype;
|
||||
selector_gpr = op.reg;
|
||||
selector_gprHi = op.regHi;
|
||||
I8_treecompare(0, nranges_minus1);
|
||||
} else {
|
||||
GEN_NODE(expr, &op);
|
||||
if (expr->rtype->size < 4)
|
||||
extend32(&op, expr->rtype, 0);
|
||||
ENSURE_GPR(&op, expr->rtype, 0);
|
||||
selector_type = expr->rtype;
|
||||
selector_gpr = op.reg;
|
||||
treecompare(0, nranges_minus1);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_switch_table() {
|
||||
static Object *create_switch_table(void) {
|
||||
Object *obj;
|
||||
ObjectList *list;
|
||||
CaseRange *currange;
|
||||
UInt32 *outptr;
|
||||
CInt64 value;
|
||||
|
||||
obj = galloc(sizeof(Object));
|
||||
list = galloc(sizeof(ObjectList));
|
||||
memclrw(obj, sizeof(Object));
|
||||
memclrw(list, sizeof(ObjectList));
|
||||
|
||||
obj->otype = OT_OBJECT;
|
||||
obj->access = ACCESSPUBLIC;
|
||||
obj->datatype = DDATA;
|
||||
obj->name = CParser_GetUniqueName();
|
||||
obj->toc = NULL;
|
||||
obj->sclass = TK_STATIC;
|
||||
obj->qual = Q_CONST;
|
||||
obj->flags |= OBJECT_FLAGS_2 | OBJECT_FLAGS_4;
|
||||
obj->u.data.linkname = obj->name;
|
||||
obj->type = NULL;
|
||||
createIndirect(obj, 0, 0);
|
||||
obj->type = TYPE(&void_ptr);
|
||||
|
||||
obj->u.data.u.switchtable.size = CInt64_GetULong(&range) + 1;
|
||||
obj->u.data.u.switchtable.data = lalloc(4 * obj->u.data.u.switchtable.size);
|
||||
|
||||
currange = caseranges;
|
||||
outptr = (UInt32 *) obj->u.data.u.switchtable.data;
|
||||
value = cint64_zero;
|
||||
while (CInt64_LessEqual(value, range)) {
|
||||
while (CInt64_Greater(CInt64_Add(first, value), CInt64_Add(currange->min, currange->range)))
|
||||
currange++;
|
||||
// HACK - this will not work properly on 64-bit systems
|
||||
*outptr = (UInt32) currange->label;
|
||||
value = CInt64_Add(value, cint64_one);
|
||||
outptr++;
|
||||
}
|
||||
|
||||
list->object = obj;
|
||||
list->next = switchtables;
|
||||
switchtables = list;
|
||||
return list->object;
|
||||
}
|
||||
|
||||
static void generate_table(ENode *expr, SwitchInfo *info) {
|
||||
Object *table;
|
||||
short reg;
|
||||
short reg2;
|
||||
short reg3;
|
||||
SwitchCase *curcase;
|
||||
Operand op1;
|
||||
Operand op2;
|
||||
|
||||
CInt64 val3 = {0, 3};
|
||||
memclrw(&op1, sizeof(Operand));
|
||||
memclrw(&op2, sizeof(Operand));
|
||||
|
||||
if (CInt64_Greater(first, cint64_zero) && CInt64_Less(first, val3)) {
|
||||
range = CInt64_Add(range, first);
|
||||
first = cint64_zero;
|
||||
}
|
||||
|
||||
table = create_switch_table();
|
||||
#line 553
|
||||
CError_ASSERT(!TYPE_IS_8BYTES(expr->rtype));
|
||||
|
||||
GEN_NODE(expr, &op1);
|
||||
if (expr->rtype->size < 4)
|
||||
extend32(&op1, expr->rtype, 0);
|
||||
ENSURE_GPR(&op1, expr->rtype, 0);
|
||||
|
||||
reg = op1.reg;
|
||||
if (CInt64_NotEqual(first, cint64_zero)) {
|
||||
SInt32 value;
|
||||
SInt32 valueext;
|
||||
reg = ALLOC_GPR();
|
||||
value = -CInt64_GetULong(&first);
|
||||
valueext = (SInt16) value;
|
||||
if (value != valueext) {
|
||||
emitpcode(PC_ADDIS, reg, op1.reg, 0, HIGH_PART(value));
|
||||
if (value)
|
||||
emitpcode(PC_ADDI, reg, reg, 0, valueext);
|
||||
} else {
|
||||
emitpcode(PC_ADDI, reg, op1.reg, 0, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (FITS_IN_SHORT(CInt64_GetULong(&range))) {
|
||||
short tmp = ALLOC_GPR();
|
||||
load_immediate(tmp, CInt64_GetULong(&range));
|
||||
emitpcode(PC_CMPL, 0, reg, tmp);
|
||||
} else {
|
||||
emitpcode(PC_CMPLI, 0, reg, CInt64_GetULong(&range));
|
||||
}
|
||||
|
||||
branch_conditional(0, EGREATER, 0, defaultlabel);
|
||||
if (table->toc) {
|
||||
op2.optype = OpndType_Symbol;
|
||||
op2.object = table->toc;
|
||||
indirect(&op2, NULL);
|
||||
} else {
|
||||
op2.optype = OpndType_Symbol;
|
||||
op2.object = table;
|
||||
}
|
||||
|
||||
if (op2.optype != OpndType_GPR) {
|
||||
reg2 = ALLOC_GPR();
|
||||
Coerce_to_register(&op2, TYPE(&void_ptr), reg2);
|
||||
}
|
||||
|
||||
if (op2.optype != OpndType_GPR) {
|
||||
#line 599
|
||||
CError_FATAL();
|
||||
} else {
|
||||
if (op2.reg != reg2)
|
||||
emitpcode(PC_MR, reg2, op2.reg);
|
||||
}
|
||||
|
||||
if (CInt64_Equal(first, cint64_zero)) {
|
||||
reg = ALLOC_GPR();
|
||||
emitpcode(PC_RLWINM, reg, op1.reg, 2, 0, 29);
|
||||
} else {
|
||||
emitpcode(PC_RLWINM, reg, reg, 2, 0, 29);
|
||||
}
|
||||
|
||||
reg3 = reg2;
|
||||
emitpcode(PC_LWZX, reg3, reg3, reg);
|
||||
for (curcase = info->cases; curcase; curcase = curcase->next)
|
||||
pcbranch(pclastblock, curcase->label->pclabel);
|
||||
pcbranch(pclastblock, info->defaultlabel->pclabel);
|
||||
emitpcode(PC_MTCTR, reg3);
|
||||
branch_indirect(table);
|
||||
}
|
||||
|
||||
void switchstatement(ENode *expr, SwitchInfo *info) {
|
||||
@ -55,7 +483,7 @@ void switchstatement(ENode *expr, SwitchInfo *info) {
|
||||
}
|
||||
|
||||
#line 656
|
||||
CError_ASSERT(ncases >= 0 && ncases <= 0x3333332);
|
||||
CError_ASSERT(ncases >= 0 && ncases <= 0x3333332U);
|
||||
|
||||
if (!info->defaultlabel->pclabel)
|
||||
info->defaultlabel->pclabel = makepclabel();
|
||||
@ -68,11 +496,30 @@ void switchstatement(ENode *expr, SwitchInfo *info) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!use_table || nranges_minus1 < 8 || (nranges_minus1 * 2) < ((range.lo / 1) + 4))
|
||||
if (!use_table || nranges_minus1 < 8 || (nranges_minus1 * 2) < ((range.lo / 2) + 4))
|
||||
generate_tree(expr);
|
||||
else
|
||||
generate_table(expr, info);
|
||||
}
|
||||
|
||||
void dumpswitchtables(Object *funcobj) {
|
||||
Object *table;
|
||||
ObjectList *list;
|
||||
SInt32 size;
|
||||
UInt32 *array;
|
||||
|
||||
for (list = switchtables; list; list = list->next) {
|
||||
table = list->object;
|
||||
#line 694
|
||||
CError_ASSERT(table->otype == OT_OBJECT && table->access == ACCESSPUBLIC && table->datatype == DDATA);
|
||||
|
||||
size = table->u.data.u.switchtable.size;
|
||||
array = (UInt32 *) table->u.data.u.switchtable.data;
|
||||
while (size--) {
|
||||
*array = CTool_EndianConvertWord32(((PCodeLabel *) *array)->block->codeOffset);
|
||||
array++;
|
||||
}
|
||||
|
||||
ObjGen_DeclareSwitchTable(table, funcobj);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "compiler/CMangler.h"
|
||||
#include "compiler/CParser.h"
|
||||
#include "compiler/CodeGen.h"
|
||||
#include "compiler/InstrSelection.h"
|
||||
#include "compiler/Operands.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeInfo.h"
|
||||
|
@ -0,0 +1,563 @@
|
||||
#include "compiler/UseDefChains.h"
|
||||
#include "compiler/Alias.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/types.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
|
||||
int number_of_Defs;
|
||||
UseOrDef *Defs;
|
||||
RegUseOrDef **reg_Defs[RegClassMax];
|
||||
int number_of_Uses;
|
||||
UseOrDef *Uses;
|
||||
RegUseOrDef **reg_Uses[RegClassMax];
|
||||
UseDefInfo *usedefinfo;
|
||||
ObjectUseDef *objectusedefs;
|
||||
ObjectUseDef *objectusedeflist;
|
||||
|
||||
ObjectUseDef *findobjectusedef(Object *object) {
|
||||
ObjectUseDef *oud;
|
||||
|
||||
oud = objectusedefs;
|
||||
while (oud) {
|
||||
if (((unsigned long) object) < ((unsigned long) oud->object))
|
||||
oud = oud->leftchild;
|
||||
else if (((unsigned long) object) > ((unsigned long) oud->object))
|
||||
oud = oud->rightchild;
|
||||
else
|
||||
return oud;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void addobjectusedef(Object *object) {
|
||||
ObjectUseDef **ptr;
|
||||
ObjectUseDef *list;
|
||||
|
||||
ptr = &objectusedefs;
|
||||
while (*ptr) {
|
||||
if (((unsigned long) object) < ((unsigned long) (*ptr)->object))
|
||||
ptr = &(*ptr)->leftchild;
|
||||
else if (((unsigned long) object) > ((unsigned long) (*ptr)->object))
|
||||
ptr = &(*ptr)->rightchild;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
list = oalloc(sizeof(ObjectUseDef));
|
||||
list->leftchild = list->rightchild = NULL;
|
||||
list->object = object;
|
||||
list->uses = list->defs = NULL;
|
||||
list->next = objectusedeflist;
|
||||
objectusedeflist = list;
|
||||
*ptr = list;
|
||||
}
|
||||
|
||||
static void addaliasusedef(Alias *alias) {
|
||||
AliasMember *member;
|
||||
|
||||
if (alias && alias != worst_case) {
|
||||
if (alias->type == AliasType2) {
|
||||
for (member = alias->parents; member; member = member->nextParent)
|
||||
addaliasusedef(member->child);
|
||||
} else {
|
||||
addobjectusedef(alias->object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void addworstcase(void) {
|
||||
addobjectusedef(&worst_case_obj);
|
||||
}
|
||||
|
||||
static void precomputememoryusedefs(void) {
|
||||
PCodeBlock *block;
|
||||
PCode *pcode;
|
||||
|
||||
objectusedeflist = NULL;
|
||||
objectusedefs = NULL;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (pcode->flags & (fPCodeFlag2 | fPCodeFlag4)) {
|
||||
if (pcode->alias) {
|
||||
if (pcode->alias->type == AliasType2 || pcode->alias->size != nbytes_loaded_or_stored_by(pcode))
|
||||
pcode->flags |= fPCodeFlag20;
|
||||
addaliasusedef(pcode->alias);
|
||||
} else {
|
||||
pcode->flags |= fPCodeFlag20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addworstcase();
|
||||
}
|
||||
|
||||
static void precomputeusedefcounts(int flag) {
|
||||
PCodeBlock *block;
|
||||
PCode *pcode;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
ObjectUseDef *oud;
|
||||
|
||||
number_of_Defs = 0;
|
||||
number_of_Uses = 0;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
||||
pcode->useID = number_of_Uses;
|
||||
pcode->defID = number_of_Defs;
|
||||
op = pcode->args;
|
||||
i = pcode->argCount;
|
||||
while (i--) {
|
||||
if (op->kind == PCOp_REGISTER && op->data.reg.reg >= n_real_registers[op->arg]) {
|
||||
if (op->data.reg.effect & EffectRead)
|
||||
number_of_Uses++;
|
||||
if (op->data.reg.effect & EffectWrite)
|
||||
number_of_Defs++;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
if (pcode->flags & fPCodeFlag2) {
|
||||
if (pcode->flags & fPCodeFlag20) {
|
||||
for (oud = objectusedeflist; oud; oud = oud->next) {
|
||||
if (may_alias_object(pcode, oud->object))
|
||||
number_of_Uses++;
|
||||
}
|
||||
} else {
|
||||
number_of_Uses++;
|
||||
}
|
||||
} else if (pcode->flags & fPCodeFlag4) {
|
||||
if (pcode->flags & fPCodeFlag20) {
|
||||
for (oud = objectusedeflist; oud; oud = oud->next) {
|
||||
if (may_alias_object(pcode, oud->object))
|
||||
number_of_Defs++;
|
||||
}
|
||||
} else {
|
||||
number_of_Defs++;
|
||||
}
|
||||
} else if (pcode->flags & fPCodeFlag8) {
|
||||
for (oud = objectusedeflist; oud; oud = oud->next) {
|
||||
if (
|
||||
oud->object->datatype == DDATA ||
|
||||
oud->object->datatype == DNONLAZYPTR ||
|
||||
(oud->object->datatype == DLOCAL && (
|
||||
oud->object->u.var.info->noregister ||
|
||||
IS_TYPE_ARRAY(oud->object->type) ||
|
||||
IS_TYPE_NONVECTOR_STRUCT(oud->object->type) ||
|
||||
IS_TYPE_CLASS(oud->object->type) ||
|
||||
IS_TYPE_12BYTES_MEMBERPOINTER(oud->object->type)
|
||||
))
|
||||
) {
|
||||
number_of_Uses++;
|
||||
number_of_Defs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void computeusedeflists(int flag) {
|
||||
ObjectUseDef *oud;
|
||||
RegUseOrDef *list;
|
||||
PCodeBlock *block;
|
||||
PCode *pcode;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
UseOrDef *use;
|
||||
UseOrDef *def;
|
||||
int useID;
|
||||
int defID;
|
||||
ObjectUseDef *tmp;
|
||||
Object *object;
|
||||
|
||||
Uses = oalloc(sizeof(UseOrDef) * number_of_Uses);
|
||||
Defs = oalloc(sizeof(UseOrDef) * number_of_Defs);
|
||||
|
||||
reg_Uses[RegClass_GPR] = oalloc(sizeof(RegUseOrDef *) * used_virtual_registers[RegClass_GPR]);
|
||||
reg_Defs[RegClass_GPR] = oalloc(sizeof(RegUseOrDef *) * used_virtual_registers[RegClass_GPR]);
|
||||
for (i = 0; i < used_virtual_registers[RegClass_GPR]; i++) {
|
||||
reg_Uses[RegClass_GPR][i] = NULL;
|
||||
reg_Defs[RegClass_GPR][i] = NULL;
|
||||
}
|
||||
|
||||
reg_Uses[RegClass_FPR] = oalloc(sizeof(RegUseOrDef *) * used_virtual_registers[RegClass_FPR]);
|
||||
reg_Defs[RegClass_FPR] = oalloc(sizeof(RegUseOrDef *) * used_virtual_registers[RegClass_FPR]);
|
||||
for (i = 0; i < used_virtual_registers[RegClass_FPR]; i++) {
|
||||
reg_Uses[RegClass_FPR][i] = NULL;
|
||||
reg_Defs[RegClass_FPR][i] = NULL;
|
||||
}
|
||||
|
||||
reg_Uses[RegClass_VR] = oalloc(sizeof(RegUseOrDef *) * used_virtual_registers[RegClass_VR]);
|
||||
reg_Defs[RegClass_VR] = oalloc(sizeof(RegUseOrDef *) * used_virtual_registers[RegClass_VR]);
|
||||
for (i = 0; i < used_virtual_registers[RegClass_VR]; i++) {
|
||||
reg_Uses[RegClass_VR][i] = NULL;
|
||||
reg_Defs[RegClass_VR][i] = NULL;
|
||||
}
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
||||
use = &Uses[useID = pcode->useID];
|
||||
def = &Defs[defID = pcode->defID];
|
||||
|
||||
op = pcode->args;
|
||||
i = pcode->argCount;
|
||||
while (i--) {
|
||||
if (op->kind == PCOp_REGISTER && op->data.reg.reg >= n_real_registers[op->arg]) {
|
||||
if (op->data.reg.effect & EffectRead) {
|
||||
use->pcode = pcode;
|
||||
use->v.kind = op->kind;
|
||||
use->v.arg = op->arg;
|
||||
use->v.u.reg = op->data.reg.reg;
|
||||
list = oalloc(sizeof(RegUseOrDef));
|
||||
list->id = useID;
|
||||
list->next = reg_Uses[op->arg][op->data.reg.reg];
|
||||
reg_Uses[op->arg][op->data.reg.reg] = list;
|
||||
use++;
|
||||
useID++;
|
||||
}
|
||||
if (op->data.reg.effect & EffectWrite) {
|
||||
def->pcode = pcode;
|
||||
def->v.kind = op->kind;
|
||||
def->v.arg = op->arg;
|
||||
def->v.u.reg = op->data.reg.reg;
|
||||
list = oalloc(sizeof(RegUseOrDef));
|
||||
list->id = defID;
|
||||
list->next = reg_Defs[op->arg][op->data.reg.reg];
|
||||
reg_Defs[op->arg][op->data.reg.reg] = list;
|
||||
def++;
|
||||
defID++;
|
||||
}
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
if (pcode->flags & fPCodeFlag2) {
|
||||
if (pcode->flags & fPCodeFlag20) {
|
||||
for (oud = objectusedeflist; oud; oud = oud->next) {
|
||||
if (may_alias_object(pcode, object = oud->object)) {
|
||||
use->pcode = pcode;
|
||||
use->v.kind = PCOp_MEMORY;
|
||||
use->v.arg = 1;
|
||||
use->v.u.object = object;
|
||||
list = oalloc(sizeof(RegUseOrDef));
|
||||
list->id = useID;
|
||||
list->next = oud->uses;
|
||||
oud->uses = list;
|
||||
use++;
|
||||
useID++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object = pcode->alias->object;
|
||||
use->pcode = pcode;
|
||||
use->v.kind = PCOp_MEMORY;
|
||||
use->v.arg = 0;
|
||||
use->v.u.object = object;
|
||||
list = oalloc(sizeof(RegUseOrDef));
|
||||
list->id = useID;
|
||||
tmp = findobjectusedef(object);
|
||||
list->next = tmp->uses;
|
||||
tmp->uses = list;
|
||||
}
|
||||
} else if (pcode->flags & fPCodeFlag4) {
|
||||
if (pcode->flags & fPCodeFlag20) {
|
||||
for (oud = objectusedeflist; oud; oud = oud->next) {
|
||||
if (may_alias_object(pcode, object = oud->object)) {
|
||||
def->pcode = pcode;
|
||||
def->v.kind = PCOp_MEMORY;
|
||||
def->v.arg = 1;
|
||||
def->v.u.object = object;
|
||||
list = oalloc(sizeof(RegUseOrDef));
|
||||
list->id = defID;
|
||||
list->next = oud->defs;
|
||||
oud->defs = list;
|
||||
def++;
|
||||
defID++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object = pcode->alias->object;
|
||||
def->pcode = pcode;
|
||||
def->v.kind = PCOp_MEMORY;
|
||||
def->v.arg = 0;
|
||||
def->v.u.object = object;
|
||||
list = oalloc(sizeof(RegUseOrDef));
|
||||
list->id = useID;
|
||||
tmp = findobjectusedef(object);
|
||||
list->next = tmp->defs;
|
||||
tmp->defs = list;
|
||||
}
|
||||
} else if (pcode->flags & fPCodeFlag8) {
|
||||
for (oud = objectusedeflist; oud; oud = oud->next) {
|
||||
object = oud->object;
|
||||
if (
|
||||
object->datatype == DDATA ||
|
||||
object->datatype == DNONLAZYPTR ||
|
||||
(object->datatype == DLOCAL && (
|
||||
object->u.var.info->noregister ||
|
||||
IS_TYPE_ARRAY(object->type) ||
|
||||
IS_TYPE_NONVECTOR_STRUCT(object->type) ||
|
||||
IS_TYPE_CLASS(oud->object->type) ||
|
||||
IS_TYPE_12BYTES_MEMBERPOINTER(object->type)
|
||||
))
|
||||
) {
|
||||
use->pcode = pcode;
|
||||
use->v.kind = PCOp_MEMORY;
|
||||
use->v.arg = 1;
|
||||
use->v.u.object = object;
|
||||
|
||||
list = oalloc(sizeof(RegUseOrDef));
|
||||
list->id = useID;
|
||||
list->next = oud->uses;
|
||||
oud->uses = list;
|
||||
|
||||
def->pcode = pcode;
|
||||
def->v.kind = PCOp_MEMORY;
|
||||
def->v.arg = 1;
|
||||
def->v.u.object = object;
|
||||
|
||||
use++;
|
||||
useID++;
|
||||
|
||||
list = oalloc(sizeof(RegUseOrDef));
|
||||
list->id = defID;
|
||||
list->next = oud->defs;
|
||||
oud->defs = list;
|
||||
|
||||
def++;
|
||||
defID++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void allocateusedefinfo(void) {
|
||||
UseDefInfo *info;
|
||||
int i;
|
||||
|
||||
usedefinfo = oalloc(pcblockcount * sizeof(UseDefInfo));
|
||||
for (i = 0, info = usedefinfo; i < pcblockcount; i++, info++) {
|
||||
info->defvec0 = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
||||
info->defvec4 = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
||||
info->defvec8 = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
||||
info->defvecC = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
||||
info->usevec10 = oalloc(4 * ((number_of_Uses + 31) >> 5));
|
||||
info->usevec14 = oalloc(4 * ((number_of_Uses + 31) >> 5));
|
||||
info->usevec18 = oalloc(4 * ((number_of_Uses + 31) >> 5));
|
||||
info->usevec1C = oalloc(4 * ((number_of_Uses + 31) >> 5));
|
||||
}
|
||||
}
|
||||
|
||||
static void computelocalusedefinfo(void) {
|
||||
PCodeBlock *block; // r28
|
||||
PCode *pcode; // r27
|
||||
UInt32 *defvec0; // r26
|
||||
UInt32 *defvec4; // r25
|
||||
UInt32 *usevec10; // r24
|
||||
UInt32 *usevec14; // r23
|
||||
UseOrDef *use; // r22
|
||||
UseOrDef *def; // r22
|
||||
int useID; // r15
|
||||
int defID; // r21
|
||||
ObjectUseDef *oud; // r17
|
||||
RegUseOrDef *list; // r16
|
||||
UseDefInfo *info; // r15
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
info = &usedefinfo[block->blockIndex];
|
||||
defvec0 = info->defvec0;
|
||||
defvec4 = info->defvec4;
|
||||
usevec10 = info->usevec10;
|
||||
usevec14 = info->usevec14;
|
||||
bitvectorinitialize(defvec0, number_of_Defs, 0);
|
||||
bitvectorinitialize(defvec4, number_of_Defs, 0);
|
||||
bitvectorinitialize(usevec10, number_of_Uses, 0);
|
||||
bitvectorinitialize(usevec14, number_of_Uses, 0);
|
||||
bitvectorinitialize(info->defvec8, number_of_Defs, 0);
|
||||
bitvectorinitialize(info->defvecC, number_of_Defs, 0);
|
||||
bitvectorinitialize(info->usevec18, number_of_Uses, 0);
|
||||
bitvectorinitialize(info->usevec1C, number_of_Uses, 0);
|
||||
|
||||
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
||||
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
||||
for (use = &Uses[useID = pcode->useID]; useID < number_of_Uses && use->pcode == pcode; use++, useID++) {
|
||||
bitvectorsetbit(useID, usevec10);
|
||||
if (use->v.kind == PCOp_REGISTER) {
|
||||
for (list = reg_Defs[use->v.arg][use->v.u.reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, defvec0))
|
||||
bitvectorclearbit(useID, usevec10);
|
||||
}
|
||||
} else {
|
||||
for (list = findobjectusedef(use->v.u.object)->defs; list; list = list->next) {
|
||||
if (uniquely_aliases(pcode, Defs[list->id].pcode)) {
|
||||
if (Defs[list->id].v.arg == 0 && bitvectorgetbit(list->id, defvec0))
|
||||
bitvectorclearbit(useID, usevec10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (def = &Defs[defID = pcode->defID]; defID < number_of_Defs && def->pcode == pcode; def++, defID++) {
|
||||
if (def->v.kind == PCOp_REGISTER) {
|
||||
for (list = reg_Uses[def->v.arg][def->v.u.reg]; list; list = list->next) {
|
||||
if (Uses[list->id].pcode->block != block)
|
||||
bitvectorsetbit(list->id, usevec14);
|
||||
}
|
||||
for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next) {
|
||||
if (Defs[list->id].pcode->block != block)
|
||||
bitvectorsetbit(list->id, defvec4);
|
||||
else
|
||||
bitvectorclearbit(list->id, defvec0);
|
||||
}
|
||||
} else if (def->v.arg == 0) {
|
||||
oud = findobjectusedef(use->v.u.object);
|
||||
for (list = oud->uses; list; list = list->next) {
|
||||
if (may_alias(pcode, Uses[list->id].pcode)) {
|
||||
if (Uses[list->id].pcode->block != block)
|
||||
bitvectorsetbit(list->id, usevec14);
|
||||
}
|
||||
}
|
||||
for (list = oud->defs; list; list = list->next) {
|
||||
if (uniquely_aliases(pcode, Defs[list->id].pcode)) {
|
||||
if (Defs[list->id].pcode->block != block)
|
||||
bitvectorsetbit(list->id, defvec4);
|
||||
else
|
||||
bitvectorclearbit(list->id, defvec0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitvectorsetbit(defID, defvec0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void computeglobalusedefinfo(void) {
|
||||
UseDefInfo *udi;
|
||||
UInt32 *defVec0;
|
||||
UInt32 *defVec4;
|
||||
UInt32 *defVec8;
|
||||
UInt32 *defVecC;
|
||||
int bitvecsize;
|
||||
int i;
|
||||
int j;
|
||||
int flag;
|
||||
PCLink *preds;
|
||||
UInt32 val;
|
||||
|
||||
bitvecsize = (number_of_Defs + 31) >> 5;
|
||||
flag = 1;
|
||||
while (flag) {
|
||||
flag = 0;
|
||||
for (i = 0; i < pcblockcount; i++) {
|
||||
if (depthfirstordering[i]) {
|
||||
udi = &usedefinfo[depthfirstordering[i]->blockIndex];
|
||||
if ((preds = depthfirstordering[i]->predecessors)) {
|
||||
defVec8 = udi->defvec8;
|
||||
bitvectorcopy(defVec8, usedefinfo[preds->block->blockIndex].defvecC, number_of_Defs);
|
||||
for (preds = preds->nextLink; preds; preds = preds->nextLink)
|
||||
bitvectorunion(defVec8, usedefinfo[preds->block->blockIndex].defvecC, number_of_Defs);
|
||||
}
|
||||
|
||||
defVecC = udi->defvecC;
|
||||
defVec8 = udi->defvec8;
|
||||
defVec0 = udi->defvec0;
|
||||
defVec4 = udi->defvec4;
|
||||
for (j = 0; j < bitvecsize; j++) {
|
||||
val = *defVec0 | (*defVec8 & ~*defVec4);
|
||||
if (val != *defVecC) {
|
||||
*defVecC = val;
|
||||
flag = 1;
|
||||
}
|
||||
defVec8++;
|
||||
defVecC++;
|
||||
defVec4++;
|
||||
defVec0++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void computeglobaldefuseinfo(void) {
|
||||
UseDefInfo *udi;
|
||||
UInt32 *useVec10;
|
||||
UInt32 *useVec14;
|
||||
UInt32 *useVec18;
|
||||
UInt32 *useVec1C;
|
||||
int bitvecsize;
|
||||
int i;
|
||||
int j;
|
||||
int flag;
|
||||
PCLink *succs;
|
||||
UInt32 val;
|
||||
PCodeBlock *block;
|
||||
|
||||
bitvecsize = (number_of_Uses + 31) >> 5;
|
||||
flag = 1;
|
||||
while (flag) {
|
||||
flag = 0;
|
||||
i = pcblockcount;
|
||||
while (i) {
|
||||
if ((block = depthfirstordering[--i])) {
|
||||
udi = &usedefinfo[block->blockIndex];
|
||||
if ((succs = block->successors)) {
|
||||
useVec1C = udi->usevec1C;
|
||||
bitvectorcopy(useVec1C, usedefinfo[succs->block->blockIndex].usevec18, number_of_Uses);
|
||||
for (succs = succs->nextLink; succs; succs = succs->nextLink)
|
||||
bitvectorunion(useVec1C, usedefinfo[succs->block->blockIndex].usevec18, number_of_Uses);
|
||||
}
|
||||
|
||||
useVec1C = udi->usevec1C;
|
||||
useVec18 = udi->usevec18;
|
||||
useVec10 = udi->usevec10;
|
||||
useVec14 = udi->usevec14;
|
||||
for (j = 0; j < bitvecsize; j++) {
|
||||
val = *useVec10 | (*useVec1C & ~*useVec14);
|
||||
if (val != *useVec18) {
|
||||
*useVec18 = val;
|
||||
flag = 1;
|
||||
}
|
||||
useVec18++;
|
||||
useVec1C++;
|
||||
useVec14++;
|
||||
useVec10++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void computeusedefchains(int flag) {
|
||||
if (flag) {
|
||||
gather_alias_info();
|
||||
precomputememoryusedefs();
|
||||
}
|
||||
|
||||
precomputeusedefcounts(flag);
|
||||
computeusedeflists(flag);
|
||||
allocateusedefinfo();
|
||||
computelocalusedefinfo();
|
||||
computedepthfirstordering();
|
||||
computeglobalusedefinfo();
|
||||
computeglobaldefuseinfo();
|
||||
}
|
||||
|
@ -0,0 +1,664 @@
|
||||
#include "compiler/ValueNumbering.h"
|
||||
#include "compiler/Alias.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/Registers.h"
|
||||
#include "compiler/RegisterInfo.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/CError.h"
|
||||
|
||||
typedef struct ValueLabel {
|
||||
struct ValueLabel *next;
|
||||
PCodeArg op;
|
||||
} ValueLabel;
|
||||
|
||||
typedef struct AvailableValue {
|
||||
struct AvailableValue *next;
|
||||
ValueLabel *labelled;
|
||||
PCode *pcode;
|
||||
int killedregister;
|
||||
int aliasnumber;
|
||||
int opnumbers[0];
|
||||
} AvailableValue;
|
||||
|
||||
typedef struct RegValue {
|
||||
int number;
|
||||
int x4;
|
||||
AvailableValue *available;
|
||||
} RegValue;
|
||||
|
||||
typedef struct State {
|
||||
void *stackedvalues;
|
||||
int valueceiling;
|
||||
} State;
|
||||
|
||||
typedef struct StackedValue {
|
||||
struct StackedValue *next;
|
||||
PCodeArg op;
|
||||
RegValue value;
|
||||
Alias *alias;
|
||||
PCode *valuepcode;
|
||||
} StackedValue;
|
||||
|
||||
int removedcommonsubexpressions;
|
||||
int nextvaluenumber;
|
||||
static AvailableValue *opvalue[428];
|
||||
static RegValue *regvalue[RegClassMax];
|
||||
static StackedValue *stackedvalues;
|
||||
static int valueceiling;
|
||||
static int moreaggressiveoptimization;
|
||||
|
||||
static void allocatecsedatastructures(void) {
|
||||
char rclass;
|
||||
|
||||
for (rclass = 0; rclass < RegClassMax; rclass++)
|
||||
regvalue[(char) rclass] = oalloc(sizeof(RegValue) * used_virtual_registers[(char) rclass]);
|
||||
}
|
||||
|
||||
static void initializecsedatastructures(void) {
|
||||
RegValue *rv;
|
||||
char rclass;
|
||||
int i;
|
||||
|
||||
nextvaluenumber = 0;
|
||||
|
||||
for (i = 0; i < 428; i++)
|
||||
opvalue[i] = NULL;
|
||||
|
||||
for (rclass = 0; rclass < RegClassMax; rclass++) {
|
||||
rv = regvalue[(char) rclass];
|
||||
for (i = 0; i < used_virtual_registers[(char) rclass]; i++, rv++) {
|
||||
rv->number = nextvaluenumber++;
|
||||
rv->x4 = 0;
|
||||
rv->available = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
initialize_alias_values();
|
||||
stackedvalues = NULL;
|
||||
valueceiling = 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
static void labelvalue(AvailableValue *av, PCodeArg *op) {
|
||||
ValueLabel *label = oalloc(sizeof(ValueLabel));
|
||||
label->op = *op;
|
||||
label->next = av->labelled;
|
||||
av->labelled = label;
|
||||
}
|
||||
|
||||
static void unlabelvalue(AvailableValue *av, PCodeArg *op) {
|
||||
ValueLabel *labelled;
|
||||
ValueLabel **ptr;
|
||||
|
||||
ptr = &av->labelled;
|
||||
while ((labelled = *ptr)) {
|
||||
if (labelled->op.data.reg.reg == op->data.reg.reg)
|
||||
*ptr = labelled->next;
|
||||
else
|
||||
ptr = &labelled->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void stackregistervalue(PCodeArg *op, RegValue *value) {
|
||||
StackedValue *stacked = oalloc(sizeof(StackedValue));
|
||||
stacked->next = stackedvalues;
|
||||
stackedvalues = stacked;
|
||||
|
||||
stacked->op = *op;
|
||||
stacked->value = *value;
|
||||
}
|
||||
|
||||
static void stackmemoryvalue(Alias *alias) {
|
||||
StackedValue *stacked = oalloc(sizeof(StackedValue));
|
||||
stacked->next = stackedvalues;
|
||||
stackedvalues = stacked;
|
||||
|
||||
stacked->op.kind = PCOp_MEMORY;
|
||||
stacked->alias = alias;
|
||||
stacked->value.number = alias->valuenumber;
|
||||
stacked->valuepcode = alias->valuepcode;
|
||||
}
|
||||
|
||||
static void unstackvalue(StackedValue *stacked) {
|
||||
PCodeArg *op = &stacked->op;
|
||||
RegValue *value;
|
||||
|
||||
if (stacked->op.kind == PCOp_MEMORY) {
|
||||
stacked->alias->valuenumber = stacked->value.number;
|
||||
stacked->alias->valuepcode = stacked->valuepcode;
|
||||
} else {
|
||||
value = ®value[op->arg][op->data.reg.reg];
|
||||
if (value->available)
|
||||
unlabelvalue(value->available, op);
|
||||
value->number = stacked->value.number;
|
||||
value->x4 = stacked->value.x4;
|
||||
value->available = stacked->value.available;
|
||||
if (value->available)
|
||||
labelvalue(value->available, op);
|
||||
}
|
||||
}
|
||||
|
||||
static int samevalue(PCodeArg *op1, PCodeArg *op2) {
|
||||
return regvalue[op1->arg][op1->data.reg.reg].number == regvalue[op2->arg][op2->data.reg.reg].number;
|
||||
}
|
||||
|
||||
static int killregister(PCodeArg *op) {
|
||||
RegValue *value;
|
||||
|
||||
value = ®value[op->arg][op->data.reg.reg];
|
||||
if (value->number < valueceiling && nextvaluenumber >= valueceiling)
|
||||
stackregistervalue(op, value);
|
||||
|
||||
if (value->available)
|
||||
unlabelvalue(value->available, op);
|
||||
value->available = NULL;
|
||||
value->x4 = 0;
|
||||
return value->number = nextvaluenumber++;
|
||||
}
|
||||
|
||||
void killmemory(Alias *alias, PCode *newValue) {
|
||||
if (alias->valuenumber < valueceiling && nextvaluenumber >= valueceiling)
|
||||
stackmemoryvalue(alias);
|
||||
|
||||
if (newValue) {
|
||||
alias->valuenumber = regvalue[newValue->args[0].arg][newValue->args[0].data.reg.reg].number;
|
||||
alias->valuepcode = newValue;
|
||||
} else {
|
||||
alias->valuenumber = nextvaluenumber++;
|
||||
alias->valuepcode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void killspecificCSEs(short op) {
|
||||
AvailableValue *av;
|
||||
ValueLabel *labelled;
|
||||
|
||||
for (av = opvalue[op]; av; av = av->next) {
|
||||
for (labelled = av->labelled; labelled; labelled = labelled->next)
|
||||
killregister(&labelled->op);
|
||||
}
|
||||
}
|
||||
|
||||
static void killallCSEs(void) {
|
||||
AvailableValue *av;
|
||||
ValueLabel *labelled;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 428; i++) {
|
||||
for (av = opvalue[i]; av; av = av->next) {
|
||||
for (labelled = av->labelled; labelled; labelled = labelled->next)
|
||||
killregister(&labelled->op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void killregisters(PCode *pcode) {
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
for (i = 0, op = pcode->args; i < pcode->argCount; i++, op++) {
|
||||
if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite))
|
||||
killregister(op);
|
||||
}
|
||||
}
|
||||
|
||||
static void copyregister(PCodeArg *src, PCodeArg *dest) {
|
||||
RegValue *srcvalue;
|
||||
RegValue *destvalue;
|
||||
|
||||
srcvalue = ®value[src->arg][src->data.reg.reg];
|
||||
destvalue = ®value[dest->arg][dest->data.reg.reg];
|
||||
|
||||
if (destvalue->number < valueceiling && nextvaluenumber >= valueceiling)
|
||||
stackregistervalue(dest, destvalue);
|
||||
|
||||
if (destvalue->available)
|
||||
unlabelvalue(destvalue->available, dest);
|
||||
destvalue->available = srcvalue->available;
|
||||
if (destvalue->available)
|
||||
labelvalue(destvalue->available, dest);
|
||||
|
||||
destvalue->number = srcvalue->number;
|
||||
|
||||
if (srcvalue->x4 && srcvalue->number == regvalue[src->arg][srcvalue->x4].number)
|
||||
destvalue->x4 = srcvalue->x4;
|
||||
else
|
||||
destvalue->x4 = src->data.reg.reg;
|
||||
}
|
||||
|
||||
static int matchvalues(AvailableValue *av, PCode *match) {
|
||||
PCodeArg *avOp;
|
||||
PCodeArg *matchOp;
|
||||
int i;
|
||||
|
||||
for (avOp = &av->pcode->args[0], matchOp = &match->args[0], i = 0; i < match->argCount; i++, avOp++, matchOp++) {
|
||||
if (i != 0) {
|
||||
switch (avOp->kind) {
|
||||
case PCOp_REGISTER:
|
||||
if (av->opnumbers[i] != regvalue[matchOp->arg][matchOp->data.reg.reg].number)
|
||||
return 0;
|
||||
break;
|
||||
case PCOp_MEMORY:
|
||||
if (matchOp->kind != PCOp_MEMORY)
|
||||
return 0;
|
||||
if (matchOp->data.mem.obj != avOp->data.mem.obj)
|
||||
return 0;
|
||||
if (matchOp->data.mem.offset != avOp->data.mem.offset)
|
||||
return 0;
|
||||
if ((unsigned char) matchOp->arg != (unsigned char) avOp->arg)
|
||||
return 0;
|
||||
break;
|
||||
case PCOp_IMMEDIATE:
|
||||
if (matchOp->kind != PCOp_IMMEDIATE)
|
||||
return 0;
|
||||
if (matchOp->data.imm.value != avOp->data.imm.value)
|
||||
return 0;
|
||||
break;
|
||||
case PCOp_LABEL:
|
||||
if (matchOp->kind != PCOp_LABEL)
|
||||
return 0;
|
||||
if (matchOp->data.label.label != avOp->data.label.label)
|
||||
return 0;
|
||||
break;
|
||||
case PCOp_SYSREG:
|
||||
#line 572
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((match->flags & (fPCodeFlag2 | fPCodeFlag20000)) && match->alias->valuenumber != av->aliasnumber)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void chooselocation(AvailableValue *av, PCodeArg *op) {
|
||||
ValueLabel *labelled;
|
||||
PCodeArg *baseop;
|
||||
|
||||
baseop = &av->pcode->args[0];
|
||||
labelled = av->labelled;
|
||||
while (labelled) {
|
||||
if (labelled->op.data.reg.reg == baseop->data.reg.reg) {
|
||||
*op = labelled->op;
|
||||
return;
|
||||
}
|
||||
labelled = labelled->next;
|
||||
}
|
||||
|
||||
*op = av->labelled[0].op;
|
||||
}
|
||||
|
||||
static int findavailablevalue(PCode *pcode, PCodeArg *op) {
|
||||
AvailableValue *av;
|
||||
PCodeArg tmp1;
|
||||
PCodeArg tmp2;
|
||||
|
||||
for (av = opvalue[pcode->op]; av; av = av->next) {
|
||||
if (av->labelled && av->pcode->flags == pcode->flags && av->pcode->argCount == pcode->argCount) {
|
||||
if (!matchvalues(av, pcode)) {
|
||||
if (!(pcode->flags & fCommutative))
|
||||
continue;
|
||||
|
||||
tmp1 = pcode->args[1];
|
||||
pcode->args[1] = pcode->args[2];
|
||||
pcode->args[2] = tmp1;
|
||||
|
||||
if (!matchvalues(av, pcode)) {
|
||||
tmp2 = pcode->args[1];
|
||||
pcode->args[1] = pcode->args[2];
|
||||
pcode->args[2] = tmp2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
chooselocation(av, op);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void addavailablevalue(PCode *pcode) {
|
||||
AvailableValue *av;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
av = oalloc(sizeof(AvailableValue) + sizeof(int) * pcode->argCount);
|
||||
av->labelled = NULL;
|
||||
av->pcode = pcode;
|
||||
for (i = 0, op = &pcode->args[0]; i < pcode->argCount; i++, op++) {
|
||||
if (op->kind == PCOp_REGISTER)
|
||||
av->opnumbers[i] = regvalue[op->arg][op->data.reg.reg].number;
|
||||
}
|
||||
|
||||
if (pcode->flags & (fPCodeFlag2 | fPCodeFlag20000))
|
||||
av->aliasnumber = pcode->alias->valuenumber;
|
||||
|
||||
op = &pcode->args[0];
|
||||
av->killedregister = killregister(op);
|
||||
labelvalue(av, op);
|
||||
regvalue[op->arg][op->data.reg.reg].available = av;
|
||||
av->next = opvalue[pcode->op];
|
||||
opvalue[pcode->op] = av;
|
||||
}
|
||||
|
||||
static int isCSEop(PCode *pcode) {
|
||||
PCodeArg *baseOp;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
baseOp = &pcode->args[0];
|
||||
|
||||
switch (pcode->op) {
|
||||
case PC_CMPI:
|
||||
case PC_CMP:
|
||||
case PC_CMPLI:
|
||||
case PC_CMPL:
|
||||
case PC_FCMPU:
|
||||
case PC_FCMPO:
|
||||
if (!moreaggressiveoptimization)
|
||||
return 0;
|
||||
break;
|
||||
case PC_LI:
|
||||
case PC_LIS:
|
||||
if (!moreaggressiveoptimization)
|
||||
return 0;
|
||||
if (pcode->args[0].data.reg.reg < first_fe_temporary_register[RegClass_GPR] || pcode->args[0].data.reg.reg > last_temporary_register[RegClass_GPR])
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (PCODE_FLAG_SET_F(pcode) & (fIsVolatile | fSideEffects | fOverflow | fPCodeFlag10000000 | fPCodeFlag20000000))
|
||||
return 0;
|
||||
|
||||
for (i = 0, op = &pcode->args[0]; i < pcode->argCount; i++, op++) {
|
||||
if (op != baseOp &&
|
||||
op->kind == baseOp->kind &&
|
||||
op->arg == baseOp->arg &&
|
||||
op->data.reg.reg == baseOp->data.reg.reg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int isCSEload(PCode *pcode) {
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
for (i = 0, op = &pcode->args[0]; i < pcode->argCount; i++, op++) {
|
||||
if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count == 1;
|
||||
}
|
||||
|
||||
static void registercopy(PCode *pcode) {
|
||||
PCodeArg *op1;
|
||||
PCodeArg *op2;
|
||||
|
||||
op1 = &pcode->args[0];
|
||||
op2 = &pcode->args[1];
|
||||
if (samevalue(op2, op1))
|
||||
deletepcode(pcode);
|
||||
else
|
||||
copyregister(op2, op1);
|
||||
}
|
||||
|
||||
static PCode *recentlystored(Alias *alias, PCodeArg *op) {
|
||||
PCode *pc;
|
||||
if ((pc = alias->valuepcode) && alias->valuenumber == regvalue[pc->args[0].arg][pc->args[0].data.reg.reg].number) {
|
||||
*op = pc->args[0];
|
||||
return pc;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void simpleload(PCode *pcode) {
|
||||
PCodeArg *origOp;
|
||||
PCodeArg op;
|
||||
PCode *rs;
|
||||
|
||||
origOp = &pcode->args[0];
|
||||
if ((pcode->flags & fIsVolatile) || !isCSEload(pcode)) {
|
||||
killregisters(pcode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (findavailablevalue(pcode, &op)) {
|
||||
if (!samevalue(origOp, &op)) {
|
||||
insertpcodebefore(pcode, makecopyinstruction(&op, origOp));
|
||||
copyregister(&op, origOp);
|
||||
}
|
||||
deletepcode(pcode);
|
||||
removedcommonsubexpressions = 1;
|
||||
} else if ((rs = recentlystored(pcode->alias, &op)) && can_reuse_stored_value(rs, pcode)) {
|
||||
if (!samevalue(origOp, &op)) {
|
||||
insertpcodebefore(pcode, makecopyinstruction(&op, origOp));
|
||||
copyregister(&op, origOp);
|
||||
}
|
||||
deletepcode(pcode);
|
||||
removedcommonsubexpressions = 1;
|
||||
} else {
|
||||
addavailablevalue(pcode);
|
||||
}
|
||||
}
|
||||
|
||||
static void simplestore(PCode *pcode) {
|
||||
update_alias_value(pcode->alias, pcode);
|
||||
killregisters(pcode);
|
||||
}
|
||||
|
||||
static void pointerload(PCode *pcode) {
|
||||
PCodeArg *op;
|
||||
PCodeArg buf;
|
||||
|
||||
op = &pcode->args[0];
|
||||
|
||||
if ((pcode->flags & fIsVolatile) || !isCSEload(pcode)) {
|
||||
killregisters(pcode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (findavailablevalue(pcode, &buf)) {
|
||||
if (!samevalue(op, &buf)) {
|
||||
insertpcodebefore(pcode, makecopyinstruction(&buf, op));
|
||||
copyregister(&buf, op);
|
||||
}
|
||||
deletepcode(pcode);
|
||||
removedcommonsubexpressions = 1;
|
||||
} else {
|
||||
addavailablevalue(pcode);
|
||||
}
|
||||
}
|
||||
|
||||
static void pointerstore(PCode *pcode) {
|
||||
update_alias_value(pcode->alias, NULL);
|
||||
killregisters(pcode);
|
||||
}
|
||||
|
||||
static void arithmeticop(PCode *pcode) {
|
||||
PCodeArg *op;
|
||||
PCodeArg buf;
|
||||
|
||||
op = &pcode->args[0];
|
||||
|
||||
if (findavailablevalue(pcode, &buf)) {
|
||||
if (!samevalue(op, &buf)) {
|
||||
insertpcodebefore(pcode, makecopyinstruction(&buf, op));
|
||||
copyregister(&buf, op);
|
||||
}
|
||||
deletepcode(pcode);
|
||||
removedcommonsubexpressions = 1;
|
||||
} else {
|
||||
addavailablevalue(pcode);
|
||||
}
|
||||
}
|
||||
|
||||
static void functioncall(PCode *pcode) {
|
||||
killregisters(pcode);
|
||||
if (coloring) {
|
||||
update_all_alias_values();
|
||||
killallCSEs();
|
||||
} else {
|
||||
update_alias_value(pcode->alias, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void operatefrommemory(PCode *pcode) {
|
||||
#line 980
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
static void operatetomemory(PCode *pcode) {
|
||||
#line 1011
|
||||
CError_FATAL();
|
||||
}
|
||||
|
||||
static void propagatecopiesto(PCode *pcode) {
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
|
||||
for (i = 0, op = &pcode->args[0]; i < pcode->argCount; i++, op++) {
|
||||
if (
|
||||
op->kind == PCOp_REGISTER &&
|
||||
(op->data.reg.effect & (EffectRead | EffectWrite | Effect8)) == EffectRead &&
|
||||
op->data.reg.reg >= n_real_registers[op->arg] &&
|
||||
regvalue[op->arg][op->data.reg.reg].x4 &&
|
||||
regvalue[op->arg][op->data.reg.reg].x4 >= n_real_registers[op->arg] &&
|
||||
regvalue[op->arg][op->data.reg.reg].number == regvalue[op->arg][regvalue[op->arg][op->data.reg.reg].x4].number
|
||||
) {
|
||||
op->data.reg.reg = regvalue[op->arg][op->data.reg.reg].x4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void removecsesfrombasicblock(PCodeBlock *block) {
|
||||
PCode *pcode;
|
||||
PCode *next;
|
||||
|
||||
for (pcode = block->firstPCode; pcode; pcode = next) {
|
||||
next = pcode->nextPCode;
|
||||
propagatecopiesto(pcode);
|
||||
if (pcode->flags & fPCodeFlag10) {
|
||||
registercopy(pcode);
|
||||
} else if ((pcode->flags & fPCodeFlag8) && (pcode->flags & (fLink | fSideEffects))) {
|
||||
functioncall(pcode);
|
||||
} else if (pcode->flags & fPCodeFlag2) {
|
||||
if (pcode->flags & fPCodeFlag20)
|
||||
pointerload(pcode);
|
||||
else
|
||||
simpleload(pcode);
|
||||
} else if (pcode->flags & fPCodeFlag4) {
|
||||
if (pcode->flags & fPCodeFlag20)
|
||||
pointerstore(pcode);
|
||||
else
|
||||
simplestore(pcode);
|
||||
} else if (pcode->flags & fPCodeFlag20000) {
|
||||
operatefrommemory(pcode);
|
||||
} else if (pcode->flags & fPCodeFlag40000) {
|
||||
operatetomemory(pcode);
|
||||
} else if ((pcode->flags & fIsCSE) && isCSEop(pcode)) {
|
||||
arithmeticop(pcode);
|
||||
} else {
|
||||
killregisters(pcode);
|
||||
}
|
||||
}
|
||||
|
||||
block->flags |= fPCBlockFlag4;
|
||||
}
|
||||
|
||||
static void getvaluestate(State *state) {
|
||||
state->stackedvalues = stackedvalues;
|
||||
state->valueceiling = valueceiling;
|
||||
}
|
||||
|
||||
static void setvaluestate(State *state) {
|
||||
stackedvalues = state->stackedvalues;
|
||||
valueceiling = state->valueceiling;
|
||||
}
|
||||
|
||||
static void forkvaluestate(int number) {
|
||||
stackedvalues = NULL;
|
||||
valueceiling = number;
|
||||
}
|
||||
|
||||
static void regressvaluestate(void) {
|
||||
AvailableValue *av;
|
||||
AvailableValue **ptr;
|
||||
int i;
|
||||
StackedValue *stacked;
|
||||
|
||||
for (i = 0; i < 428; i++) {
|
||||
ptr = &opvalue[i];
|
||||
while ((av = *ptr)) {
|
||||
if (av->killedregister >= valueceiling)
|
||||
*ptr = av->next;
|
||||
else
|
||||
ptr = &av->next;
|
||||
}
|
||||
}
|
||||
|
||||
for (stacked = stackedvalues; stacked; stacked = stacked->next)
|
||||
unstackvalue(stacked);
|
||||
}
|
||||
|
||||
static void removecsesfromextendedbasicblock(PCodeBlock *block) {
|
||||
PCLink *succ;
|
||||
int counter;
|
||||
State state;
|
||||
|
||||
removecsesfrombasicblock(block);
|
||||
while (block->successors &&
|
||||
!block->successors->nextLink &&
|
||||
block->successors->block->predecessors &&
|
||||
!block->successors->block->predecessors->nextLink) {
|
||||
block = block->successors->block;
|
||||
removecsesfrombasicblock(block);
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
for (succ = block->successors; succ; succ = succ->nextLink) {
|
||||
if (!(succ->block->flags & fPCBlockFlag4) && succ->block->predecessors && !succ->block->predecessors->nextLink)
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (counter) {
|
||||
getvaluestate(&state);
|
||||
forkvaluestate(nextvaluenumber);
|
||||
for (succ = block->successors; succ; succ = succ->nextLink) {
|
||||
if (!(succ->block->flags & fPCBlockFlag4) && succ->block->predecessors && !succ->block->predecessors->nextLink) {
|
||||
removecsesfromextendedbasicblock(succ->block);
|
||||
regressvaluestate();
|
||||
}
|
||||
}
|
||||
setvaluestate(&state);
|
||||
}
|
||||
}
|
||||
|
||||
void removecommonsubexpressions(Object *proc, int flag) {
|
||||
PCodeBlock *block;
|
||||
|
||||
moreaggressiveoptimization = flag;
|
||||
removedcommonsubexpressions = 0;
|
||||
gather_alias_info();
|
||||
allocatecsedatastructures();
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock)
|
||||
block->flags &= ~fPCBlockFlag4;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
if (!(block->flags & fPCBlockFlag4)) {
|
||||
initializecsedatastructures();
|
||||
removecsesfromextendedbasicblock(block);
|
||||
}
|
||||
}
|
||||
|
||||
freeoheap();
|
||||
}
|
||||
|
@ -0,0 +1,549 @@
|
||||
#include "compiler/VectorArraysToRegs.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CFunc.h"
|
||||
#include "compiler/BitVectors.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
#include "compiler/PCode.h"
|
||||
#include "compiler/PCodeInfo.h"
|
||||
#include "compiler/Registers.h"
|
||||
#include "compiler/UseDefChains.h"
|
||||
#include "compiler/objects.h"
|
||||
#include "compiler/types.h"
|
||||
|
||||
typedef struct LocalVectorArray {
|
||||
struct LocalVectorArray *next;
|
||||
Object *object;
|
||||
unsigned int invalid:1;
|
||||
SInt32 arraySize;
|
||||
SInt32 elementCount;
|
||||
int totalUses;
|
||||
int elements[1];
|
||||
} LocalVectorArray;
|
||||
|
||||
typedef struct VectorPropInfo {
|
||||
UInt32 *vec0;
|
||||
UInt32 *vec4;
|
||||
UInt32 *vec8;
|
||||
UInt32 *vecC;
|
||||
} VectorPropInfo;
|
||||
|
||||
typedef struct ADDI {
|
||||
PCode *instr;
|
||||
RegUseOrDef *list;
|
||||
} ADDI;
|
||||
|
||||
static int number_of_ADDIs;
|
||||
static ADDI *ADDIs;
|
||||
static VectorPropInfo *vectorpropinfo;
|
||||
static int *naddsinblock;
|
||||
static int *firstaddinblock;
|
||||
static Boolean converted_arrays;
|
||||
|
||||
static LocalVectorArray *scanforlocalvectorarrays(void) {
|
||||
SInt32 elementCount;
|
||||
LocalVectorArray *head;
|
||||
LocalVectorArray *array;
|
||||
ObjectList *list;
|
||||
int i;
|
||||
SInt32 arraySize;
|
||||
|
||||
head = NULL;
|
||||
|
||||
for (list = locals; list; list = list->next) {
|
||||
if (
|
||||
list->object &&
|
||||
!(IS_TYPE_POINTER(list->object->type) ? (TPTR_QUAL(list->object->type) & Q_VOLATILE) : (list->object->qual & Q_VOLATILE)) &&
|
||||
list->object->type &&
|
||||
IS_TYPE_ARRAY(list->object->type) &&
|
||||
IS_TYPE_VECTOR(TPTR_TARGET(list->object->type))
|
||||
) {
|
||||
arraySize = list->object->type->size;
|
||||
elementCount = arraySize / 16;
|
||||
if (elementCount > 0 && elementCount <= 8) {
|
||||
array = oalloc(sizeof(int) * (elementCount - 1) + sizeof(LocalVectorArray));
|
||||
array->next = head;
|
||||
head = array;
|
||||
|
||||
array->object = list->object;
|
||||
array->arraySize = arraySize;
|
||||
array->elementCount = elementCount;
|
||||
array->totalUses = 0;
|
||||
array->invalid = 0;
|
||||
|
||||
for (i = 0; i < elementCount; i++) {
|
||||
array->elements[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static LocalVectorArray *lookup_vector_array_object(LocalVectorArray *arrays, Object *object) {
|
||||
while (arrays) {
|
||||
if (arrays->object == object)
|
||||
return arrays;
|
||||
arrays = arrays->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void scaninstructions(LocalVectorArray *arrays) {
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
int counter;
|
||||
int i;
|
||||
PCodeArg *op;
|
||||
LocalVectorArray *array;
|
||||
int element;
|
||||
|
||||
naddsinblock = oalloc(sizeof(int) * pcblockcount);
|
||||
memclrw(naddsinblock, sizeof(int) * pcblockcount);
|
||||
|
||||
firstaddinblock = oalloc(sizeof(int) * pcblockcount);
|
||||
memclrw(firstaddinblock, sizeof(int) * pcblockcount);
|
||||
|
||||
number_of_ADDIs = 0;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
firstaddinblock[block->blockIndex] = number_of_ADDIs;
|
||||
counter = 0;
|
||||
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
if (!(instr->flags & fPCodeFlag1) && instr->argCount) {
|
||||
op = instr->args;
|
||||
i = instr->argCount;
|
||||
while (i--) {
|
||||
if (
|
||||
op->kind == PCOp_MEMORY &&
|
||||
op->arg == PCOpMemory1 &&
|
||||
(array = lookup_vector_array_object(arrays, op->data.mem.obj)) &&
|
||||
!array->invalid
|
||||
)
|
||||
{
|
||||
if (instr->op != PC_ADDI) {
|
||||
array->invalid = 1;
|
||||
} else if (instr->args[0].data.reg.reg < n_real_registers[RegClass_GPR]) {
|
||||
array->invalid = 1;
|
||||
} else {
|
||||
number_of_ADDIs++;
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (!array->invalid) {
|
||||
element = op->data.mem.offset / 16;
|
||||
if (element < array->elementCount)
|
||||
array->elements[element]++;
|
||||
else
|
||||
array->invalid = 1;
|
||||
}
|
||||
}
|
||||
op++;
|
||||
}
|
||||
}
|
||||
}
|
||||
naddsinblock[block->blockIndex] = counter;
|
||||
}
|
||||
}
|
||||
|
||||
static void computeaddilist(LocalVectorArray *arrays) {
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
RegUseOrDef *list;
|
||||
ADDI *addi;
|
||||
UInt32 *vec;
|
||||
LocalVectorArray *array;
|
||||
UseOrDef *def;
|
||||
int defID;
|
||||
UseOrDef *use;
|
||||
int useID;
|
||||
|
||||
ADDIs = oalloc(sizeof(ADDI) * number_of_ADDIs);
|
||||
memclrw(ADDIs, sizeof(ADDI) * number_of_ADDIs);
|
||||
|
||||
vec = oalloc(4 * ((number_of_Uses + 31) >> 5));
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
if (naddsinblock[block->blockIndex]) {
|
||||
bitvectorcopy(vec, usedefinfo[block->blockIndex].usevec1C, number_of_Uses);
|
||||
addi = &ADDIs[firstaddinblock[block->blockIndex] + naddsinblock[block->blockIndex] - 1];
|
||||
for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
|
||||
if (!(instr->flags & fPCodeFlag1) && instr->argCount) {
|
||||
int reg; // r18
|
||||
if (
|
||||
instr->op == PC_ADDI &&
|
||||
(reg = instr->args[0].data.reg.reg) >= n_real_registers[RegClass_GPR] &&
|
||||
instr->args[2].kind == PCOp_MEMORY &&
|
||||
(unsigned char) instr->args[2].arg == 1 &&
|
||||
(array = lookup_vector_array_object(arrays, instr->args[2].data.mem.obj)) &&
|
||||
!array->invalid
|
||||
)
|
||||
{
|
||||
addi->instr = instr;
|
||||
addi->list = NULL;
|
||||
for (list = reg_Uses[RegClass_GPR][reg]; list; list = list->next) {
|
||||
if (bitvectorgetbit(list->id, vec)) {
|
||||
RegUseOrDef *node = oalloc(sizeof(RegUseOrDef));
|
||||
node->id = list->id;
|
||||
node->next = addi->list;
|
||||
addi->list = node;
|
||||
}
|
||||
}
|
||||
addi--;
|
||||
}
|
||||
|
||||
for (def = &Defs[defID = instr->defID]; defID < number_of_Defs && def->pcode == instr; def++, defID++) {
|
||||
if (def->v.kind == PCOp_REGISTER) {
|
||||
RegUseOrDef *l;
|
||||
for (l = reg_Uses[(char) def->v.arg][def->v.u.reg]; l; l = l->next)
|
||||
bitvectorclearbit(l->id, vec);
|
||||
}
|
||||
}
|
||||
|
||||
for (use = &Uses[useID = instr->useID]; useID < number_of_Uses && use->pcode == instr; use++, useID++) {
|
||||
if (use->v.kind == PCOp_REGISTER)
|
||||
bitvectorsetbit(useID, vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void allocatevectorpropinfo(void) {
|
||||
VectorPropInfo *info;
|
||||
int i;
|
||||
|
||||
vectorpropinfo = oalloc(sizeof(VectorPropInfo) * pcblockcount);
|
||||
for (i = 0, info = vectorpropinfo; i < pcblockcount; i++, info++) {
|
||||
info->vec0 = oalloc(4 * ((number_of_ADDIs + 31) >> 5));
|
||||
info->vec4 = oalloc(4 * ((number_of_ADDIs + 31) >> 5));
|
||||
info->vec8 = oalloc(4 * ((number_of_ADDIs + 31) >> 5));
|
||||
info->vecC = oalloc(4 * ((number_of_ADDIs + 31) >> 5));
|
||||
}
|
||||
}
|
||||
|
||||
static void computelocalvectorpropinfo(LocalVectorArray *arrays) {
|
||||
VectorPropInfo *info;
|
||||
PCodeBlock *block;
|
||||
PCode *instr;
|
||||
UInt32 *vec0;
|
||||
UInt32 *vec4;
|
||||
int index;
|
||||
PCodeArg *op;
|
||||
int i;
|
||||
int addi_i;
|
||||
ADDI *addi;
|
||||
LocalVectorArray *array;
|
||||
|
||||
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
||||
info = &vectorpropinfo[block->blockIndex];
|
||||
vec0 = info->vec0;
|
||||
vec4 = info->vec4;
|
||||
bitvectorinitialize(vec0, number_of_ADDIs, 0);
|
||||
bitvectorinitialize(vec4, number_of_ADDIs, 0);
|
||||
index = firstaddinblock[block->blockIndex];
|
||||
|
||||
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
||||
if (!(instr->flags & fPCodeFlag1) && instr->argCount) {
|
||||
i = instr->argCount;
|
||||
op = instr->args;
|
||||
while (i--) {
|
||||
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR && (op->data.reg.effect & EffectWrite)) {
|
||||
for (addi_i = 0, addi = ADDIs; addi_i < number_of_ADDIs; addi_i++, addi++) {
|
||||
if (
|
||||
addi->instr &&
|
||||
(char) addi->instr->args[0].arg == (char) op->arg &&
|
||||
addi->instr->args[0].data.reg.reg == op->data.reg.reg
|
||||
)
|
||||
{
|
||||
if (addi->instr->block == block)
|
||||
bitvectorclearbit(addi_i, vec0);
|
||||
else
|
||||
bitvectorsetbit(addi_i, vec4);
|
||||
}
|
||||
}
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
if (
|
||||
instr->op == PC_ADDI &&
|
||||
instr->args[2].kind == PCOp_MEMORY &&
|
||||
instr->args[2].arg == PCOpMemory1 &&
|
||||
(array = lookup_vector_array_object(arrays, instr->args[2].data.mem.obj)) &&
|
||||
!array->invalid
|
||||
)
|
||||
{
|
||||
bitvectorsetbit(index, vec0);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void computeglobalvectorpropinfo(void) {
|
||||
VectorPropInfo *info;
|
||||
PCodeBlock *block;
|
||||
UInt32 *vec0;
|
||||
UInt32 *vec4;
|
||||
UInt32 *vec8;
|
||||
UInt32 *vecC;
|
||||
int bitvecsize;
|
||||
int blockIndex;
|
||||
int i;
|
||||
int j;
|
||||
int flag;
|
||||
PCLink *preds;
|
||||
UInt32 val;
|
||||
|
||||
bitvecsize = (number_of_ADDIs + 31) >> 5;
|
||||
flag = 1;
|
||||
info = &vectorpropinfo[pcbasicblocks->blockIndex];
|
||||
bitvectorinitialize(info->vec8, number_of_ADDIs, 0);
|
||||
bitvectorcopy(info->vecC, info->vec0, number_of_ADDIs);
|
||||
|
||||
for (block = pcbasicblocks->nextBlock; block; block = block->nextBlock) {
|
||||
info = &vectorpropinfo[block->blockIndex];
|
||||
vecC = info->vecC;
|
||||
vec4 = info->vec4;
|
||||
for (i = 0; i < bitvecsize; vecC++, vec4++, i++)
|
||||
*vecC = ~*vec4;
|
||||
}
|
||||
|
||||
while (flag) {
|
||||
flag = 0;
|
||||
for (blockIndex = 0; blockIndex < pcblockcount; blockIndex++) {
|
||||
if (depthfirstordering[blockIndex]) {
|
||||
info = &vectorpropinfo[depthfirstordering[blockIndex]->blockIndex];
|
||||
if ((preds = depthfirstordering[blockIndex]->predecessors)) {
|
||||
vec8 = info->vec8;
|
||||
bitvectorcopy(vec8, vectorpropinfo[preds->block->blockIndex].vecC, number_of_ADDIs);
|
||||
for (preds = preds->nextLink; preds; preds = preds->nextLink)
|
||||
bitvectorintersect(vec8, vectorpropinfo[preds->block->blockIndex].vecC, number_of_ADDIs);
|
||||
}
|
||||
|
||||
vecC = info->vecC;
|
||||
vec8 = info->vec8;
|
||||
vec0 = info->vec0;
|
||||
vec4 = info->vec4;
|
||||
for (j = 0; j < bitvecsize; j++) {
|
||||
val = *vec0 | (*vec8 & ~*vec4);
|
||||
if (val != *vecC) {
|
||||
*vecC = val;
|
||||
flag = 1;
|
||||
}
|
||||
vec8++;
|
||||
vecC++;
|
||||
vec4++;
|
||||
vec0++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int precedes(PCode *a, PCode *b) {
|
||||
PCode *scan;
|
||||
|
||||
for (scan = a->nextPCode; scan; scan = scan->nextPCode) {
|
||||
if (scan == b)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int checkvectorstoreorload(int addiID, int useID) {
|
||||
PCode *addiInstr;
|
||||
UseOrDef *use;
|
||||
|
||||
addiInstr = ADDIs[addiID].instr;
|
||||
use = Uses + useID;
|
||||
if (!addiInstr)
|
||||
return 0;
|
||||
|
||||
if (addiInstr->args[0].data.reg.reg < n_real_registers[RegClass_GPR])
|
||||
return 0;
|
||||
|
||||
if (use->pcode->op != PC_LVX && use->pcode->op != PC_STVX)
|
||||
return 0;
|
||||
|
||||
if (
|
||||
use->pcode->args[1].kind != PCOp_REGISTER ||
|
||||
use->pcode->args[1].arg != RegClass_GPR ||
|
||||
use->pcode->args[1].data.reg.reg != 0
|
||||
)
|
||||
return 0;
|
||||
|
||||
return use->pcode->args[2].data.reg.reg == addiInstr->args[0].data.reg.reg;
|
||||
}
|
||||
|
||||
static int checkalluses(LocalVectorArray *arrays, int addiID) {
|
||||
RegUseOrDef *list;
|
||||
PCode *instr;
|
||||
LocalVectorArray *array;
|
||||
|
||||
instr = ADDIs[addiID].instr;
|
||||
for (list = ADDIs[addiID].list; list; list = list->next) {
|
||||
if (list && !checkvectorstoreorload(addiID, list->id)) {
|
||||
array = lookup_vector_array_object(arrays, instr->args[2].data.mem.obj);
|
||||
array->invalid = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void convert_array_to_register(LocalVectorArray *arrays, int addiID) {
|
||||
ADDI *addi;
|
||||
int newReg;
|
||||
RegUseOrDef *list;
|
||||
PCode *instr;
|
||||
PCode *useInstr;
|
||||
LocalVectorArray *array;
|
||||
int element;
|
||||
|
||||
addi = ADDIs + addiID;
|
||||
|
||||
if (!(instr = addi->instr))
|
||||
return;
|
||||
|
||||
if (
|
||||
!(array = lookup_vector_array_object(arrays, instr->args[2].data.mem.obj)) ||
|
||||
array->invalid
|
||||
)
|
||||
return;
|
||||
|
||||
element = instr->args[2].data.mem.offset / 16;
|
||||
if (element > array->elementCount)
|
||||
return;
|
||||
|
||||
newReg = array->elements[element];
|
||||
for (list = addi->list; list; list = list->next) {
|
||||
useInstr = Uses[list->id].pcode;
|
||||
if (useInstr->op == PC_LVX) {
|
||||
converted_arrays = 1;
|
||||
change_opcode(useInstr, PC_VMR);
|
||||
change_num_operands(useInstr, 2);
|
||||
useInstr->args[1].kind = PCOp_REGISTER;
|
||||
useInstr->args[1].arg = RegClass_VR;
|
||||
useInstr->args[1].data.reg.reg = newReg;
|
||||
useInstr->args[1].data.reg.effect = EffectRead;
|
||||
} else if (useInstr->op == PC_STVX) {
|
||||
converted_arrays = 1;
|
||||
change_opcode(useInstr, PC_VMR);
|
||||
change_num_operands(useInstr, 2);
|
||||
useInstr->args[1] = useInstr->args[0];
|
||||
useInstr->args[0].kind = PCOp_REGISTER;
|
||||
useInstr->args[0].arg = RegClass_VR;
|
||||
useInstr->args[0].data.reg.reg = newReg;
|
||||
useInstr->args[0].data.reg.effect = EffectWrite;
|
||||
} else {
|
||||
#line 661
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
deletepcode(addi->instr);
|
||||
}
|
||||
|
||||
static void convert_arrays_to_registers(LocalVectorArray *arrays) {
|
||||
int i;
|
||||
int counter;
|
||||
LocalVectorArray **ptr;
|
||||
LocalVectorArray *array;
|
||||
|
||||
for (i = 0; i < number_of_ADDIs; i++)
|
||||
checkalluses(arrays, i);
|
||||
|
||||
counter = 0;
|
||||
ptr = &arrays;
|
||||
array = *ptr;
|
||||
while (array) {
|
||||
if (array->invalid) {
|
||||
*ptr = array->next;
|
||||
array = *ptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
counter += array->elementCount;
|
||||
|
||||
for (i = 0; i < array->elementCount; i++)
|
||||
array->totalUses += array->elements[i];
|
||||
|
||||
array = array->next;
|
||||
}
|
||||
|
||||
if (arrays) {
|
||||
while (counter > 32) {
|
||||
LocalVectorArray *best;
|
||||
int score;
|
||||
score = 0;
|
||||
best = NULL;
|
||||
for (array = arrays; array; array = array->next) {
|
||||
if (best) {
|
||||
if (array->totalUses < score) {
|
||||
score = array->totalUses;
|
||||
best = array;
|
||||
}
|
||||
} else {
|
||||
best = array;
|
||||
score = array->totalUses;
|
||||
}
|
||||
}
|
||||
|
||||
if (!best)
|
||||
break;
|
||||
|
||||
if (best == arrays) {
|
||||
arrays = best->next;
|
||||
} else {
|
||||
for (array = arrays; array; array = array->next) {
|
||||
if (array->next == best) {
|
||||
array->next = best->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
counter -= best->elementCount;
|
||||
}
|
||||
|
||||
if (!(array = arrays))
|
||||
return;
|
||||
|
||||
while (array) {
|
||||
for (i = 0; i < array->elementCount; i++)
|
||||
array->elements[i] = used_virtual_registers[RegClass_VR]++;
|
||||
array = array->next;
|
||||
}
|
||||
|
||||
if (arrays) {
|
||||
for (i = 0; i < number_of_ADDIs; i++)
|
||||
convert_array_to_register(arrays, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vectorarraystoregs(void) {
|
||||
LocalVectorArray *arrays;
|
||||
|
||||
converted_arrays = 0;
|
||||
if ((arrays = scanforlocalvectorarrays())) {
|
||||
scaninstructions(arrays);
|
||||
if (number_of_ADDIs > 0) {
|
||||
computeusedefchains(0);
|
||||
computeaddilist(arrays);
|
||||
allocatevectorpropinfo();
|
||||
computelocalvectorpropinfo(arrays);
|
||||
computedepthfirstordering();
|
||||
computeglobalvectorpropinfo();
|
||||
convert_arrays_to_registers(arrays);
|
||||
}
|
||||
}
|
||||
|
||||
freeoheap();
|
||||
return converted_arrays;
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
* Common imports and Mac OS types
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -3,4 +3,8 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern int propagatedadds;
|
||||
|
||||
extern void propagateaddinstructions(Object *proc);
|
||||
|
||||
#endif
|
||||
|
@ -3,4 +3,57 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct AliasMember AliasMember;
|
||||
|
||||
typedef enum AliasType {
|
||||
AliasType0,
|
||||
AliasType1,
|
||||
AliasType2
|
||||
} AliasType;
|
||||
|
||||
struct Alias {
|
||||
Alias *next;
|
||||
Alias *hashNext;
|
||||
AliasMember *children;
|
||||
AliasMember *parents;
|
||||
Object *object;
|
||||
SInt32 offset;
|
||||
SInt32 size;
|
||||
int valuenumber;
|
||||
PCode *valuepcode;
|
||||
UInt32 *vec24;
|
||||
int index;
|
||||
AliasType type;
|
||||
};
|
||||
|
||||
struct AliasMember {
|
||||
AliasMember *nextParent;
|
||||
AliasMember *nextChild;
|
||||
Alias *parent;
|
||||
Alias *child;
|
||||
};
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern Alias *worst_case;
|
||||
extern Object worst_case_obj;
|
||||
|
||||
extern void initialize_aliases(void);
|
||||
extern Alias *make_alias(Object *object, SInt32 offset, SInt32 size);
|
||||
extern Alias *make_alias_set(void);
|
||||
extern void add_alias_member(Alias *parent, Alias *child);
|
||||
extern Alias *make_alias_set_from_IR(void);
|
||||
extern void gather_alias_info(void);
|
||||
extern Boolean may_alias(PCode *a, PCode *b);
|
||||
extern Boolean uniquely_aliases(PCode *a, PCode *b);
|
||||
extern Boolean may_alias_worst_case(PCode *pcode);
|
||||
extern Boolean may_alias_object(PCode *pcode, Object *object);
|
||||
extern void initialize_alias_values(void);
|
||||
extern void update_alias_value(Alias *alias, PCode *pcode);
|
||||
extern void update_all_alias_values(void);
|
||||
|
||||
#endif
|
||||
|
@ -25,11 +25,13 @@ extern Boolean Bv_IsEmpty(const BitVector *bv);
|
||||
|
||||
inline void Bv_SetBit(UInt32 bit, BitVector *bv) {
|
||||
if ((bit / 32) < bv->size) {
|
||||
bv->data[bit / 32] |= ~(1 << (bit & 31));
|
||||
bv->data[bit / 32] |= 1 << (bit & 31);
|
||||
} else {
|
||||
#line 56
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
#define Bv_IsBitSet(_bit, _bv) ( (((_bit) >> 5) < (_bv)->size) && ((_bv)->data[(_bit) >> 5] & (1 << ((_bit) & 31))) )
|
||||
|
||||
#endif
|
@ -3,4 +3,19 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern void bitvectorcopy(UInt32 *dst, UInt32 *src, int len);
|
||||
extern int bitvectorchanged(UInt32 *dst, UInt32 *src, int len);
|
||||
extern void bitvectorinitialize(UInt32 *vec, int len, UInt32 initval);
|
||||
extern void bitvectorintersect(UInt32 *dst, UInt32 *src, int len);
|
||||
extern void bitvectorunion(UInt32 *dst, UInt32 *src, int len);
|
||||
extern void bitvectordifference(UInt32 *dst, UInt32 *src, int len);
|
||||
extern void bitvectorcomplement(UInt32 *dst, UInt32 *src, int len);
|
||||
extern int bitvectorcount(UInt32 *vec, int len);
|
||||
extern int bitvectorisempty(UInt32 *vec, int len);
|
||||
extern int bitvectorintersectionisempty(UInt32 *a, UInt32 *b, int len);
|
||||
|
||||
#define bitvectorgetbit(_bit, _vec) ((1 << ((_bit) & 31)) & (_vec)[(_bit) >> 5])
|
||||
#define bitvectorsetbit(_bit, _vec) ((_vec)[(_bit) >> 5] |= 1 << ((_bit) & 31))
|
||||
#define bitvectorclearbit(_bit, _vec) ((_vec)[(_bit) >> 5] &= ~(1 << ((_bit) & 31)))
|
||||
|
||||
#endif
|
||||
|
@ -3,4 +3,7 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
// TODO
|
||||
extern Boolean CExcept_CanThrowException(Object *obj, Boolean flag);
|
||||
|
||||
#endif
|
||||
|
@ -10,7 +10,7 @@ extern const CInt64 cint64_one;
|
||||
extern const CInt64 cint64_max;
|
||||
extern const CInt64 cint64_min;
|
||||
|
||||
inline int CInt64_IsNegative(const CInt64 *n) {
|
||||
inline Boolean CInt64_IsNegative(const CInt64 *n) {
|
||||
return (n->hi & 0x80000000) != 0;
|
||||
}
|
||||
inline UInt32 CInt64_GetULong(const CInt64 *n) { // 42E660 in mwcppc.exe
|
||||
@ -33,6 +33,9 @@ inline Boolean CInt64_IsZero(CInt64 *n) {
|
||||
// return 0;
|
||||
return n->hi == 0 && n->lo == 0;
|
||||
}
|
||||
inline Boolean CInt64_IsOne(CInt64 *n) { // assumed name
|
||||
return n->hi == 0 && n->lo == 1;
|
||||
}
|
||||
inline void CInt64_Extend32(CInt64 *n) { // assumed name
|
||||
n->hi = (n->lo >> 31) ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ typedef struct COpts {
|
||||
Boolean disable_registers;
|
||||
Boolean fp_contract;
|
||||
Boolean no_register_save_helpers;
|
||||
char ppc_unroll_speculative;
|
||||
Boolean ppc_unroll_speculative;
|
||||
short ppc_unroll_instructions_limit;
|
||||
short ppc_unroll_factor_limit;
|
||||
Boolean altivec_model;
|
||||
@ -206,20 +206,20 @@ typedef struct COpts {
|
||||
Boolean optimize_for_size;
|
||||
Boolean optimizewithasm;
|
||||
Boolean crippled;
|
||||
char opt_common_subs;
|
||||
char opt_loop_invariants;
|
||||
Boolean opt_common_subs;
|
||||
Boolean opt_loop_invariants;
|
||||
char opt_propagation;
|
||||
char opt_dead_assignments;
|
||||
char opt_strength_reduction;
|
||||
char opt_strength_reduction_strict;
|
||||
Boolean opt_strength_reduction;
|
||||
Boolean opt_strength_reduction_strict;
|
||||
char opt_dead_code;
|
||||
char opt_lifetimes;
|
||||
char _B1; // unused?
|
||||
char opt_unroll_loops;
|
||||
char opt_vectorize_loops;
|
||||
char _B4; // amount of IRO passes?
|
||||
char opt_pointer_analysis;
|
||||
char opt_pointer_analysis_mode;
|
||||
Boolean opt_pointer_analysis;
|
||||
unsigned char opt_pointer_analysis_mode;
|
||||
char loop_unroll_count;
|
||||
char loop_unroll_size_threshold;
|
||||
Boolean isGeneratingDebugInfo;
|
||||
|
@ -3,4 +3,9 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern int movedloopinvariantcode;
|
||||
extern int unswitchedinvariantcode;
|
||||
|
||||
extern void moveloopinvariantcode(void);
|
||||
|
||||
#endif
|
||||
|
@ -2,5 +2,11 @@
|
||||
#define COMPILER_COLORING_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/Registers.h"
|
||||
|
||||
//extern RegClass coloring_class;
|
||||
extern char coloring_class;
|
||||
|
||||
extern void colorinstructions(Object *proc);
|
||||
|
||||
#endif
|
||||
|
@ -119,6 +119,12 @@ extern void memclr(void *ptr, SInt32 size);
|
||||
extern void memclrw(void *ptr, SInt32 size);
|
||||
extern void CToLowercase(char *a, char *b);
|
||||
extern short getbit(SInt32 l);
|
||||
extern inline SInt32 CTool_EndianReadWord32(void *value) {
|
||||
return *((SInt32 *) value);
|
||||
}
|
||||
extern inline UInt32 CTool_EndianConvertWord32(UInt32 value) {
|
||||
return value;
|
||||
}
|
||||
extern void CTool_EndianConvertWord64(CInt64 ci, char *result);
|
||||
extern UInt16 CTool_EndianConvertInPlaceWord16Ptr(UInt16 *x);
|
||||
extern UInt32 CTool_EndianConvertInPlaceWord32Ptr(UInt32 *x);
|
||||
|
@ -3,4 +3,8 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern int propagatedconstants;
|
||||
|
||||
extern void propagateconstants(void);
|
||||
|
||||
#endif
|
||||
|
@ -2,5 +2,51 @@
|
||||
#define COMPILER_COPYPROPAGATION_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/UseDefChains.h"
|
||||
|
||||
typedef int (*IsCandidateFunc)(PCode *);
|
||||
typedef int (*PropagatesToUseFunc)(int a, int b);
|
||||
typedef void (*PropagateAndFinishFunc)(int id);
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct Propagation {
|
||||
IsCandidateFunc is_candidate;
|
||||
PropagatesToUseFunc propagatestouse;
|
||||
PropagateAndFinishFunc propagateandfinish;
|
||||
char *name;
|
||||
char *nameplural;
|
||||
char *format;
|
||||
Boolean computesUseDefChains;
|
||||
} Propagation;
|
||||
|
||||
typedef struct Candidate {
|
||||
PCode *pcode;
|
||||
RegUseOrDef *list;
|
||||
} Candidate;
|
||||
|
||||
typedef struct PropInfo {
|
||||
UInt32 *vec0;
|
||||
UInt32 *vec4;
|
||||
UInt32 *vec8;
|
||||
UInt32 *vecC;
|
||||
} PropInfo;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern int propagatedcopies;
|
||||
extern int propagated_instructions;
|
||||
extern int recursive_propagation;
|
||||
extern int number_of_candidates;
|
||||
extern Candidate *Candidates;
|
||||
extern PropInfo *propinfo;
|
||||
extern int *ncandidatesinblock;
|
||||
extern int *firstcandidateinblock;
|
||||
|
||||
extern int precedes(PCode *a, PCode *b);
|
||||
extern void propagateinstructions(Object *proc, Propagation *config, int passCount, Boolean localflag);
|
||||
extern void propagatecopyinstructions(Object *proc, int flag);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,48 @@
|
||||
#ifndef COMPILER_IROUSEDEF_H
|
||||
#define COMPILER_IROUSEDEF_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/BitVector.h"
|
||||
#include "compiler/enode.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
struct IROUse {
|
||||
SInt32 index;
|
||||
IRONode *node;
|
||||
IROLinear *linear;
|
||||
VarRecord *var;
|
||||
IROUse *globalnext;
|
||||
IROUse *varnext;
|
||||
BitVector *x18;
|
||||
UInt16 x1C;
|
||||
};
|
||||
struct IRODef {
|
||||
SInt32 index;
|
||||
IRONode *node;
|
||||
IROLinear *linear;
|
||||
VarRecord *var;
|
||||
IRODef *globalnext;
|
||||
IRODef *varnext;
|
||||
UInt16 x18;
|
||||
Boolean x1A;
|
||||
Boolean x1B;
|
||||
Boolean x1C;
|
||||
Boolean x1D;
|
||||
};
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern ENodeType IRO_NonAssignmentOp[MAXEXPR];
|
||||
extern IROUse *IRO_FirstVarUse;
|
||||
extern IROUse *IRO_LastVarUse;
|
||||
|
||||
extern CInt64 IRO_GetSelfAssignmentVal(IROLinear *linear);
|
||||
extern void IRO_InitializeNonAssignmentOpArray(void);
|
||||
extern void IRO_InitializeAssignmentFoldingFunctionArray(void);
|
||||
extern Boolean IRO_UseDef(Boolean optDeadAssignments, Boolean optPropagation);
|
||||
extern void IRO_SplitLifetimes(void);
|
||||
|
||||
#endif
|
||||
|
@ -150,7 +150,8 @@ typedef enum IAEffectType {
|
||||
IAEffect_0,
|
||||
IAEffect_1,
|
||||
IAEffect_2,
|
||||
IAEffect_3
|
||||
IAEffect_3,
|
||||
IAEffect_4
|
||||
} IAEffectType;
|
||||
typedef struct IAEffect {
|
||||
IAEffectType type;
|
||||
@ -166,8 +167,8 @@ typedef struct IAEffects {
|
||||
Boolean x3;
|
||||
Boolean x4;
|
||||
Boolean x5;
|
||||
UInt32 numoperands;
|
||||
UInt32 numlabels;
|
||||
SInt32 numoperands;
|
||||
SInt32 numlabels;
|
||||
IAEffect operands[16];
|
||||
CLabel *labels[16];
|
||||
} IAEffects;
|
||||
|
@ -3,4 +3,39 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
enum {
|
||||
fSpilled = 1,
|
||||
fPushed = 2,
|
||||
fCoalesced = 4,
|
||||
fCoalescedInto = 8,
|
||||
fPairHigh = 0x10,
|
||||
fPairLow = 0x20,
|
||||
fIGNode40 = 0x40
|
||||
};
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct IGNode {
|
||||
struct IGNode *next;
|
||||
Object *spillTemporary;
|
||||
PCode *instr8;
|
||||
int spillCost;
|
||||
short x10;
|
||||
short x12;
|
||||
short x14;
|
||||
UInt16 flags;
|
||||
short arraySize;
|
||||
short array[1];
|
||||
} IGNode;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern IGNode **interferencegraph;
|
||||
extern Boolean coalesced_nregisters;
|
||||
|
||||
extern int interferes(UInt32 a, UInt32 b);
|
||||
extern void buildinterferencegraph(Object *proc);
|
||||
|
||||
#endif
|
||||
|
@ -3,7 +3,28 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
// do me
|
||||
typedef struct IROAddrRecord IROAddrRecord;
|
||||
typedef struct IROAssign IROAssign;
|
||||
typedef struct IRODef IRODef;
|
||||
typedef struct IROElmList IROElmList;
|
||||
typedef struct IROExpr IROExpr;
|
||||
typedef struct IROLinear IROLinear;
|
||||
typedef struct IROList IROList;
|
||||
typedef struct IROListNode IROListNode;
|
||||
typedef struct IROLoop IROLoop;
|
||||
typedef struct IRONode IRONode;
|
||||
typedef struct IROUse IROUse;
|
||||
|
||||
extern Boolean DoScalarize;
|
||||
extern Boolean DoLinearize;
|
||||
extern Boolean EarlyReturn;
|
||||
extern Boolean IRO_CPFirstTime;
|
||||
extern Boolean VectorPhaseCalledFromUnroll;
|
||||
extern Boolean IRO_Log;
|
||||
|
||||
extern Statement *IRO_Optimizer(Object *obj, Statement *stmt);
|
||||
extern void IRO_Setup(void);
|
||||
extern void IRO_Cleanup(void);
|
||||
extern void CodeGen_UpdateOptimizerOptions(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,45 @@
|
||||
#ifndef COMPILER_IROCSE_H
|
||||
#define COMPILER_IROCSE_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/BitVector.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
struct IROExpr {
|
||||
Boolean x0;
|
||||
UInt16 index;
|
||||
IROLinear *linear;
|
||||
Object *x8;
|
||||
IRONode *node;
|
||||
BitVector *depends;
|
||||
IROExpr *x14;
|
||||
Boolean couldError;
|
||||
Boolean notSubable;
|
||||
IROLinear *x1A;
|
||||
VarRecord *x1E;
|
||||
IROLinear *x22;
|
||||
IROExpr *next;
|
||||
};
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern BitVector *IRO_Depends;
|
||||
extern Boolean IRO_NotSubable;
|
||||
extern Boolean IRO_IsVolatile;
|
||||
extern Boolean IRO_CouldError;
|
||||
extern IROExpr *IRO_FirstExpr;
|
||||
extern IROExpr *IRO_LastExpr;
|
||||
extern SInt32 IRO_NumExprs;
|
||||
|
||||
extern void IRO_FindDepends_NoAlloc(IROLinear *linear);
|
||||
extern void IRO_FindDepends(IROLinear *linear);
|
||||
extern void IRO_FindExpressions(BitVector *bv, Boolean flag);
|
||||
extern void IRO_RemoveExpr(IROExpr *expr);
|
||||
extern void IRO_ComputeAvail(void);
|
||||
extern void IRO_CommonSubs(void);
|
||||
extern void IRO_GenerateTopLevelExprsForSubableOperands(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,27 @@
|
||||
#ifndef COMPILER_IRODUMP_H
|
||||
#define COMPILER_IRODUMP_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/BitVector.h"
|
||||
#include "compiler/enode.h"
|
||||
|
||||
extern char *IRO_NodeName(ENodeType nodetype);
|
||||
extern void IRO_InitializeNodeNamesArray(void);
|
||||
extern void IRO_DumpIntTree(IROLinear *linear);
|
||||
extern void IRO_DumpLinearList(IROLinear *linear);
|
||||
extern void IRO_DumpBits(char *name, BitVector *bv);
|
||||
extern void IRO_DumpAfterPhase(char *str, Boolean flag);
|
||||
extern void IRO_LogForFunction(char *name);
|
||||
extern void IRO_DumpFlowgraph(void);
|
||||
extern void IRO_DumpNode(IRONode *node);
|
||||
extern void IRO_DumpAssignments(void);
|
||||
extern void IRO_DumpVars(void);
|
||||
extern void IRO_DumpDf(void);
|
||||
extern void IRO_DumpExprs(void);
|
||||
extern void IRO_SetupDump(void);
|
||||
extern void IRO_CleanupDump(void);
|
||||
extern void IRO_Dump(char *format, ...);
|
||||
extern void IRO_DumpAddr(IROAddrRecord *rec);
|
||||
extern void IRO_SpellType(Type *type, char *buf);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef COMPILER_IROEMPTYLOOP_H
|
||||
#define COMPILER_IROEMPTYLOOP_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
extern void IRO_FindEmptyLoops(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,10 @@
|
||||
#ifndef COMPILER_IROEVAL_H
|
||||
#define COMPILER_IROEVAL_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
// TODO
|
||||
extern void IRO_TruncateBitfieldValueToType(CInt64 *val, Type *type, Type *type2);
|
||||
extern void IRO_TruncateValueToType(CInt64 *val, Type *type);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef COMPILER_IROEXPRREGENERATION_H
|
||||
#define COMPILER_IROEXPRREGENERATION_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
extern void IRO_RegenerateExpressions(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,98 @@
|
||||
#ifndef COMPILER_IROFLOWGRAPH_H
|
||||
#define COMPILER_IROFLOWGRAPH_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/BitVector.h"
|
||||
#include "compiler/CError.h"
|
||||
#include "compiler/CompilerTools.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
|
||||
struct IRONode {
|
||||
UInt16 index;
|
||||
UInt16 numsucc;
|
||||
UInt16 *succ;
|
||||
UInt16 numpred;
|
||||
UInt16 *pred;
|
||||
IROLinear *first;
|
||||
IROLinear *last;
|
||||
BitVector *x16; // In
|
||||
BitVector *x1A; // Out
|
||||
BitVector *x1E; // Gen
|
||||
BitVector *x22; // Kill
|
||||
UInt32 x26;
|
||||
BitVector *x2A; // AA
|
||||
BitVector *dom;
|
||||
IRONode *nextnode;
|
||||
Boolean x36;
|
||||
Boolean x37;
|
||||
Boolean mustreach;
|
||||
Boolean x39;
|
||||
UInt16 loopdepth;
|
||||
Boolean x3C;
|
||||
struct ObjectSet *addressed;
|
||||
Boolean mustreach1;
|
||||
};
|
||||
|
||||
typedef struct IRONodes {
|
||||
UInt16 *indices;
|
||||
UInt16 num;
|
||||
UInt16 base;
|
||||
} IRONodes;
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern UInt16 IRO_NumNodes;
|
||||
extern IRONode *IRO_FirstNode;
|
||||
extern IRONode *IRO_LastNode;
|
||||
extern IRONode *IRO_EndNode;
|
||||
extern IRONode **IRO_NodeTable;
|
||||
extern BitVector *IRO_VarKills;
|
||||
extern BitVector *IRO_Avail;
|
||||
extern BitVector *IRO_FuncKills;
|
||||
extern BitVector *IRO_ExprKills;
|
||||
|
||||
extern void IRO_ComputeSuccPred(void);
|
||||
extern void IRO_ComputeDom(void);
|
||||
extern void IRO_BuildFlowgraph(IROLinear *linear);
|
||||
extern IRONode *IRO_NewFlowGraphNode(void);
|
||||
extern IRONode *IRO_MergeFlowGraphNodes(IRONode *a, IRONode *b);
|
||||
|
||||
inline void IROFlowgraph_sub_4C2140(IRONodes *nodes) {
|
||||
nodes->indices = oalloc(sizeof(UInt16) * IRO_NumNodes);
|
||||
nodes->num = 0;
|
||||
nodes->base = 0;
|
||||
}
|
||||
|
||||
inline void IROFlowgraph_sub_4C20E0(IRONodes *nodes) {
|
||||
}
|
||||
|
||||
inline UInt16 IROFlowgraph_sub_4C2040(IRONodes *nodes) {
|
||||
return nodes->num;
|
||||
}
|
||||
|
||||
inline UInt16 IROFlowgraph_sub_4C2100(IRONodes *nodes) {
|
||||
UInt16 result = -1;
|
||||
if (nodes->num) {
|
||||
result = nodes->indices[nodes->base];
|
||||
nodes->base = (nodes->base + 1) % IRO_NumNodes;
|
||||
nodes->num--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void IROFlowgraph_sub_4C3880(IRONodes *nodes, UInt16 index) {
|
||||
if (nodes->num < IRO_NumNodes) {
|
||||
nodes->indices[(nodes->base + nodes->num) % IRO_NumNodes] = index;
|
||||
nodes->num++;
|
||||
} else {
|
||||
#line 93
|
||||
CError_FATAL();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,12 @@
|
||||
#ifndef COMPILER_IROJUMP_H
|
||||
#define COMPILER_IROJUMP_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
extern Boolean IRO_DoJumpChaining(void);
|
||||
extern void IRO_MakeReachable(IRONode *node);
|
||||
extern Boolean IRO_RemoveUnreachable(void);
|
||||
extern Boolean IRO_RemoveRedundantJumps(void);
|
||||
extern Boolean IRO_RemoveLabels(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,163 @@
|
||||
#ifndef COMPILER_IROLINEARFORM_H
|
||||
#define COMPILER_IROLINEARFORM_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/Switch.h"
|
||||
#include "compiler/enode.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
|
||||
typedef struct IROLinearIRSave {
|
||||
IROLinear *firstLinear;
|
||||
IROLinear *lastLinear;
|
||||
UInt32 numLinear;
|
||||
Statement *curStat;
|
||||
Boolean disableDueToAsm;
|
||||
Boolean isLeafFunction;
|
||||
Boolean functionHasReturn;
|
||||
void *nullCheckList;
|
||||
Statement *currStmt;
|
||||
Statement *prevStmt;
|
||||
} IROLinearIRSave;
|
||||
|
||||
typedef enum IROLinearType {
|
||||
IROLinearNop,
|
||||
IROLinearOperand,
|
||||
IROLinearOp1Arg,
|
||||
IROLinearOp2Arg,
|
||||
IROLinearGoto,
|
||||
IROLinearIf,
|
||||
IROLinearIfNot,
|
||||
IROLinearReturn,
|
||||
IROLinearLabel,
|
||||
IROLinearSwitch,
|
||||
IROLinearOp3Arg,
|
||||
IROLinearFunccall,
|
||||
IROLinearEntry,
|
||||
IROLinearExit,
|
||||
IROLinearBeginCatch,
|
||||
IROLinearEndCatch,
|
||||
IROLinearEndCatchDtor,
|
||||
IROLinearAsm,
|
||||
IROLinear18,
|
||||
IROLinear19,
|
||||
IROLinearEnd
|
||||
} IROLinearType;
|
||||
|
||||
enum {
|
||||
IROLF_1 = 0x1,
|
||||
IROLF_Reffed = 0x2,
|
||||
IROLF_Assigned = 0x4,
|
||||
IROLF_8 = 0x8,
|
||||
IROLF_Used = 0x10,
|
||||
IROLF_Ind = 0x20,
|
||||
IROLF_Subs = 0x40,
|
||||
IROLF_80 = 0x80,
|
||||
IROLF_LoopInvariant = 0x100,
|
||||
IROLF_BeginLoop = 0x200,
|
||||
IROLF_EndLoop = 0x400,
|
||||
IROLF_Ris = 0x800,
|
||||
IROLF_Immind = 0x1000,
|
||||
IROLF_VecOp = 0x2000,
|
||||
IROLF_4000 = 0x4000,
|
||||
IROLF_8000 = 0x8000,
|
||||
IROLF_VecOpBase = 0x10000,
|
||||
IROLF_20000 = 0x20000,
|
||||
IROLF_CounterLoop = 0x40000,
|
||||
IROLF_BitfieldIndirect = 0x80000,
|
||||
IROLF_CouldError = 0x100000
|
||||
};
|
||||
|
||||
// actual name is LinearNode as per mwccppc v8
|
||||
struct IROLinear {
|
||||
IROLinearType type;
|
||||
ENodeType nodetype;
|
||||
SInt32 flags;
|
||||
UInt16 nodeflags;
|
||||
unsigned short index;
|
||||
Statement *stmt;
|
||||
Type *rtype;
|
||||
IROExpr *expr;
|
||||
struct ERange *x16;
|
||||
PointsToFunction *pointsToFunction;
|
||||
Boolean x1E;
|
||||
union {
|
||||
struct {
|
||||
void *data1;
|
||||
void *data2;
|
||||
void *data3;
|
||||
void *data4;
|
||||
void *data5;
|
||||
} idk;
|
||||
// Operand
|
||||
ENode *node;
|
||||
// Op1Arg
|
||||
IROLinear *monadic;
|
||||
// Op2Arg
|
||||
struct {
|
||||
IROLinear *left;
|
||||
IROLinear *right;
|
||||
} diadic;
|
||||
// Op3Arg
|
||||
struct {
|
||||
IROLinear *a;
|
||||
IROLinear *b;
|
||||
IROLinear *c;
|
||||
} args3;
|
||||
// Funccall
|
||||
struct {
|
||||
char ispascal;
|
||||
short argCount;
|
||||
IROLinear **args;
|
||||
IROLinear *linear8; // funcref
|
||||
TypeFunc *functype;
|
||||
struct LocationSetSet *returnedLocs;
|
||||
} funccall;
|
||||
// Asm
|
||||
Statement *asm_stmt;
|
||||
// If, IfNot, Goto, Label
|
||||
struct {
|
||||
CLabel *label;
|
||||
IROLinear *x4; // if,ifnot only??
|
||||
} label;
|
||||
struct {
|
||||
SwitchInfo *info;
|
||||
IROLinear *x4;
|
||||
} swtch;
|
||||
// BeginCatch, EndCatch, EndCatchDtor
|
||||
struct {
|
||||
IROLinear *linear;
|
||||
int x4;
|
||||
int x8;
|
||||
} ctch;
|
||||
} u;
|
||||
IROLinear *next;
|
||||
};
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern IROLinear *IRO_FirstLinear;
|
||||
extern IROLinear *IRO_LastLinear;
|
||||
extern UInt32 IRO_NumLinear;
|
||||
extern Statement *CurStat;
|
||||
|
||||
extern IROLinear *IRO_NewLinear(IROLinearType type);
|
||||
extern void IRO_PreLinearize(Statement *stmt);
|
||||
extern void IRO_Linearize(Statement *stmt);
|
||||
extern ENode *IRO_NewENode(ENodeType nodetype);
|
||||
extern Statement *IRO_Delinearize(IRONode *node, IROLinear *linear);
|
||||
extern void IRO_RenumberInts(void);
|
||||
extern void IRO_UpdateFlagsOnInts(void);
|
||||
extern void IRO_SaveLinearIR(IROLinearIRSave *save);
|
||||
extern void IRO_RestoreLinearIR(IROLinearIRSave *save);
|
||||
|
||||
#define IS_LINEAR_ENODE(_linear, _nodetype) ( ((_linear)->type == IROLinearOperand) && ((_linear)->u.node->type) == (_nodetype) )
|
||||
#define IS_LINEAR_MONADIC(_linear, _nodetype) ( ((_linear)->type == IROLinearOp1Arg) && ((_linear)->nodetype) == (_nodetype) )
|
||||
#define IS_LINEAR_DIADIC(_linear, _nodetype) ( ((_linear)->type == IROLinearOp2Arg) && ((_linear)->nodetype) == (_nodetype) )
|
||||
#define IS_LINEAR_DIADIC_2(_linear, _nodetype1, _nodetype2) ( ((_linear)->type == IROLinearOp2Arg) && (((_linear)->nodetype) == (_nodetype1) || ((_linear)->nodetype) == (_nodetype2)) )
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,111 @@
|
||||
#ifndef COMPILER_IROLOOP_H
|
||||
#define COMPILER_IROLOOP_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/BitVector.h"
|
||||
|
||||
typedef enum IROLoopIndFlags {
|
||||
LoopInd_1 = 1,
|
||||
LoopInd_2 = 2,
|
||||
LoopInd_4 = 4,
|
||||
LoopInd_8 = 8
|
||||
} IROLoopIndFlags;
|
||||
|
||||
typedef enum IROLoopFlags {
|
||||
LoopFlags_1 = 1,
|
||||
LP_LOOP_HAS_CALLS = 2,
|
||||
LP_LOOP_HAS_CNTRLFLOW = 4,
|
||||
LoopFlags_8 = 8,
|
||||
LP_INDUCTION_NOT_FOUND = 0x10,
|
||||
LP_IFEXPR_NON_CANONICAL = 0x20,
|
||||
LP_HAS_MULTIPLE_INDUCTIONS = 0x40,
|
||||
LP_LOOP_HDR_HAS_SIDEEFFECTS = 0x80,
|
||||
LoopFlags_100 = 0x100,
|
||||
LoopFlags_200 = 0x200,
|
||||
LP_LOOP_STEP_ISPOS = 0x400,
|
||||
LoopFlags_800 = 0x800,
|
||||
LoopFlags_1000 = 0x1000,
|
||||
LoopFlags_2000 = 0x2000,
|
||||
LP_LOOP_STEP_ISNEG = 0x4000,
|
||||
LP_LOOP_HAS_ASM = 0x8000,
|
||||
LoopFlags_10000 = 0x10000,
|
||||
LoopFlags_20000 = 0x20000,
|
||||
LoopFlags_40000 = 0x40000
|
||||
} IROLoopFlags;
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct IROLoopInd {
|
||||
IROLoopIndFlags flags;
|
||||
VarRecord *var;
|
||||
IRONode *fnode;
|
||||
IROLinear *nd;
|
||||
SInt32 addConst;
|
||||
IROLinear *addNode;
|
||||
struct IROLoopInd *next;
|
||||
} IROLoopInd;
|
||||
|
||||
struct IROLoop {
|
||||
SInt32 flags;
|
||||
IRONode *fnode;
|
||||
int x8;
|
||||
int xC;
|
||||
int x10;
|
||||
IROLinear *nd14; // assignment expression that sets the initial value of induction
|
||||
IROLinear *nd18;
|
||||
IROLoopInd *induction;
|
||||
int index20;
|
||||
int index24;
|
||||
CInt64 x28;
|
||||
CInt64 x30;
|
||||
int sizeBySomeMeasurement;
|
||||
};
|
||||
|
||||
typedef enum IROLoopMemRefFlags {
|
||||
LoopMemRef_1 = 1,
|
||||
LoopMemRef_2 = 2,
|
||||
LoopMemRef_4 = 4,
|
||||
LoopMemRef_8 = 8,
|
||||
LoopMemRef_10 = 0x10
|
||||
} IROLoopMemRefFlags;
|
||||
|
||||
typedef struct IROLoopMemRef {
|
||||
IROLoopMemRefFlags flags;
|
||||
IROLinear *nd;
|
||||
IROElmList *list;
|
||||
IROAddrRecord *rec;
|
||||
struct IROLoopMemRef *next;
|
||||
} IROLoopMemRef;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern IRONode *LoopNode;
|
||||
extern Boolean ConditionalHeaderAtBottom;
|
||||
extern IROLoopInd *FirstInd;
|
||||
extern BitVector *InLoop;
|
||||
extern IROList IRO_InitLList;
|
||||
extern BitVector *InLoop_Exits;
|
||||
extern BitVector *InLoop_Tails;
|
||||
extern UInt32 LoopExitNumber;
|
||||
extern UInt32 LoopTailNum;
|
||||
extern IRONode *LoopExitSuccessor;
|
||||
extern IRONode *LoopTail;
|
||||
extern IROLoopMemRef *IRO_LoopMemRefFirst;
|
||||
extern IROLoopMemRef *IRO_LoopMemRefCurrent;
|
||||
|
||||
extern void FindMustReach(void);
|
||||
extern void FindMustReach1(IRONode *checkfnode);
|
||||
extern void AddPreds(IRONode *fnode);
|
||||
extern void IncLoopDepth(void);
|
||||
extern void IRO_SetLoopDepth(void);
|
||||
extern void IRO_FindLoops(void);
|
||||
extern void ComputeLoopKills(void);
|
||||
extern void ComputeLoopInvariance(void);
|
||||
extern void ComputeLoopInduction(void);
|
||||
extern void FindAssignmenttoInductionVar(IROLoop *loop, IRONode *fnode);
|
||||
extern IROLoop *ExtractLoopInfo(IRONode *fnode);
|
||||
extern CLabel *BuildLabel(IROList *list);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,15 @@
|
||||
#ifndef COMPILER_IROMALLOC_H
|
||||
#define COMPILER_IROMALLOC_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
extern size_t IRO_msize(void *buf);
|
||||
extern void *IRO_malloc(size_t size);
|
||||
extern void IRO_free(void *buf);
|
||||
extern void *IRO_realloc(void *buf, size_t newsize);
|
||||
extern void *IRO_calloc(size_t a, size_t b);
|
||||
extern void IRO_pool_free_all(void);
|
||||
extern void IRO_InitializeAllocator(void);
|
||||
extern void IRO_TerminateAllocator(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,25 @@
|
||||
#ifndef COMPILER_IROPOINTERANALYSIS_H
|
||||
#define COMPILER_IROPOINTERANALYSIS_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
extern void PointerAnalysis_Setup(void);
|
||||
extern void PointerAnalysis_Cleanup(void);
|
||||
extern void IRO_AnalyzePointers(Object *function);
|
||||
extern Boolean PointerAnalysis_TwoLinearNodePointerExprsMightAlias(Object *proc, IROLinear *nd1, IROLinear *nd2);
|
||||
extern Boolean PointerAnalysis_TwoENodePointerExprsMightAlias(Object *proc, ENode *nd1, ENode *nd2);
|
||||
extern Boolean PointerAnalysis_IsLinearNodePointerExprDefinite(Object *proc, IROLinear *nd);
|
||||
extern Boolean PointerAnalysis_IsENodePointerExprDefinite(Object *proc, ENode *nd);
|
||||
extern Boolean PointerAnalysis_IsVariableValueDefinite(Object *proc, VarRecord *var, PointsToFunction *pointsTo);
|
||||
extern void PointerAnalysis_LookupLinearNodePointerExpr(Object *proc, IROLinear *indirect, IROListNode **list);
|
||||
extern void PointerAnalysis_LookupENodePointerExpr(Object *proc, ENode *indirect, ENodeList **list);
|
||||
extern void PointerAnalysis_LookupVariableIntoLinearNodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, IROList **list);
|
||||
extern void PointerAnalysis_LookupVariableIntoENodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, ENodeList **list);
|
||||
extern void PointerAnalysis_GetFunctionKills(Object *proc, IROLinear *funccall, ObjectList **list);
|
||||
extern void PointerAnalysis_GetFunctionDependencies(Object *proc, IROLinear *funccall, ObjectList **list);
|
||||
extern void PointerAnalysis_PragmaMode(void);
|
||||
extern void PointerAnalysis_ParseEntryPointsToSpecifier(DeclInfo *di);
|
||||
extern void PointerAnalysis_ParseExitPointsToSpecifier(DeclInfo *di);
|
||||
extern void PointerAnalysis_ParseFunctionModifiesSpecifier(DeclInfo *di);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,35 @@
|
||||
#ifndef COMPILER_IROPROPAGATE_H
|
||||
#define COMPILER_IROPROPAGATE_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/BitVector.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
struct IROAssign {
|
||||
IROLinear *linear;
|
||||
UInt16 index;
|
||||
UInt16 varIndex;
|
||||
IROLinear *linear2;
|
||||
BitVector *depends;
|
||||
Object *varObj;
|
||||
VarRecord *var;
|
||||
IROAssign *next;
|
||||
IROAssign *prev;
|
||||
UInt16 x20;
|
||||
IRONode *node;
|
||||
};
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern IROAssign *IRO_FirstAssign;
|
||||
extern IROAssign *IRO_LastAssign;
|
||||
extern SInt32 IRO_NumAssign;
|
||||
|
||||
extern int IRO_IsRegable(Object *obj);
|
||||
extern Boolean IRO_CopyAndConstantPropagation(void);
|
||||
extern void IRO_ExpressionPropagation(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef COMPILER_IRORANGEPROPAGATION_H
|
||||
#define COMPILER_IRORANGEPROPAGATION_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
extern Boolean IRO_RangePropagateInFNode(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,10 @@
|
||||
#ifndef COMPILER_IROSUBABLE_H
|
||||
#define COMPILER_IROSUBABLE_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
extern void IRO_InitializeIsSubableOpArray(void);
|
||||
extern Boolean IRO_IsSubableExpression(IROLinear *nd);
|
||||
extern Boolean IRO_IsVectorTempCandidate(IROLinear *nd);
|
||||
|
||||
#endif
|
||||
|
9
includes/compiler/IroTransform.h
Normal file
9
includes/compiler/IroTransform.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef COMPILER_IROTRANSFORM_H
|
||||
#define COMPILER_IROTRANSFORM_H
|
||||
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
// TODO
|
||||
extern Boolean IRO_TransformSelfAssignmentToAssignment(IROLinear *linear);
|
||||
|
||||
#endif
|
@ -1,6 +1,22 @@
|
||||
#ifndef COMPILER_IROUNROLLLOOP_H
|
||||
#define COMPILER_IROUNROLLLOOP_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
|
||||
extern void IRO_LoopUnroller(void);
|
||||
extern void IRO_IterateForLoopBody();
|
||||
extern void IRO_LinearizeForLoopPostLoop();
|
||||
extern void BuildEarlyLoopExitTest();
|
||||
extern void BuildLoopExitTest();
|
||||
extern void IsIterationCountConstant();
|
||||
extern void NoOpBlock();
|
||||
extern void IRO_TestConstantIterationCount();
|
||||
extern void BuildOrigIterationCount();
|
||||
extern void BuildNewFinalvalue();
|
||||
extern void BuildUnrolledBodyEntryTest();
|
||||
extern void ChangeInductionReference();
|
||||
extern void UpdateInductionIncrement();
|
||||
extern void GenInitialAssignment();
|
||||
extern void GenNewInduction();
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,112 @@
|
||||
#ifndef COMPILER_IROUTIL_H
|
||||
#define COMPILER_IROUTIL_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/CParser.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
struct IROList {
|
||||
IROLinear *head;
|
||||
IROLinear *tail;
|
||||
};
|
||||
|
||||
struct IROListNode {
|
||||
IROList list;
|
||||
IROListNode *nextList;
|
||||
};
|
||||
|
||||
struct IROElmList {
|
||||
void *element;
|
||||
IROElmList *next;
|
||||
};
|
||||
|
||||
struct IROAddrRecord {
|
||||
IROLinear *linear;
|
||||
unsigned short numObjRefs;
|
||||
IROElmList *objRefs;
|
||||
unsigned short numMisc;
|
||||
IROElmList *misc;
|
||||
unsigned short numInts;
|
||||
IROElmList *ints;
|
||||
int x16;
|
||||
};
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern Object *FunctionName;
|
||||
extern Boolean IRO_IsLeafFunction;
|
||||
extern Boolean IRO_FunctionHasReturn;
|
||||
extern Boolean DisableDueToAsm;
|
||||
extern Boolean LoopOptimizerRun;
|
||||
|
||||
extern Object *IRO_IsVariable(IROLinear *linear);
|
||||
extern Boolean IRO_IsConstant(IROLinear *linear);
|
||||
extern Boolean IRO_IsPow2(IROLinear *linear, SInt32 *powvalue);
|
||||
extern Boolean IRO_IsIntConstant(IROLinear *linear);
|
||||
extern Boolean IRO_IsFloatConstant(IROLinear *linear);
|
||||
extern Boolean IRO_IsVector128Constant(IROLinear *linear);
|
||||
extern Boolean IRO_IsAssignment(IROLinear *linear);
|
||||
extern Boolean IRO_TypesEqual(Type *a, Type *b);
|
||||
extern Type *IRO_UnsignedType(Type *type);
|
||||
extern Type *IRO_SignedType(Type *type);
|
||||
extern Boolean IRO_is_CPtypeequal(Type *a, Type *b);
|
||||
extern Boolean IRO_ExprsSame(IROLinear *a, IROLinear *b);
|
||||
extern CLabel *IRO_NewLabel(void);
|
||||
extern Boolean IRO_ExprsSameSemantically(IROLinear *a, IROLinear *b);
|
||||
extern IROLinear *IRO_FindPrecedAfter(IROLinear *a, IROLinear *iter);
|
||||
extern IROLinear *IRO_FindPreced(IROLinear *a);
|
||||
extern IROLinear *IRO_FindFirst(IROLinear *linear);
|
||||
extern void IRO_CutAndPasteAfter(IROLinear *a, IROLinear *b, IROLinear *c);
|
||||
extern Boolean IRO_IsConstantZero(IROLinear *linear);
|
||||
extern Boolean IRO_IsConstantOne(IROLinear *linear);
|
||||
extern Boolean IRO_IsConstantNegativeOne(IROLinear *linear);
|
||||
extern void IRO_NopOut(IROLinear *linear);
|
||||
extern void IRO_NopNonSideEffects(IROLinear *linear, SInt32 level);
|
||||
extern void IRO_BuildList(IROLinear *linear, Boolean isEntry);
|
||||
typedef void (*IROWalkTreeFunc)(IROLinear *linear, Boolean isEntry);
|
||||
extern void IRO_WalkTree(IROLinear *linear, IROWalkTreeFunc func);
|
||||
extern void IRO_WalkTreeToPropagateFlags(IROLinear *linear, IROWalkTreeFunc func);
|
||||
extern void IRO_WalkInts(IROLinear *a, IROLinear *b, IROWalkTreeFunc func);
|
||||
extern void IRO_Cut(IROLinear *a, IROLinear *b);
|
||||
extern void IRO_Paste(IROLinear *a, IROLinear *b, IROLinear *c);
|
||||
extern void IRO_PasteAfter(IROLinear *a, IROLinear *b, IROLinear *c);
|
||||
extern void IRO_ClipExpr(IROExpr *expr);
|
||||
extern void IRO_ClipExprTree(IROLinear *linear);
|
||||
extern void IRO_MoveExpression(IROExpr *expr, IROLinear *linear);
|
||||
extern void IRO_InitList(IROList *list);
|
||||
extern void IRO_AddToList(IROLinear *linear, IROList *list);
|
||||
extern IROLinear *IRO_FindLabelNode(CLabel *label, IROLinear *linear);
|
||||
extern void IRO_DuplicateExprRange(IROLinear *start, IROLinear *end, IROList *list);
|
||||
extern IROLinear *IRO_DuplicateExpr(IROLinear *linear, IROList *list);
|
||||
extern IROLinear *IRO_TempReference(Object *obj, IROList *list);
|
||||
extern IROLinear *IRO_LocateFather(IROLinear *linear);
|
||||
extern IROLinear *IRO_LocateFather_Cut_And_Paste(IROLinear *a, IROLinear *b);
|
||||
extern IROLinear *IRO_LocateFather_Cut_And_Paste_Without_Nopping(IROLinear *a, IROLinear *b);
|
||||
extern void IRO_ReplaceReference(IROLinear *a, Object *obj, IROLinear *b);
|
||||
extern void IRO_ReplaceReferenceWithNode(IROLinear *a, IROLinear *b);
|
||||
extern void IRO_GetTemp(IROExpr *expr);
|
||||
extern IROLinear *IRO_AssignToTemp(IROExpr *expr);
|
||||
extern IROLinear *IRO_FindStart(IROLinear *linear);
|
||||
extern void IRO_DeleteCommaNode(IROLinear *linear, IROExpr *expr);
|
||||
extern void IRO_RemoveCommaNodeFromIR(void);
|
||||
extern IROAddrRecord *IRO_InitAddrRecordPointer(IROLinear *linear);
|
||||
extern IROLinear *IRO_HasSideEffect(IROLinear *linear);
|
||||
extern IROLinear *IRO_CheckSideEffect(IROLinear *linear);
|
||||
typedef void (*WalkObjFunc)(Object *obj);
|
||||
extern void IRO_WalkExcActions(ExceptionAction *action, WalkObjFunc func);
|
||||
extern Boolean IRO_FunctionCallMightThrowException(IROLinear *linear);
|
||||
extern IROLinear *IRO_NewIntConst(CInt64 val, Type *type);
|
||||
extern IROLinear *IRO_NewFloatConst(Float val, Type *type);
|
||||
extern Boolean IRO_IsAddressMultiply(IROLinear *linear);
|
||||
extern void IRO_SetupForUserBreakChecking(void);
|
||||
extern void IRO_CheckForUserBreak(void);
|
||||
|
||||
// TODO is this elsewhere?
|
||||
inline Boolean IRO_IsUnsignedType(Type *type) {
|
||||
return is_unsigned(type);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,51 @@
|
||||
#ifndef COMPILER_IROVARS_H
|
||||
#define COMPILER_IROVARS_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/IrOptimizer.h"
|
||||
#include "compiler/enode.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
struct VarRecord {
|
||||
UInt16 index;
|
||||
Object *object;
|
||||
int x6;
|
||||
Boolean xA;
|
||||
Boolean xB;
|
||||
Boolean xC;
|
||||
VarRecord *next;
|
||||
IRODef *defs;
|
||||
IROUse *uses;
|
||||
Type *x1A; // bitfield-related
|
||||
IROLinear *x1E;
|
||||
};
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern VarRecord *IRO_FirstVar;
|
||||
extern VarRecord *IRO_LastVar;
|
||||
extern SInt32 IRO_NumVars;
|
||||
extern Boolean IRO_IsBitField;
|
||||
extern SInt32 IRO_BaseTerms;
|
||||
extern SInt32 IRO_VarTerms;
|
||||
extern Boolean IRO_IsModifyOp[MAXEXPR];
|
||||
extern Boolean IRO_IsAssignOp[MAXEXPR];
|
||||
|
||||
extern void IRO_InitializeIRO_IsModifyOpArray(void);
|
||||
extern void IRO_InitializeIRO_IsAssignOpArray(void);
|
||||
extern VarRecord *IRO_FindVar(Object *object, Boolean flag1, Boolean flag2);
|
||||
extern void IRO_FindAllVars(void);
|
||||
extern void IRO_ZapVarPtrs(void);
|
||||
extern void IRO_UpdateVars(void);
|
||||
extern void IRO_AddElmToList(IROLinear *linear, IROElmList **list);
|
||||
extern void IRO_DecomposeAddressExpression(IROLinear *linear, IROAddrRecord *rec);
|
||||
extern void IRO_DecomposeAddressExpression_Cheap(IROLinear *linear);
|
||||
extern VarRecord *IRO_FindAssigned(IROLinear *linear);
|
||||
extern void IRO_GetKills(IROLinear *linear);
|
||||
extern void IRO_CheckInit(void);
|
||||
extern void IRO_RewriteBitFieldTemps(void);
|
||||
extern void IRO_ScalarizeClassDataMembers(void);
|
||||
|
||||
#endif
|
||||
|
18
includes/compiler/LiveInfo.h
Normal file
18
includes/compiler/LiveInfo.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef COMPILER_LIVEINFO_H
|
||||
#define COMPILER_LIVEINFO_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
typedef struct LiveInfo {
|
||||
UInt32 *vec0; // use
|
||||
UInt32 *vec4; // def
|
||||
UInt32 *vec8; // in
|
||||
UInt32 *vecC; // out
|
||||
} LiveInfo;
|
||||
|
||||
extern LiveInfo *liveinfo;
|
||||
|
||||
extern void computelivevariables(Object *proc);
|
||||
extern int dead(PCode *instr, char rclass, UInt32 *vec);
|
||||
|
||||
#endif
|
@ -3,4 +3,8 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern int deletedloads;
|
||||
|
||||
extern void deletedeadloads(Object *proc);
|
||||
|
||||
#endif
|
||||
|
@ -2,5 +2,97 @@
|
||||
#define COMPILER_LOOPDETECTION_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/BitVector.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct BlockList {
|
||||
struct BlockList *next;
|
||||
PCodeBlock *block;
|
||||
} BlockList;
|
||||
|
||||
typedef struct InstrList {
|
||||
struct InstrList *next;
|
||||
PCode *instr;
|
||||
} InstrList;
|
||||
|
||||
typedef enum LoopBound {
|
||||
LOOP_BOUND_INDETERMINATE,
|
||||
LOOP_BOUND_CONSTANT,
|
||||
LOOP_BOUND_VARIABLE
|
||||
} LoopBound;
|
||||
|
||||
typedef struct Loop {
|
||||
struct Loop *parent;
|
||||
struct Loop *nextSibling;
|
||||
struct Loop *children;
|
||||
PCodeBlock *body; // repeated block
|
||||
PCodeBlock *preheader; // block at the start of the loop
|
||||
PCodeBlock *footer; // block at the end of the loop
|
||||
PCode *pc18;
|
||||
BlockList *blocks;
|
||||
UInt32 *memberblocks;
|
||||
UInt32 *vec24;
|
||||
UInt32 *vec28;
|
||||
UInt32 *vec2C;
|
||||
struct BasicInductionVar *basicInductionVars;
|
||||
int loopWeight;
|
||||
int bodySize; // amount of instructions in the body
|
||||
SInt32 iterationCount;
|
||||
SInt32 lower;
|
||||
SInt32 upper;
|
||||
SInt32 step; // value added in each iteration
|
||||
unsigned char unknownCondition;
|
||||
Boolean x4D;
|
||||
Boolean x4E;
|
||||
Boolean x4F;
|
||||
Boolean isUnknownCountingLoop; // is a counting loop with non-constant iteration count
|
||||
Boolean isKnownCountingLoop;
|
||||
Boolean x52;
|
||||
Boolean x53;
|
||||
Boolean x54;
|
||||
LoopBound lowerType;
|
||||
LoopBound upperType;
|
||||
Boolean x57;
|
||||
} Loop;
|
||||
|
||||
typedef struct BasicInductionVar {
|
||||
struct BasicInductionVar *next;
|
||||
Loop *loop;
|
||||
struct InductionVar *inductionVars;
|
||||
InstrList *instrsC;
|
||||
PCode *initializer;
|
||||
SInt32 step;
|
||||
short reg;
|
||||
} BasicInductionVar;
|
||||
|
||||
typedef struct InductionVar {
|
||||
struct InductionVar *next;
|
||||
BasicInductionVar *basicVar;
|
||||
PCode *instr;
|
||||
PCode *instrC;
|
||||
Loop *someloop;
|
||||
SInt32 step;
|
||||
short x18; // arg index within instr
|
||||
short x1A; // arg index within instr
|
||||
short x1C; // reg
|
||||
short x1E; // reg
|
||||
} InductionVar;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern Loop *loopsinflowgraph;
|
||||
extern int loopdetection_nblocks;
|
||||
extern BitVector *LoopTemp;
|
||||
extern void *LoopList_First;
|
||||
|
||||
extern void addblocktoloop(Loop *loop, PCodeBlock *block);
|
||||
extern void insertpreheaderblock(Loop *loop);
|
||||
extern void findloopsinflowgraph(void);
|
||||
extern void analyzeForCountableLoops(Loop *loop);
|
||||
extern void analyzeloop(Loop *loop);
|
||||
extern void analyzeloopsinflowgraph(void);
|
||||
|
||||
#endif
|
||||
|
@ -3,4 +3,12 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern int optimizedloops;
|
||||
extern int optimizedloop_full_unroll;
|
||||
extern int optimizedloop_trans_regs;
|
||||
|
||||
extern void pccomputepredecessors1(PCodeBlock *block);
|
||||
extern void changearraytoregisters(void);
|
||||
extern void optimizeloops(void);
|
||||
|
||||
#endif
|
||||
|
@ -3,4 +3,7 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
// more stuff goes here
|
||||
extern void ObjGen_DeclareSwitchTable(Object *a, Object *b);
|
||||
|
||||
#endif
|
||||
|
@ -16,7 +16,10 @@
|
||||
|
||||
enum {
|
||||
EffectRead = 1,
|
||||
EffectWrite = 2
|
||||
EffectWrite = 2,
|
||||
Effect4 = 4,
|
||||
Effect8 = 8,
|
||||
Effect40 = 0x40 // spilled register?
|
||||
};
|
||||
|
||||
/*typedef enum {
|
||||
@ -48,7 +51,7 @@ typedef enum {
|
||||
|
||||
struct PCodeArg {
|
||||
PCOpKind kind;
|
||||
char arg;
|
||||
unsigned char arg;
|
||||
union {
|
||||
struct {
|
||||
unsigned short effect;
|
||||
@ -74,14 +77,46 @@ struct PCodeArg {
|
||||
} data;
|
||||
};
|
||||
|
||||
#define PC_OP_IS_REGISTER(_op, _rclass, _reg) \
|
||||
((_op)->kind == PCOp_REGISTER && \
|
||||
(char) (_op)->arg == (_rclass) && \
|
||||
(_op)->data.reg.reg == (_reg))
|
||||
|
||||
#define PC_OP_IS_READ_REGISTER(_op, _rclass, _reg) \
|
||||
((_op)->kind == PCOp_REGISTER && \
|
||||
(char) (_op)->arg == (_rclass) && \
|
||||
(_op)->data.reg.reg == (_reg) && \
|
||||
((_op)->data.reg.effect & EffectRead))
|
||||
|
||||
#define PC_OP_IS_WRITE_REGISTER(_op, _rclass, _reg) \
|
||||
((_op)->kind == PCOp_REGISTER && \
|
||||
(char) (_op)->arg == (_rclass) && \
|
||||
(_op)->data.reg.reg == (_reg) && \
|
||||
((_op)->data.reg.effect & EffectWrite))
|
||||
|
||||
#define PC_OP_IS_ANY_REGISTER(_op, _rclass) \
|
||||
((_op)->kind == PCOp_REGISTER && \
|
||||
(char) (_op)->arg == (_rclass))
|
||||
|
||||
#define PC_OP_IS_READ_ANY_REGISTER(_op, _rclass) \
|
||||
((_op)->kind == PCOp_REGISTER && \
|
||||
(char) (_op)->arg == (_rclass) && \
|
||||
((_op)->data.reg.effect & EffectRead))
|
||||
|
||||
#define PC_OP_IS_WRITE_ANY_REGISTER(_op, _rclass) \
|
||||
((_op)->kind == PCOp_REGISTER && \
|
||||
(char) (_op)->arg == (_rclass) && \
|
||||
((_op)->data.reg.effect & EffectWrite))
|
||||
|
||||
|
||||
struct PCode {
|
||||
PCode *nextPCode;
|
||||
PCode *prevPCode;
|
||||
PCodeBlock *block;
|
||||
unsigned int xx_C;
|
||||
unsigned int _10;
|
||||
int flags;
|
||||
void *_18;
|
||||
int useID;
|
||||
int defID;
|
||||
UInt32 flags;
|
||||
struct Alias *alias;
|
||||
SInt32 sourceoffset;
|
||||
short op;
|
||||
short argCount;
|
||||
@ -92,7 +127,7 @@ struct PCodeLabel {
|
||||
PCodeLabel *nextLabel;
|
||||
PCodeBlock *block;
|
||||
short resolved;
|
||||
short index;
|
||||
unsigned short index;
|
||||
};
|
||||
|
||||
typedef struct _PCLink {
|
||||
@ -118,8 +153,8 @@ struct PCodeBlock {
|
||||
/* PCode Flags */
|
||||
enum {
|
||||
fPCodeFlag1 = 1,
|
||||
fPCodeFlag2 = 2,
|
||||
fPCodeFlag4 = 4,
|
||||
fPCodeFlag2 = 2, // some kinda load
|
||||
fPCodeFlag4 = 4, // some kinda store
|
||||
fPCodeFlag8 = 8,
|
||||
fPCodeFlag10 = 0x10,
|
||||
fPCodeFlag20 = 0x20,
|
||||
@ -134,8 +169,8 @@ enum {
|
||||
fCommutative = 0x2000,
|
||||
fIsCSE = 0x4000,
|
||||
fPCodeFlag8000 = 0x8000,
|
||||
fPCodeFlag20000 = 0x20000, // ?
|
||||
fPCodeFlag40000 = 0x40000, // ?
|
||||
fPCodeFlag20000 = 0x20000, // some kinda load?
|
||||
fPCodeFlag40000 = 0x40000, // some kinda store?
|
||||
// Set 1 only
|
||||
fLink = 0x1000000,
|
||||
fBranchNotTaken = 0x4000000,
|
||||
@ -150,7 +185,7 @@ enum {
|
||||
fPCodeFlag4000000 = 0x4000000,
|
||||
fPCodeFlag8000000 = 0x8000000,
|
||||
fPCodeFlag10000000 = 0x10000000,
|
||||
fPCodeFlag20000000 = 0x20000000,
|
||||
fPCodeFlag20000000 = 0x20000000, // record bit?
|
||||
fPCodeFlag40000000 = 0x40000000,
|
||||
fPCodeFlag80000000 = 0x80000000
|
||||
};
|
||||
@ -159,9 +194,10 @@ enum {
|
||||
fPCBlockFlag1 = 1, // prologue
|
||||
fPCBlockFlag2 = 2, // epilogue
|
||||
fPCBlockFlag4 = 4,
|
||||
fPCBlockFlag8 = 8,
|
||||
fPCBlockFlag8 = 8, // scheduled?
|
||||
fPCBlockFlag10 = 0x10,
|
||||
fPCBlockFlag20 = 0x20,
|
||||
fPCBlockFlag2000 = 0x2000,
|
||||
fPCBlockFlag4000 = 0x4000
|
||||
};
|
||||
|
||||
|
@ -3,4 +3,8 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern UInt32 assemblepcode(PCode *instr, UInt32 offset, PCodeArg *dummyArg);
|
||||
extern void optimizefinalbranches();
|
||||
extern void assemblefunction();
|
||||
|
||||
#endif
|
||||
|
@ -17,6 +17,10 @@ typedef enum {
|
||||
PCOp_PLACEHOLDEROPERAND
|
||||
} PCOpKind;
|
||||
|
||||
typedef enum {
|
||||
PCOpMemory1 = 1
|
||||
} PCOpMemoryArg;
|
||||
|
||||
typedef struct _OpcodeInfo {
|
||||
const char *name;
|
||||
const char *format;
|
||||
|
@ -3,4 +3,36 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern int pclist_bad_operand;
|
||||
|
||||
extern void pcinitlisting(void);
|
||||
extern void pccleanuplisting(void);
|
||||
extern void pclistblocks(char *name1, char *name2);
|
||||
extern void pclistdataflow(void);
|
||||
extern void pclistinterferences(char *class_format, int regcount);
|
||||
extern void pclistspill(void);
|
||||
extern void pclistcopypropitem(void);
|
||||
extern void pclistcoalesce(void);
|
||||
extern void pclistusedefs(void);
|
||||
extern void pclistpropinfo(void);
|
||||
extern void pclistloops(void);
|
||||
extern void pclistswitchtables(void);
|
||||
extern void pclistdominators(void);
|
||||
extern void pclistbackedge(void);
|
||||
extern void pclistinterferencegraphnode(void);
|
||||
extern void pclistinterferencegraph(void);
|
||||
extern void pclistblock_scheduler(void);
|
||||
extern void pclistblocks_start_scheduler(char *str1, char *str2);
|
||||
extern void pclistblocks_end_scheduler(void);
|
||||
extern void pctotalheap(void);
|
||||
extern void pctotalmemory(void);
|
||||
extern void pcmessage(char *probably_a_string, ...);
|
||||
extern int formatalias(Alias *alias, char *buf, int bufSize);
|
||||
extern int dumpalias(Alias *alias, int len, Boolean flag1, Boolean flag2);
|
||||
extern void pcformatset(void);
|
||||
extern int GetLineEndOffset(char *str, int lineNum, int len);
|
||||
extern int GetLineOffset(char *str, int lineNum, int len);
|
||||
extern void DumpSourceCode(void);
|
||||
extern int DumpIR_SrcBreak(void);
|
||||
|
||||
#endif
|
||||
|
@ -4,16 +4,29 @@
|
||||
#include "compiler/common.h"
|
||||
|
||||
enum {
|
||||
Register0 = 0,
|
||||
Register2 = 2,
|
||||
RegisterMax = 32
|
||||
};
|
||||
const char RegClass_SPR = 0;
|
||||
/*const char RegClass_SPR = 0;
|
||||
const char RegClass_CRFIELD = 1;
|
||||
const char RegClass_VR = 2;
|
||||
const char RegClass_FPR = 3;
|
||||
const char RegClass_GPR = 4;
|
||||
const char RegClassMax = 5;
|
||||
const char RegClass_6 = 6;
|
||||
const char RegClass_DCR = 7;
|
||||
const char RegClass_DCR = 7;*/
|
||||
typedef enum RegClass {
|
||||
RegClass_Invalid = -1,
|
||||
RegClass_SPR = 0,
|
||||
RegClass_CRFIELD = 1,
|
||||
RegClass_VR = 2,
|
||||
RegClass_FPR = 3,
|
||||
RegClass_GPR = 4,
|
||||
RegClassMax = 5,
|
||||
RegClass_6 = 6,
|
||||
RegClass_DCR = 7
|
||||
} RegClass;
|
||||
|
||||
enum {
|
||||
RegState0 = 0,
|
||||
|
@ -3,4 +3,46 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
typedef int (*LatencyFunc)(PCode *instr);
|
||||
typedef void (*InitializeFunc)(void);
|
||||
typedef int (*CanIssueFunc)(PCode *instr);
|
||||
typedef void (*IssueFunc)(PCode *instr);
|
||||
typedef void (*AdvanceClockFunc)(void);
|
||||
typedef int (*SerializesFunc)(PCode *instr);
|
||||
typedef int (*UsesVPermuteUnitFunc)(PCode *instr);
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct MachineInfo {
|
||||
int x0;
|
||||
int x4;
|
||||
int x8;
|
||||
LatencyFunc latency;
|
||||
InitializeFunc initialize;
|
||||
CanIssueFunc can_issue;
|
||||
IssueFunc issue;
|
||||
AdvanceClockFunc advance_clock;
|
||||
SerializesFunc serializes;
|
||||
UsesVPermuteUnitFunc uses_vpermute_unit;
|
||||
} MachineInfo;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern MachineInfo machine601;
|
||||
extern MachineInfo machine603;
|
||||
extern MachineInfo machine603e;
|
||||
extern MachineInfo machine604;
|
||||
extern MachineInfo machine7400;
|
||||
extern MachineInfo machine7450;
|
||||
extern MachineInfo machine750;
|
||||
extern MachineInfo machine821;
|
||||
|
||||
extern int is_same_operand(PCodeArg *a, PCodeArg *b);
|
||||
extern void scheduleinstructions(Boolean flag);
|
||||
extern int is_dependent(PCode *a, PCode *b, char rclass);
|
||||
extern int uses_vpermute_unit(PCode *instr);
|
||||
extern int default_uses_vpermute_unit(PCode *instr);
|
||||
|
||||
#endif
|
||||
|
@ -3,4 +3,7 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern void estimatespillcosts(void);
|
||||
extern void insertspillcode(void);
|
||||
|
||||
#endif
|
||||
|
@ -3,4 +3,8 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern int strengthreducedloops;
|
||||
|
||||
extern void strengthreduceloops(void);
|
||||
|
||||
#endif
|
||||
|
@ -2,5 +2,65 @@
|
||||
#define COMPILER_USEDEFCHAINS_H
|
||||
|
||||
#include "compiler/common.h"
|
||||
#include "compiler/Registers.h"
|
||||
#include "compiler/PCodeInfo.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
typedef struct TinyValue {
|
||||
PCOpKind kind;
|
||||
unsigned char arg;
|
||||
union {
|
||||
short reg;
|
||||
Object *object;
|
||||
} u;
|
||||
} TinyValue;
|
||||
|
||||
typedef struct UseDefInfo {
|
||||
UInt32 *defvec0;
|
||||
UInt32 *defvec4;
|
||||
UInt32 *defvec8;
|
||||
UInt32 *defvecC;
|
||||
UInt32 *usevec10;
|
||||
UInt32 *usevec14;
|
||||
UInt32 *usevec18;
|
||||
UInt32 *usevec1C;
|
||||
} UseDefInfo;
|
||||
|
||||
typedef struct UseOrDef {
|
||||
PCode *pcode;
|
||||
TinyValue v;
|
||||
} UseOrDef;
|
||||
|
||||
typedef struct RegUseOrDef {
|
||||
struct RegUseOrDef *next;
|
||||
int id;
|
||||
} RegUseOrDef;
|
||||
|
||||
typedef struct ObjectUseDef {
|
||||
struct ObjectUseDef *next;
|
||||
struct ObjectUseDef *leftchild;
|
||||
struct ObjectUseDef *rightchild;
|
||||
Object *object;
|
||||
RegUseOrDef *uses;
|
||||
RegUseOrDef *defs;
|
||||
} ObjectUseDef;
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern int number_of_Defs;
|
||||
extern UseOrDef *Defs;
|
||||
extern RegUseOrDef **reg_Defs[RegClassMax];
|
||||
extern int number_of_Uses;
|
||||
extern UseOrDef *Uses;
|
||||
extern RegUseOrDef **reg_Uses[RegClassMax];
|
||||
extern UseDefInfo *usedefinfo;
|
||||
extern ObjectUseDef *objectusedefs;
|
||||
extern ObjectUseDef *objectusedeflist;
|
||||
|
||||
extern ObjectUseDef *findobjectusedef(Object *object);
|
||||
extern void computeusedefchains(int flag);
|
||||
|
||||
#endif
|
||||
|
@ -3,4 +3,17 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
extern int removedcommonsubexpressions;
|
||||
extern int nextvaluenumber;
|
||||
|
||||
extern void killmemory(Alias *alias, PCode *newValue);
|
||||
extern void removecommonsubexpressions(Object *proc, int flag);
|
||||
|
||||
#endif
|
||||
|
@ -3,4 +3,6 @@
|
||||
|
||||
#include "compiler/common.h"
|
||||
|
||||
extern int vectorarraystoregs(void);
|
||||
|
||||
#endif
|
||||
|
@ -112,6 +112,7 @@ typedef enum Section {
|
||||
N_SECTIONS = 45
|
||||
} Section;
|
||||
|
||||
typedef struct Alias Alias;
|
||||
typedef struct BClassList BClassList;
|
||||
typedef struct CI_FuncData CI_FuncData;
|
||||
typedef struct CLabel CLabel;
|
||||
|
@ -279,14 +279,67 @@ enum {
|
||||
};
|
||||
|
||||
#define ENODE_IS(_enode, _etype) ( (_enode)->type == (_etype) )
|
||||
#define ENODE_IS2(_enode, _etype1, _etype2) ( ENODE_IS((_enode), (_etype1)) || ENODE_IS(_enode, (_etype2)) )
|
||||
#define ENODE_IS3(_enode, _etype1, _etype2, _etype3) ( ENODE_IS((_enode), (_etype1)) || ENODE_IS(_enode, (_etype2)) || ENODE_IS(_enode, (_etype3)) )
|
||||
#define ENODE_IS2(_enode, _etype1, _etype2) ( ENODE_IS((_enode), (_etype1)) || ENODE_IS((_enode), (_etype2)) )
|
||||
#define ENODE_IS3(_enode, _etype1, _etype2, _etype3) ( ENODE_IS((_enode), (_etype1)) || ENODE_IS((_enode), (_etype2)) || ENODE_IS((_enode), (_etype3)) )
|
||||
#define ENODE_IS4(_enode, _etype1, _etype2, _etype3, _etype4) ( ENODE_IS((_enode), (_etype1)) || ENODE_IS((_enode), (_etype2)) || ENODE_IS((_enode), (_etype3)) || ENODE_IS((_enode), (_etype4)) )
|
||||
#define ENODE_IS_RANGE(_enode, _lo, _hi) ( ((_enode)->type >= (_lo)) && ((_enode)->type <= (_hi)) )
|
||||
#define ENODE_QUALS(_enode) ( (UInt32) ( (_enode)->flags & ENODE_FLAG_QUALS ) )
|
||||
#define ENODE_IS_INDIRECT_TO(_enode, _etype) ( ENODE_IS((_enode), EINDIRECT) && ENODE_IS((_enode)->data.monadic, (_etype)) )
|
||||
#define ENODE_IS_ASSIGN(_enode) ( ENODE_IS_RANGE((_enode), EASS, EORASS) )
|
||||
#define ENODE_IS_ASSIGN_TO(_enode, _etype) ( ENODE_IS_RANGE((_enode), EASS, EORASS) && ENODE_IS((_enode)->data.diadic.left->data.monadic, (_etype)) )
|
||||
|
||||
// 0 to 8, 0x30 to 0x31
|
||||
#define ENODE_CASE_MONADIC \
|
||||
case EPOSTINC: \
|
||||
case EPOSTDEC: \
|
||||
case EPREINC: \
|
||||
case EPREDEC: \
|
||||
case EINDIRECT: \
|
||||
case EMONMIN: \
|
||||
case EBINNOT: \
|
||||
case ELOGNOT: \
|
||||
case EFORCELOAD: \
|
||||
case ETYPCON: \
|
||||
case EBITFIELD:
|
||||
|
||||
// 9 to 0x1B
|
||||
#define ENODE_CASE_DIADIC_1 \
|
||||
case EMUL: \
|
||||
case EMULV: \
|
||||
case EDIV: \
|
||||
case EMODULO: \
|
||||
case EADDV: \
|
||||
case ESUBV: \
|
||||
case EADD: \
|
||||
case ESUB: \
|
||||
case ESHL: \
|
||||
case ESHR: \
|
||||
case ELESS: \
|
||||
case EGREATER: \
|
||||
case ELESSEQU: \
|
||||
case EGREATEREQU: \
|
||||
case EEQU: \
|
||||
case ENOTEQU: \
|
||||
case EAND: \
|
||||
case EXOR: \
|
||||
case EOR:
|
||||
|
||||
// 0x1E to 0x28, 0x2D, 0x2F
|
||||
#define ENODE_CASE_ASSIGN \
|
||||
case EASS: \
|
||||
case EMULASS: \
|
||||
case EDIVASS: \
|
||||
case EMODASS: \
|
||||
case EADDASS: \
|
||||
case ESUBASS: \
|
||||
case ESHLASS: \
|
||||
case ESHRASS: \
|
||||
case EANDASS: \
|
||||
case EXORASS: \
|
||||
case EORASS: \
|
||||
case EBCLR: \
|
||||
case EBSET:
|
||||
|
||||
#ifdef __MWERKS__
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user