mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-4979 Better support for partial array optimizations
This commit is contained in:
parent
43655ab76c
commit
784540f1c0
14 changed files with 317 additions and 134 deletions
|
@ -4,9 +4,9 @@
|
|||
* Licensed 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.
|
||||
|
@ -1100,6 +1100,66 @@ bool Funcdata::collapseIntMultMult(Varnode *vn)
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Return a Varnode in the \e unique space that is defined by a COPY op taking the given Varnode as input.
|
||||
/// If a COPY op to a \e unique already exists, it may be returned. If the preexisting COPY is not usable
|
||||
/// at the specified \b point, it is redefined at an earlier point in the control-flow so that it can be used.
|
||||
/// \param vn is the given Varnode to COPY
|
||||
/// \param point is the PcodeOp where the copy needs to be available
|
||||
/// \return the \e unique Varnode COPY
|
||||
Varnode *Funcdata::buildCopyTemp(Varnode *vn,PcodeOp *point)
|
||||
|
||||
{
|
||||
PcodeOp *otherOp = (PcodeOp *)0;
|
||||
PcodeOp *usedCopy = (PcodeOp *)0;
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
||||
PcodeOp *op = *iter;
|
||||
if (op->code() != CPUI_COPY) continue;
|
||||
Varnode *outvn = op->getOut();
|
||||
if (outvn->getSpace()->getType() == IPTR_INTERNAL) {
|
||||
if (outvn->isTypeLock())
|
||||
continue;
|
||||
otherOp = op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (otherOp != (PcodeOp *)0) {
|
||||
if (point->getParent() == otherOp->getParent()) {
|
||||
if (point->getSeqNum().getOrder() < otherOp->getSeqNum().getOrder())
|
||||
usedCopy = (PcodeOp *)0;
|
||||
else
|
||||
usedCopy = otherOp;
|
||||
}
|
||||
else {
|
||||
BlockBasic *common;
|
||||
common = (BlockBasic *)FlowBlock::findCommonBlock(point->getParent(),otherOp->getParent());
|
||||
if (common == point->getParent())
|
||||
usedCopy = (PcodeOp *)0;
|
||||
else if (common == otherOp->getParent())
|
||||
usedCopy = otherOp;
|
||||
else { // Neither op is ancestor of the other
|
||||
usedCopy = newOp(1,common->getStop());
|
||||
opSetOpcode(usedCopy,CPUI_COPY);
|
||||
newUniqueOut(vn->getSize(),usedCopy);
|
||||
opSetInput(usedCopy,vn,0);
|
||||
opInsertEnd(usedCopy,common);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (usedCopy == (PcodeOp *)0) {
|
||||
usedCopy = newOp(1,point->getAddr());
|
||||
opSetOpcode(usedCopy, CPUI_COPY);
|
||||
newUniqueOut(vn->getSize(), usedCopy);
|
||||
opSetInput(usedCopy, vn, 0);
|
||||
opInsertBefore(usedCopy, point);
|
||||
}
|
||||
if (otherOp != (PcodeOp *)0 && otherOp != usedCopy) {
|
||||
totalReplace(otherOp->getOut(),usedCopy->getOut());
|
||||
opDestroy(otherOp);
|
||||
}
|
||||
return usedCopy->getOut();
|
||||
}
|
||||
|
||||
/// \brief Trace a boolean value to a set of PcodeOps that can be changed to flip the boolean value
|
||||
///
|
||||
/// The boolean Varnode is either the output of the given PcodeOp or the
|
||||
|
@ -1108,7 +1168,7 @@ bool Funcdata::collapseIntMultMult(Varnode *vn)
|
|||
/// \param op is the given PcodeOp
|
||||
/// \param fliplist is the array that will hold the ops to flip
|
||||
/// \return 0 if the change normalizes, 1 if the change is ambivalent, 2 if the change does not normalize
|
||||
int4 opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
|
||||
int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
|
||||
|
||||
{
|
||||
Varnode *vn;
|
||||
|
@ -1168,7 +1228,7 @@ int4 opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
|
|||
/// facilitate the flip.
|
||||
/// \param data is the function being modified
|
||||
/// \param fliplist is the list of PcodeOps to modify
|
||||
void opFlipInPlaceExecute(Funcdata &data,vector<PcodeOp *> &fliplist)
|
||||
void Funcdata::opFlipInPlaceExecute(vector<PcodeOp *> &fliplist)
|
||||
|
||||
{
|
||||
Varnode *vn;
|
||||
|
@ -1180,53 +1240,29 @@ void opFlipInPlaceExecute(Funcdata &data,vector<PcodeOp *> &fliplist)
|
|||
vn = op->getIn(0);
|
||||
PcodeOp *otherop = op->getOut()->loneDescend(); // Must be a lone descendant
|
||||
int4 slot = otherop->getSlot(op->getOut());
|
||||
data.opSetInput(otherop,vn,slot); // Propagate -vn- into otherop
|
||||
data.opDestroy(op);
|
||||
opSetInput(otherop,vn,slot); // Propagate -vn- into otherop
|
||||
opDestroy(op);
|
||||
}
|
||||
else if (opc == CPUI_MAX) {
|
||||
if (op->code() == CPUI_BOOL_AND)
|
||||
data.opSetOpcode(op,CPUI_BOOL_OR);
|
||||
opSetOpcode(op,CPUI_BOOL_OR);
|
||||
else if (op->code() == CPUI_BOOL_OR)
|
||||
data.opSetOpcode(op,CPUI_BOOL_AND);
|
||||
opSetOpcode(op,CPUI_BOOL_AND);
|
||||
else
|
||||
throw LowlevelError("Bad flipInPlace op");
|
||||
}
|
||||
else {
|
||||
data.opSetOpcode(op,opc);
|
||||
opSetOpcode(op,opc);
|
||||
if (flipyes) {
|
||||
data.opSwapInput(op,0,1);
|
||||
opSwapInput(op,0,1);
|
||||
|
||||
if ((opc == CPUI_INT_LESSEQUAL)||(opc == CPUI_INT_SLESSEQUAL))
|
||||
data.replaceLessequal(op);
|
||||
replaceLessequal(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Get the earliest use/read of a Varnode in a specified basic block
|
||||
///
|
||||
/// \param vn is the Varnode to search for
|
||||
/// \param bl is the specified basic block in which to search
|
||||
/// \return the earliest PcodeOp reading the Varnode or NULL
|
||||
PcodeOp *earliestUseInBlock(Varnode *vn,BlockBasic *bl)
|
||||
|
||||
{
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
PcodeOp *res = (PcodeOp *)0;
|
||||
|
||||
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
||||
PcodeOp *op = *iter;
|
||||
if (op->getParent() != bl) continue;
|
||||
if (res == (PcodeOp *)0)
|
||||
res = op;
|
||||
else {
|
||||
if (op->getSeqNum().getOrder() < res->getSeqNum().getOrder())
|
||||
res = op;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \brief Find a duplicate calculation of a given PcodeOp reading a specific Varnode
|
||||
///
|
||||
/// We only match 1 level of calculation. Additionally the duplicate must occur in the
|
||||
|
@ -1236,7 +1272,7 @@ PcodeOp *earliestUseInBlock(Varnode *vn,BlockBasic *bl)
|
|||
/// \param bl is the indicated basic block
|
||||
/// \param earliest is the specified op to be earlier than
|
||||
/// \return the discovered duplicate PcodeOp or NULL
|
||||
PcodeOp *cseFindInBlock(PcodeOp *op,Varnode *vn,BlockBasic *bl,PcodeOp *earliest)
|
||||
PcodeOp *Funcdata::cseFindInBlock(PcodeOp *op,Varnode *vn,BlockBasic *bl,PcodeOp *earliest)
|
||||
|
||||
{
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
|
@ -1265,11 +1301,10 @@ PcodeOp *cseFindInBlock(PcodeOp *op,Varnode *vn,BlockBasic *bl,PcodeOp *earliest
|
|||
/// (depth 1 functional equivalence) eliminate the redundancy. Return the remaining (dominating)
|
||||
/// PcodeOp. If neither op dominates the other, both are eliminated, and a new PcodeOp
|
||||
/// is built at a commonly accessible point.
|
||||
/// \param data is the function being modified
|
||||
/// \param op1 is the first of the given PcodeOps
|
||||
/// \param op2 is the second given PcodeOp
|
||||
/// \return the dominating PcodeOp
|
||||
PcodeOp *cseElimination(Funcdata &data,PcodeOp *op1,PcodeOp *op2)
|
||||
PcodeOp *Funcdata::cseElimination(PcodeOp *op1,PcodeOp *op2)
|
||||
|
||||
{
|
||||
PcodeOp *replace;
|
||||
|
@ -1288,25 +1323,25 @@ PcodeOp *cseElimination(Funcdata &data,PcodeOp *op1,PcodeOp *op2)
|
|||
else if (common == op2->getParent())
|
||||
replace = op2;
|
||||
else { // Neither op is ancestor of the other
|
||||
replace = data.newOp(op1->numInput(),common->getStop());
|
||||
data.opSetOpcode(replace,op1->code());
|
||||
data.newVarnodeOut(op1->getOut()->getSize(),op1->getOut()->getAddr(),replace);
|
||||
replace = newOp(op1->numInput(),common->getStop());
|
||||
opSetOpcode(replace,op1->code());
|
||||
newVarnodeOut(op1->getOut()->getSize(),op1->getOut()->getAddr(),replace);
|
||||
for(int4 i=0;i<op1->numInput();++i) {
|
||||
if (op1->getIn(i)->isConstant())
|
||||
data.opSetInput(replace,data.newConstant(op1->getIn(i)->getSize(),op1->getIn(i)->getOffset()),i);
|
||||
opSetInput(replace,newConstant(op1->getIn(i)->getSize(),op1->getIn(i)->getOffset()),i);
|
||||
else
|
||||
data.opSetInput(replace,op1->getIn(i),i);
|
||||
opSetInput(replace,op1->getIn(i),i);
|
||||
}
|
||||
data.opInsertEnd(replace,common);
|
||||
opInsertEnd(replace,common);
|
||||
}
|
||||
}
|
||||
if (replace != op1) {
|
||||
data.totalReplace(op1->getOut(),replace->getOut());
|
||||
data.opDestroy(op1);
|
||||
totalReplace(op1->getOut(),replace->getOut());
|
||||
opDestroy(op1);
|
||||
}
|
||||
if (replace != op2) {
|
||||
data.totalReplace(op2->getOut(),replace->getOut());
|
||||
data.opDestroy(op2);
|
||||
totalReplace(op2->getOut(),replace->getOut());
|
||||
opDestroy(op2);
|
||||
}
|
||||
return replace;
|
||||
}
|
||||
|
@ -1329,10 +1364,9 @@ static bool compareCseHash(const pair<uintm,PcodeOp *> &a,const pair<uintm,Pcode
|
|||
/// The hash serves as a primary test for duplicate calculations; if it doesn't match
|
||||
/// the PcodeOps aren't common subexpressions. This method searches for hash matches
|
||||
/// then does secondary testing and eliminates any redundancy it finds.
|
||||
/// \param data is the function being modified
|
||||
/// \param list is the list of (hash, PcodeOp) pairs
|
||||
/// \param outlist will hold Varnodes produced by duplicate calculations
|
||||
void cseEliminateList(Funcdata &data,vector< pair<uintm,PcodeOp *> > &list,vector<Varnode *> &outlist)
|
||||
void Funcdata::cseEliminateList(vector< pair<uintm,PcodeOp *> > &list,vector<Varnode *> &outlist)
|
||||
|
||||
{
|
||||
PcodeOp *op1,*op2,*resop;
|
||||
|
@ -1350,9 +1384,9 @@ void cseEliminateList(Funcdata &data,vector< pair<uintm,PcodeOp *> > &list,vecto
|
|||
if ((!op1->isDead())&&(!op2->isDead())&&op1->isCseMatch(op2)) {
|
||||
Varnode *outvn1 = op1->getOut();
|
||||
Varnode *outvn2 = op2->getOut();
|
||||
if ((outvn1 == (Varnode *)0)||data.isHeritaged(outvn1)) {
|
||||
if ((outvn2 == (Varnode *)0)||data.isHeritaged(outvn2)) {
|
||||
resop = cseElimination(data,op1,op2);
|
||||
if ((outvn1 == (Varnode *)0)||isHeritaged(outvn1)) {
|
||||
if ((outvn2 == (Varnode *)0)||isHeritaged(outvn2)) {
|
||||
resop = cseElimination(op1,op2);
|
||||
outlist.push_back(resop->getOut());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue