mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +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());
|
const List &list(el->getChildren());
|
||||||
List::const_iterator iter;
|
List::const_iterator iter;
|
||||||
|
|
||||||
AllowedLanes allowedLanes; // Only allocate once
|
LanedRegister lanedRegister; // Only allocate once
|
||||||
for(iter=list.begin();iter!=list.end();++iter) {
|
for(iter=list.begin();iter!=list.end();++iter) {
|
||||||
if (allowedLanes.restoreXml(*iter, this)) {
|
if (lanedRegister.restoreXml(*iter, this)) {
|
||||||
lanerecords.push_back(allowedLanes);
|
lanerecords.push_back(lanedRegister);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lanerecords.sort();
|
lanerecords.sort();
|
||||||
|
|
|
@ -152,7 +152,7 @@ public:
|
||||||
vector<TypeOp *> inst; ///< Registered p-code instructions
|
vector<TypeOp *> inst; ///< Registered p-code instructions
|
||||||
UserOpManage userops; ///< Specifically registered user-defined p-code ops
|
UserOpManage userops; ///< Specifically registered user-defined p-code ops
|
||||||
vector<PreferSplitRecord> splitrecords; ///< registers that we would prefer to see split for this processor
|
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
|
ActionDatabase allacts; ///< Actions that can be applied in this architecture
|
||||||
bool loadersymbols_parsed; ///< True if loader symbols have been read
|
bool loadersymbols_parsed; ///< True if loader symbols have been read
|
||||||
#ifdef CPUI_STATISTICS
|
#ifdef CPUI_STATISTICS
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "coreaction.hh"
|
#include "coreaction.hh"
|
||||||
#include "condexe.hh"
|
#include "condexe.hh"
|
||||||
#include "double.hh"
|
#include "double.hh"
|
||||||
|
#include "subflow.hh"
|
||||||
|
|
||||||
/// \brief A stack equation
|
/// \brief A stack equation
|
||||||
struct StackEqn {
|
struct StackEqn {
|
||||||
|
@ -494,6 +495,94 @@ int4 ActionStackPtrFlow::apply(Funcdata &data)
|
||||||
return 0;
|
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)
|
int4 ActionSegmentize::apply(Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -4505,6 +4594,7 @@ void universal_action(Architecture *conf)
|
||||||
// actmainloop->addAction( new ActionParamShiftStop("paramshift") );
|
// actmainloop->addAction( new ActionParamShiftStop("paramshift") );
|
||||||
actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); // Do before dead code removed
|
actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); // Do before dead code removed
|
||||||
actmainloop->addAction( new ActionDeadCode("deadcode") );
|
actmainloop->addAction( new ActionDeadCode("deadcode") );
|
||||||
|
actmainloop->addAction( new ActionLaneDivide("base") );
|
||||||
actmainloop->addAction( new ActionDynamicMapping("dynamic") ); // Must come before restructurevarnode and infertypes
|
actmainloop->addAction( new ActionDynamicMapping("dynamic") ); // Must come before restructurevarnode and infertypes
|
||||||
actmainloop->addAction( new ActionRestructureVarnode("localrecovery") );
|
actmainloop->addAction( new ActionRestructureVarnode("localrecovery") );
|
||||||
actmainloop->addAction( new ActionSpacebase("base") ); // Must come before infertypes and nonzeromask
|
actmainloop->addAction( new ActionSpacebase("base") ); // Must come before infertypes and nonzeromask
|
||||||
|
|
|
@ -97,6 +97,24 @@ public:
|
||||||
virtual int4 apply(Funcdata &data);
|
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.
|
/// \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
|
/// 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;
|
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
|
/// 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
|
/// map to the number of lanes. Positions that are out of bounds or that do
|
||||||
/// not fall on a lane boundary will return -1.
|
/// 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 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
|
||||||
/// \return \b true if the XML description provides lane sizes
|
/// \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;
|
string laneSizes;
|
||||||
|
@ -248,7 +278,7 @@ bool AllowedLanes::restoreXml(const Element *el,const AddrSpaceManager *manage)
|
||||||
if (laneSizes.empty()) return false;
|
if (laneSizes.empty()) return false;
|
||||||
storage.space = (AddrSpace *)0;
|
storage.space = (AddrSpace *)0;
|
||||||
storage.restoreXml(el, manage);
|
storage.restoreXml(el, manage);
|
||||||
sizes.clear();
|
sizeBitMask = 0;
|
||||||
string::size_type pos = 0;
|
string::size_type pos = 0;
|
||||||
while(pos != string::npos) {
|
while(pos != string::npos) {
|
||||||
string::size_type nextPos = laneSizes.find(',',pos);
|
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);
|
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||||
int4 sz = -1;
|
int4 sz = -1;
|
||||||
s >> sz;
|
s >> sz;
|
||||||
if (sz < 0) return false;
|
if (sz < 0 || sz > 16)
|
||||||
sizes.push_back(sz);
|
throw LowlevelError("Bad lane size: " + value);
|
||||||
|
addSize(sz);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,16 +85,16 @@ 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 AllowedLanes {
|
class LanedRegister {
|
||||||
VarnodeData storage; ///< Defining characteristics of the register
|
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:
|
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
|
bool restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore object from XML stream
|
||||||
const VarnodeData &getStorage(void) const { return storage; } ///< Get VarnodeData for storage
|
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
|
void addSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list
|
||||||
int4 getBaseLaneSize(int4 i) const { return sizes[i]; } ///< Get the base lane size for the i-th splitting
|
bool contains(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes
|
||||||
bool operator<(const AllowedLanes &op2) const { return (storage < op2.storage); } ///< Compare based on VarnodeData
|
bool operator<(const LanedRegister &op2) const { return (storage < op2.storage); } ///< Compare based on VarnodeData
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Description of logical lanes within a \b big Varnode
|
/// \brief Description of logical lanes within a \b big Varnode
|
||||||
|
@ -110,6 +110,7 @@ public:
|
||||||
LaneDescription(const LaneDescription &op2); ///< Copy constructor
|
LaneDescription(const LaneDescription &op2); ///< Copy constructor
|
||||||
LaneDescription(int4 origSize,int4 sz); ///< Construct uniform lanes
|
LaneDescription(int4 origSize,int4 sz); ///< Construct uniform lanes
|
||||||
LaneDescription(int4 origSize,int4 lo,int4 hi); ///< Construct two lanes of arbitrary size
|
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 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 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
|
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