blob: 0444bcf31b45a3f589fa7a073837846009eb42dc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Vyacheslav P. Shakin
*/
#include <fstream>
#include "Stl.h"
#include "Log.h"
#include "Ia32IRManager.h"
#include "Ia32Printer.h"
namespace Jitrino
{
namespace Ia32
{
//========================================================================================
// class EarlyPropagation
//========================================================================================
/**
* class EarlyPropagation implements a simple algorithm of constant and copy propagation.
* It works only with operands which have single definitions.
* In addition to constants it also propagates heap reads.
*
* The main goal of the pass is to reduce register pressure.
*
*/
class EarlyPropagation : public SessionAction {
struct OpndInfo
{
U_32 defCount;
Inst * sourceInst;
U_32 sourceOpndId;
U_32 sourceOpndDefCountAtCopy;
OpndInfo()
:defCount(0), sourceInst(NULL), sourceOpndId(EmptyUint32), sourceOpndDefCountAtCopy(0){}
};
void runImpl();
U_32 getNeedInfo()const{ return 0; }
};
static ActionFactory<EarlyPropagation> _early_prop("early_prop");
static bool isTypeConversionAllowed(Opnd* fromOpnd, Opnd* toOpnd) {
Type * fromType = fromOpnd->getType();
Type * toType = toOpnd->getType();
bool fromIsGCType = fromType->isObject() || fromType->isManagedPtr();
bool toIsGCType = toType->isObject() || toType->isManagedPtr();
return fromIsGCType == toIsGCType;
}
//___________________________________________________________________________________________________
void EarlyPropagation::runImpl()
{
irManager->updateLoopInfo();
U_32 opndCount=irManager->getOpndCount();
MemoryManager mm("early_prop");
OpndInfo * opndInfos = new(mm) OpndInfo[opndCount];
Node * currentLoopHeader = NULL;
bool anyInstHandled=false;
LoopTree* lt = irManager->getFlowGraph()->getLoopTree();
const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder();
for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) {
Node * node=*it;
if (!node->isBlockNode()) {
continue;
}
Node * loopHeader = lt->getLoopHeader(node, false);
if (currentLoopHeader != loopHeader){
currentLoopHeader = loopHeader;
for (U_32 i = 0; i < opndCount; ++i)
if (opndInfos[i].sourceOpndId != EmptyUint32)
opndInfos[i].defCount++;
}
for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){
bool assignedOpndPropagated = false;
Inst::Opnds opnds(inst, Inst::OpndRole_All);
for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){
Opnd * opnd=inst->getOpnd(it);
U_32 roles=inst->getOpndRoles(it);
U_32 opndId = opnd->getId();
OpndInfo& opndInfo = opndInfos[opndId];
U_32 mask = 0;
if (roles & Inst::OpndRole_Def){
++opndInfo.defCount;
}else if (roles & Inst::OpndRole_Use){
if (opndInfo.sourceOpndId != EmptyUint32){
if (opndInfo.sourceOpndDefCountAtCopy < opndInfos[opndInfo.sourceOpndId].defCount)
opndInfo.sourceOpndId = EmptyUint32;
else{
Opnd * srcOpnd = irManager->getOpnd(opndInfo.sourceOpndId);
Constraint co = srcOpnd->getConstraint(Opnd::ConstraintKind_Location);
if (co.getKind() == OpndKind_Mem){
mask = (1<<it)-1;
if ((roles & Inst::OpndRole_Explicit) == 0 ||
inst->hasKind(Inst::Kind_PseudoInst) || irManager->isGCSafePoint(inst) ||
opndInfo.sourceInst != inst->getPrevInst() || assignedOpndPropagated ||
(inst->getConstraint(it, mask, co.getSize())&co).isNull()
)
opndInfo.sourceOpndId = EmptyUint32;
assignedOpndPropagated = true;
}
}
}
}
if (opndInfo.defCount > 1){
opndInfo.sourceOpndId = EmptyUint32;
}
}
/*
Here is the previous version to test whether the inst is copy or not.
bool isCopy = inst->getMnemonic() == Mnemonic_MOV ||(
(inst->getMnemonic() == Mnemonic_ADD || inst->getMnemonic() == Mnemonic_SUB) &&
inst->getOpnd(3)->isPlacedIn(OpndKind_Imm) && inst->getOpnd(3)->getImmValue()==0
&& inst->getOpnd(3)->getRuntimeInfo()==NULL
);
It considered special case of 'dst = src +/- 0' as copy.
In fact there are more similar cases like 'IMUL src, 1 ; shift src, 0' etc.
Such checks are obsolete now, Should as peephole takes care about such copies.
Anyway, the code above had a bug: 'inst->getOpnd(3)' crashes in instructions
in native form (like ADD def_use, use).
*/
const bool isCopy = inst->getMnemonic() == Mnemonic_MOV;
if (isCopy){ // CopyPseudoInst or mov
Opnd * defOpnd = inst->getOpnd(0);
Opnd * srcOpnd = inst->getOpnd(1);
U_32 defOpndId = defOpnd->getId();
OpndInfo * opndInfo = opndInfos + defOpndId;
bool instHandled=false;
bool typeConvOk = isTypeConversionAllowed(srcOpnd, defOpnd);
if (typeConvOk && opndInfo->defCount == 1 && ! srcOpnd->isPlacedIn(OpndKind_Reg)){
if (!defOpnd->hasAssignedPhysicalLocation()){
opndInfo->sourceInst = inst;
opndInfo->sourceOpndId = srcOpnd->getId();
instHandled=true;
}
}
if (instHandled){
if (opndInfos[opndInfo->sourceOpndId].sourceOpndId != EmptyUint32)
opndInfo->sourceOpndId = opndInfos[opndInfo->sourceOpndId].sourceOpndId;
opndInfo->sourceOpndDefCountAtCopy = opndInfos[opndInfo->sourceOpndId].defCount;
anyInstHandled=true;
}
}
}
}
if (anyInstHandled){
Opnd ** replacements = new(mm) Opnd* [opndCount];
memset(replacements, 0, sizeof(Opnd*) * opndCount);
bool hasReplacements = false;
for (U_32 i = 0; i < opndCount; ++i){
if (opndInfos[i].sourceOpndId != EmptyUint32){
Inst * inst = opndInfos[i].sourceInst;
if (inst !=NULL){
inst->unlink();
}
if (opndInfos[i].sourceOpndId != i){
Opnd* origOpnd= irManager->getOpnd(i);
Opnd* replacementOpnd = irManager->getOpnd(opndInfos[i].sourceOpndId);
assert(isTypeConversionAllowed(replacementOpnd, origOpnd));
if (origOpnd->getType()->isUnmanagedPtr() && replacementOpnd->getType()->isInteger()) {
replacementOpnd->setType(origOpnd->getType());
}/* else if (origOpnd->getType()->isObject() && replacementOpnd->getType()->isUnmanagedPtr()) {
replacementOpnd->setType(origOpnd->getType());
}*/
replacements[i] = replacementOpnd;
hasReplacements = true;
}
}
}
if (hasReplacements){
const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder();
for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) {
Node * node=*it;
if (!node->isBlockNode()) {
continue;
}
for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){
inst->replaceOpnds(replacements);
}
}
}
}
}
}}