mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
added ActionLaneDivide
This commit is contained in:
parent
90182c6251
commit
04d28bcc4e
6 changed files with 154 additions and 14 deletions
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue