added ActionLaneDivide

This commit is contained in:
caheckman 2019-10-18 09:39:42 -04:00
parent 90182c6251
commit 04d28bcc4e
6 changed files with 154 additions and 14 deletions

View file

@ -820,10 +820,10 @@ void Architecture::parseLaneSizes(const Element *el)
const List &list(el->getChildren());
List::const_iterator iter;
AllowedLanes allowedLanes; // Only allocate once
LanedRegister lanedRegister; // Only allocate once
for(iter=list.begin();iter!=list.end();++iter) {
if (allowedLanes.restoreXml(*iter, this)) {
lanerecords.push_back(allowedLanes);
if (lanedRegister.restoreXml(*iter, this)) {
lanerecords.push_back(lanedRegister);
}
}
lanerecords.sort();

View file

@ -152,7 +152,7 @@ public:
vector<TypeOp *> inst; ///< Registered p-code instructions
UserOpManage userops; ///< Specifically registered user-defined p-code ops
vector<PreferSplitRecord> splitrecords; ///< registers that we would prefer to see split for this processor
list<AllowedLanes> lanerecords; ///< Vector registers that have preferred lane sizes
list<LanedRegister> lanerecords; ///< Vector registers that have preferred lane sizes
ActionDatabase allacts; ///< Actions that can be applied in this architecture
bool loadersymbols_parsed; ///< True if loader symbols have been read
#ifdef CPUI_STATISTICS

View file

@ -16,6 +16,7 @@
#include "coreaction.hh"
#include "condexe.hh"
#include "double.hh"
#include "subflow.hh"
/// \brief A stack equation
struct StackEqn {
@ -494,6 +495,94 @@ int4 ActionStackPtrFlow::apply(Funcdata &data)
return 0;
}
/// \brief Try to divide a single Varnode into lanes
///
/// Look for a CPUI_SUBPIECE op that takes the given Varnode as the input. If
/// the output size is an acceptable lane size, try to split data-flow through
/// this Varnode using this lane scheme. Try a split for every output size of such a
/// SUBPIECE op until one succeeds.
/// \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
bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister)
{
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
LanedRegister checkedLanes;
while(iter != vn->endDescend()) {
PcodeOp *op = *iter;
++iter;
if (op->code() != CPUI_SUBPIECE) continue;
int4 curSize = op->getOut()->getSize();
if (lanedRegister.contains(curSize)) {
if (checkedLanes.contains(curSize)) continue;
checkedLanes.addSize(curSize); // Only check this scheme once
LaneDescription description(lanedRegister.getStorage().size,curSize); // Lane scheme dictated by curSize
int4 bytePos = (int4)(lanedRegister.getStorage().offset - vn->getOffset());
if (lanedRegister.getStorage().space->isBigEndian()) {
bytePos = lanedRegister.getStorage().size - (bytePos + vn->getSize()); // Convert to significance order
}
if (!description.subset(bytePos,vn->getSize())) // Try to restrict lane scheme to actual Varnode
continue;
LaneDivide laneDivide(&data,op->getIn(0),description);
if (laneDivide.doTrace()) {
laneDivide.apply();
count += 1; // Indicate a change was made
return true;
}
}
}
return false;
}
/// \brief Search for and attempt to split Varnodes that match the given laned vector register
///
/// \param data is the function being modified
/// \param lanedRegister is the given register and acceptable lane schemes
/// \param iter is an iterator to the first Varnode that matches the vector register
void ActionLaneDivide::processLane(Funcdata &data,const LanedRegister &lanedRegister,VarnodeLocSet::const_iterator iter)
{
int4 fullSize = lanedRegister.getStorage().size;
Address startAddress(lanedRegister.getStorage().getAddr());
Address lastAddress(startAddress + (fullSize-1));
VarnodeLocSet::const_iterator enditer = data.endLoc();
while(iter != enditer) {
Varnode *vn = *iter;
++iter;
if (lastAddress < vn->getAddr())
break;
int4 diff = (int4)(vn->getOffset() - startAddress.getOffset());
if (diff + vn->getSize() > fullSize) // Must be contained by full register
continue;
if (diff != 0 && diff != fullSize/2) // Must be all or half of full register
continue;
if (processVarnode(data,vn,lanedRegister)) {
// If changes were made, iterator may no longer be valid, generate a new one
iter = data.beginLoc(startAddress);
}
}
}
int4 ActionLaneDivide::apply(Funcdata &data)
{
if (data.getArch()->lanerecords.empty())
return 0;
const LanedRegister &lastRecord( data.getArch()->lanerecords.back() );
Address lastAddress( lastRecord.getStorage().getAddr() + lastRecord.getStorage().size - 1);
list<LanedRegister>::const_iterator iter;
for(iter=data.getArch()->lanerecords.begin();iter!=data.getArch()->lanerecords.end();++iter) {
const LanedRegister &lanedRegister( *iter );
VarnodeLocSet::const_iterator viter = data.beginLoc(lanedRegister.getStorage().getAddr());
if (viter == data.endLoc()) break;
Varnode *vn = *viter;
if (lastAddress < vn->getAddr()) break;
processLane(data,lanedRegister,viter);
}
return 0;
}
int4 ActionSegmentize::apply(Funcdata &data)
{
@ -4505,6 +4594,7 @@ void universal_action(Architecture *conf)
// actmainloop->addAction( new ActionParamShiftStop("paramshift") );
actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); // Do before dead code removed
actmainloop->addAction( new ActionDeadCode("deadcode") );
actmainloop->addAction( new ActionLaneDivide("base") );
actmainloop->addAction( new ActionDynamicMapping("dynamic") ); // Must come before restructurevarnode and infertypes
actmainloop->addAction( new ActionRestructureVarnode("localrecovery") );
actmainloop->addAction( new ActionSpacebase("base") ); // Must come before infertypes and nonzeromask

