GP-1683 Extensions to SUBPIECE/shift rules

This commit is contained in:
caheckman 2022-04-27 11:45:14 -04:00
parent d0a8291e93
commit aa85bba5d7
3 changed files with 70 additions and 11 deletions

View file

@ -4736,7 +4736,7 @@ int4 RuleSubCancel::applyOp(PcodeOp *op,Funcdata &data)
}
/// \class RuleShiftSub
/// \brief Simplify SUBPIECE applied to INT_LEFT: `sub( V << 8*c, c) => sub(V,0)`
/// \brief Simplify SUBPIECE applied to INT_LEFT: `sub( V << 8*k, c) => sub(V,c-k)`
void RuleShiftSub::getOpList(vector<uint4> &oplist) const
{
@ -4749,13 +4749,20 @@ int4 RuleShiftSub::applyOp(PcodeOp *op,Funcdata &data)
if (!op->getIn(0)->isWritten()) return 0;
PcodeOp *shiftop = op->getIn(0)->getDef();
if (shiftop->code() != CPUI_INT_LEFT) return 0;
if (!shiftop->getIn(1)->isConstant()) return 0;
if (8*op->getIn(1)->getOffset() != shiftop->getIn(1)->getOffset())
return 0;
Varnode *sa = shiftop->getIn(1);
if (!sa->isConstant()) return 0;
int4 n = sa->getOffset();
if ((n & 7) != 0) return 0; // Must shift by a multiple of 8 bits
int4 c = op->getIn(1)->getOffset();
Varnode *vn = shiftop->getIn(0);
if (vn->isFree()) return 0;
int4 insize = vn->getSize();
int4 outsize = op->getOut()->getSize();
c -= n/8;
if (c < 0 || c + outsize > insize) // Check if this is a natural truncation
return 0;
data.opSetInput(op,vn,0);
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),0),1);
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),c),1);
return 1;
}
@ -6879,7 +6886,8 @@ int4 RuleExtensionPush::applyOp(PcodeOp *op,Funcdata &data)
/// \brief Pull-back SUBPIECE through INT_RIGHT and INT_SRIGHT
///
/// The form looks like:
/// - `sub( V>>c ,d ) => sub( V, d+k/8 ) >> (c-k) where k = (c/8)*8`
/// - `sub( V>>n ,c ) => sub( V, c+k/8 ) >> (n-k) where k = (n/8)*8` or
/// - `sub( V>>n, c ) => ext( sub( V, c+k/8 ) ) if n is big`
void RuleSubNormal::getOpList(vector<uint4> &oplist) const
{
@ -6901,13 +6909,35 @@ int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data)
int4 n = shiftop->getIn(1)->getOffset();
int4 c = op->getIn(1)->getOffset();
int4 k = (n/8);
int4 insize = a->getSize();
int4 outsize = op->getOut()->getSize();
// If totalcut + remain > original input, shrink cut
if (k+c+outsize > shiftout->getSize())
k = shiftout->getSize()-c-outsize;
// Total shift + outsize must be greater equal to size of input
if ((n+8*c+8*outsize < 8*a->getSize())&&(n != k*8)) return 0;
if ((n+8*c+8*outsize < 8*insize)&&(n != k*8)) return 0;
// If totalcut + remain > original input
if (k+c+outsize > insize) {
int4 truncSize = insize - c - k;
if (n == k*8 && truncSize > 0 && popcount(truncSize)==1) {
// We need an additional extension
c += k;
PcodeOp *newop = data.newOp(2,op->getAddr());
opc = (opc == CPUI_INT_SRIGHT) ? CPUI_INT_SEXT : CPUI_INT_ZEXT;
data.opSetOpcode(newop,CPUI_SUBPIECE);
data.newUniqueOut(truncSize,newop);
data.opSetInput(newop,a,0);
data.opSetInput(newop,data.newConstant(4,c),1);
data.opInsertBefore(newop,op);
data.opSetInput(op,newop->getOut(),0);
data.opRemoveInput(op,1);
data.opSetOpcode(op,opc);
return 1;
}
else
k = insize-c-outsize; // Or we can shrunk the cut
}
// if n == k*8, then a shift is unnecessary
c += k;
n -= k*8;
@ -6919,7 +6949,7 @@ int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data)
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_SUBPIECE);
data.newUniqueOut(op->getOut()->getSize(),newop);
data.newUniqueOut(outsize,newop);
data.opSetInput(newop,a,0);
data.opSetInput(newop,data.newConstant(4,c),1);
data.opInsertBefore(newop,op);