lanedivide mode=2 default lane size

This commit is contained in:
caheckman 2019-11-18 11:06:11 -05:00
parent 93471fb3ea
commit 7e050e771a
4 changed files with 94 additions and 29 deletions

View file

@ -495,23 +495,18 @@ int4 ActionStackPtrFlow::apply(Funcdata &data)
return 0; return 0;
} }
/// \brief Try to divide a single Varnode into lanes /// \brief Examine the PcodeOps using the given Varnode to determine possible lane sizes
/// ///
/// Look for a CPUI_SUBPIECE op that takes the given Varnode as the input or a /// Run through the defining op and any descendant ops of the given Varnode, looking for
/// CPUI_PIECE op that defines it. The smallest piece involved in this op is considered the /// CPUI_PIECE and CPUI_SUBPIECE. Use these to determine possible lane sizes and
/// putative lane size. If this lane size is acceptable, try to split data-flow through /// register them with the given LanedRegister object.
/// this Varnode using this lane scheme. Try a split for every CPUI_SUBPIECE/CPUI_PIECE the /// \param vn is the given Varnode
/// given Varnode is involved in until one succeeds. /// \param allowedLanes is used to determine if a putative lane size is allowed
/// \param data is the function being transformed /// \param checkLanes collects the possible lane sizes
/// \param vn is the given single Varnode void ActionLaneDivide::collectLaneSizes(Varnode *vn,const LanedRegister &allowedLanes,LanedRegister &checkLanes)
/// \param lanedRegister is acceptable set of lane sizes for the Varnode
/// \param allowDowncast is \b true if we allow lane systems with SUBPIECE terminators
/// \return \b true if the Varnode (and its data-flow) was successfully split
bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,bool allowDowncast)
{ {
list<PcodeOp *>::const_iterator iter = vn->beginDescend(); list<PcodeOp *>::const_iterator iter = vn->beginDescend();
LanedRegister checkedLanes;
int4 step = 0; // 0 = descendants, 1 = def, 2 = done int4 step = 0; // 0 = descendants, 1 = def, 2 = done
if (iter == vn->endDescend()) { if (iter == vn->endDescend()) {
step = 1; step = 1;
@ -536,16 +531,46 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi
if (tmpSize < curSize) if (tmpSize < curSize)
curSize = tmpSize; curSize = tmpSize;
} }
if (lanedRegister.allowedLane(curSize)) { if (allowedLanes.allowedLane(curSize))
if (checkedLanes.allowedLane(curSize)) continue; checkLanes.addLaneSize(curSize); // Register this possible size
checkedLanes.addLaneSize(curSize); // Only check this scheme once }
LaneDescription description(lanedRegister.getWholeSize(),curSize); // Lane scheme dictated by curSize }
LaneDivide laneDivide(&data,vn,description,allowDowncast);
if (laneDivide.doTrace()) { /// \brief Search for a likely lane size and try to divide a single Varnode into these lanes
laneDivide.apply(); ///
count += 1; // Indicate a change was made /// There are different ways to search for a lane size:
return true; ///
} /// Mode 0: Collect putative lane sizes based on the local ops using the Varnode. Attempt
/// to divide based on each of those lane sizes in turn.
///
/// Mode 1: Similar to mode 0, except we allow for SUBPIECE operations that truncate to
/// variables that are smaller than the lane size.
///
/// Mode 2: Attempt to divide based on a default lane size.
/// \param data is the function being transformed
/// \param vn is the given single Varnode
/// \param lanedRegister is acceptable set of lane sizes for the Varnode
/// \param mode is the lane size search mode (0, 1, or 2)
/// \return \b true if the Varnode (and its data-flow) was successfully split
bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 mode)
{
LanedRegister checkLanes; // Lanes we are going to try, initialized to no lanes
bool allowDowncast = (mode > 0);
if (mode < 2)
collectLaneSizes(vn,lanedRegister,checkLanes);
else {
checkLanes.addLaneSize(4); // Default lane size
}
LanedRegister::const_iterator enditer = checkLanes.end();
for(LanedRegister::const_iterator iter=checkLanes.begin();iter!=enditer;++iter) {
int4 curSize = *iter;
LaneDescription description(lanedRegister.getWholeSize(),curSize); // Lane scheme dictated by curSize
LaneDivide laneDivide(&data,vn,description,allowDowncast);
if (laneDivide.doTrace()) {
laneDivide.apply();
count += 1; // Indicate a change was made
return true;
} }
} }
return false; return false;
@ -555,25 +580,31 @@ int4 ActionLaneDivide::apply(Funcdata &data)
{ {
map<VarnodeData,const LanedRegister *>::const_iterator iter; map<VarnodeData,const LanedRegister *>::const_iterator iter;
bool allowDowncast = false; for(int4 mode=0;mode<3;++mode) {
for(int4 i=0;i<2;++i) { bool allStorageProcessed = true;
for(iter=data.beginLaneAccess();iter!=data.endLaneAccess();++iter) { for(iter=data.beginLaneAccess();iter!=data.endLaneAccess();++iter) {
const LanedRegister *lanedReg = (*iter).second; const LanedRegister *lanedReg = (*iter).second;
Address addr = (*iter).first.getAddr(); Address addr = (*iter).first.getAddr();
int4 sz = (*iter).first.size; int4 sz = (*iter).first.size;
VarnodeLocSet::const_iterator viter = data.beginLoc(sz,addr); VarnodeLocSet::const_iterator viter = data.beginLoc(sz,addr);
VarnodeLocSet::const_iterator venditer = data.endLoc(sz,addr); VarnodeLocSet::const_iterator venditer = data.endLoc(sz,addr);
bool allVarnodesProcessed = true;
while(viter != venditer) { while(viter != venditer) {
Varnode *vn = *viter; Varnode *vn = *viter;
if (processVarnode(data, vn, *lanedReg, allowDowncast)) { if (processVarnode(data, vn, *lanedReg, mode)) {
viter = data.beginLoc(sz,addr); viter = data.beginLoc(sz,addr);
venditer = data.endLoc(sz, addr); // Recalculate bounds venditer = data.endLoc(sz, addr); // Recalculate bounds
allVarnodesProcessed = true;
} }
else else {
++viter; ++viter;
allVarnodesProcessed = false;
}
} }
if (!allVarnodesProcessed)
allStorageProcessed = false;
} }
allowDowncast = true; if (allStorageProcessed) break;
} }
data.clearLanedAccessMap(); data.clearLanedAccessMap();
return 0; return 0;

View file

@ -104,7 +104,8 @@ public:
/// if a particular lane scheme makes sense in terms of the function's data-flow, and then /// if a particular lane scheme makes sense in terms of the function's data-flow, and then
/// rewrites the data-flow so that the lanes become explicit Varnodes. /// rewrites the data-flow so that the lanes become explicit Varnodes.
class ActionLaneDivide : public Action { class ActionLaneDivide : public Action {
bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,bool allowDowncast); void collectLaneSizes(Varnode *vn,const LanedRegister &allowedLanes,LanedRegister &checkLanes);
bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 mode);
public: public:
ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const { virtual Action *clone(const ActionGroupList &grouplist) const {

View file

@ -261,6 +261,19 @@ bool TransformOp::attemptInsertion(Funcdata *fd)
return true; // Already inserted return true; // Already inserted
} }
void LanedRegister::LanedIterator::normalize(void)
{
uint4 flag = 1;
flag <<= size;
while(flag <= mask) {
if ((flag & mask) != 0) return; // Found a valid lane size
size += 1;
flag <<= 1;
}
size = -1; // Indicate ending iterator
}
/// Read XML of the form \<register name=".." vector_lane_sizes=".."/> /// Read XML of the form \<register name=".." vector_lane_sizes=".."/>
/// \param el is the particular \e register tag /// \param el is the particular \e register tag
/// \param manage is used to map register names to storage info /// \param manage is used to map register names to storage info

View file

@ -86,6 +86,24 @@ public:
/// \brief Describes a (register) storage location and the ways it might be split into lanes /// \brief Describes a (register) storage location and the ways it might be split into lanes
class LanedRegister { class LanedRegister {
friend class LanedIterator;
public:
/// \brief Class for iterating over possible lane sizes
class LanedIterator {
int4 size; ///< Current lane size
uint4 mask; ///< Collection being iterated over
void normalize(void); ///< Normalize the iterator, after increment or initialization
public:
LanedIterator(const LanedRegister *lanedR) { size = 0; mask = lanedR->sizeBitMask; normalize(); } ///< Constructor
LanedIterator(void) { size = -1; mask = 0; } ///< Constructor for ending iterator
LanedIterator &operator++(void) { size += 1; normalize(); return *this; } ///< Preincrement operator
int4 operator*(void) const { return size; } /// Dereference operator
LanedIterator &operator=(const LanedIterator &op2) { size = op2.size; mask = op2.mask; return *this; } ///< Assignment
bool operator==(const LanedIterator &op2) const { return (size == op2.size); } ///< Equal operator
bool operator!=(const LanedIterator &op2) const { return (size != op2.size); } ///< Not-equal operator
};
typedef LanedIterator const_iterator;
private:
int4 wholeSize; ///< Size of the whole register int4 wholeSize; ///< Size of the whole register
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
public: public:
@ -96,6 +114,8 @@ public:
uint4 getSizeBitMask(void) const { return sizeBitMask; } ///< Get the bit mask of possible lane sizes uint4 getSizeBitMask(void) const { return sizeBitMask; } ///< Get the bit mask of possible lane sizes
void addLaneSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list void addLaneSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list
bool allowedLane(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes bool allowedLane(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes
const_iterator begin(void) const { return LanedIterator(this); } ///< Starting iterator over possible lane sizes
const_iterator end(void) const { return LanedIterator(); } ///< Ending iterator over possible lane sizes
}; };
/// \brief Description of logical lanes within a \b big Varnode /// \brief Description of logical lanes within a \b big Varnode