View file

@ -97,6 +97,24 @@ public:
virtual int4 apply(Funcdata &data);
};
/// \brief Find Varnodes with a vectorized lane scheme and attempt to split the lanes
///
/// The Architecture lists (vector) registers that may be used to perform parallelized operations
/// on \b lanes within the register. This action looks for these registers as Varnodes, determines
/// 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.
class ActionLaneDivide : public Action {
bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister);
void processLane(Funcdata &data,const LanedRegister &lanedRegister,VarnodeLocSet::const_iterator iter);
public:
ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionLaneDivide(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Make sure pointers into segmented spaces have the correct form.
///
/// Convert user-defined ops defined as segment p-code ops by a cspec tag into the internal CPUI_SEGMENTOP

View file

@ -58,6 +58,36 @@ LaneDescription::LaneDescription(int4 origSize,int4 lo,int4 hi)
lanePosition[1] = lo;
}
/// Given a subrange, specified as an offset into the whole and size,
/// throw out any lanes in \b this that aren't in the subrange, so that the
/// size of whole is the size of the subrange. If the subrange intersects partially
/// with any of the lanes, return \b false.
/// \param lsbOffset is the number of bytes to remove from the front of the description
/// \param size is the number of bytes in the subrange
/// \return \b true if \b this was successfully transformed to the subrange
bool LaneDescription::subset(int4 lsbOffset,int4 size)
{
if (lsbOffset == 0 && size == wholeSize)
return true; // subrange is the whole range
int4 firstLane = getBoundary(lsbOffset);
if (firstLane < 0) return false;
int4 lastLane = getBoundary(lsbOffset + size);
if (lastLane < 0) return false;
vector<int4> newLaneSize;
lanePosition.clear();
int4 newPosition = 0;
for(int4 i=firstLane;i<lastLane;++i) {
int4 sz = laneSize[i];
lanePosition.push_back(newPosition);
newLaneSize.push_back(sz);
newPosition += sz;
}
wholeSize = size;
laneSize = newLaneSize;
return true;
}
/// Position 0 will map to index 0 and a position equal to whole size will
/// map to the number of lanes. Positions that are out of bounds or that do
/// not fall on a lane boundary will return -1.
@ -235,7 +265,7 @@ bool TransformOp::attemptInsertion(Funcdata *fd)
/// \param el is the particular \e register tag
/// \param manage is used to map register names to storage info
/// \return \b true if the XML description provides lane sizes
bool AllowedLanes::restoreXml(const Element *el,const AddrSpaceManager *manage)
bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage)
{
string laneSizes;
@ -248,7 +278,7 @@ bool AllowedLanes::restoreXml(const Element *el,const AddrSpaceManager *manage)
if (laneSizes.empty()) return false;
storage.space = (AddrSpace *)0;
storage.restoreXml(el, manage);
sizes.clear();
sizeBitMask = 0;
string::size_type pos = 0;
while(pos != string::npos) {
string::size_type nextPos = laneSizes.find(',',pos);
@ -267,8 +297,9 @@ bool AllowedLanes::restoreXml(const Element *el,const AddrSpaceManager *manage)
s.unsetf(ios::dec | ios::hex | ios::oct);
int4 sz = -1;
s >> sz;
if (sz < 0) return false;
sizes.push_back(sz);
if (sz < 0 || sz > 16)
throw LowlevelError("Bad lane size: " + value);
addSize(sz);
}
return true;
}

View file

@ -85,16 +85,16 @@ public:
};
/// \brief Describes a (register) storage location and the ways it might be split into lanes
class AllowedLanes {
class LanedRegister {
VarnodeData storage; ///< Defining characteristics of the register
vector<int4> sizes; ///< Size of individual lane (in bytes) for each possible lane splitting
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
public:
AllowedLanes(void) {} ///< Constructor for use with restoreXml
LanedRegister(void) { sizeBitMask = 0; } ///< Constructor
bool restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore object from XML stream
const VarnodeData &getStorage(void) const { return storage; } ///< Get VarnodeData for storage
int4 numSplittings(void) const { return sizes.size(); } ///< Get the number of different lane splittings
int4 getBaseLaneSize(int4 i) const { return sizes[i]; } ///< Get the base lane size for the i-th splitting
bool operator<(const AllowedLanes &op2) const { return (storage < op2.storage); } ///< Compare based on VarnodeData
void addSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list
bool contains(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes
bool operator<(const LanedRegister &op2) const { return (storage < op2.storage); } ///< Compare based on VarnodeData
};
/// \brief Description of logical lanes within a \b big Varnode
@ -110,6 +110,7 @@ public:
LaneDescription(const LaneDescription &op2); ///< Copy constructor
LaneDescription(int4 origSize,int4 sz); ///< Construct uniform lanes
LaneDescription(int4 origSize,int4 lo,int4 hi); ///< Construct two lanes of arbitrary size
bool subset(int4 lsbOffset,int4 size); ///< Trim \b this to a subset of the original lanes
int4 getNumLanes(void) const { return laneSize.size(); } ///< Get the total number of lanes
int4 getWholeSize(void) const { return wholeSize; } ///< Get the size of the region being split
int4 getSize(int4 i) const { return laneSize[i]; } ///< Get the size of the i-th lane