Merge remote-tracking branch 'origin/GP-5581_sleighPiecewiseUniques--SQUASHED'

This commit is contained in:
Ryan Kurtz 2025-08-18 13:44:28 -04:00
commit 6773801f6e
20 changed files with 798 additions and 482 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -583,9 +583,6 @@ VarnodeTpl *PcodeCompile::buildTruncatedVarnode(VarnodeTpl *basevn,uint4 bitoffs
if ((bitoffset % 8) != 0) return (VarnodeTpl *)0;
if ((numbits % 8) != 0) return (VarnodeTpl *)0;
if (basevn->getSpace().isUniqueSpace()) // Do we really want to prevent truncated uniques??
return (VarnodeTpl *)0;
ConstTpl::const_type offset_type = basevn->getOffset().getType();
if ((offset_type != ConstTpl::real)&&(offset_type != ConstTpl::handle))
return (VarnodeTpl *)0;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -540,6 +540,18 @@ void VarnodeTpl::decode(Decoder &decoder)
decoder.closeElement(el);
}
bool VarnodeTpl::operator==(const VarnodeTpl &op2) const
{
return space==op2.space && offset==op2.offset && size==op2.size;
}
bool VarnodeTpl::operator!=(const VarnodeTpl &op2) const
{
return !(*this == op2);
}
bool VarnodeTpl::operator<(const VarnodeTpl &op2) const
{

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -91,6 +91,8 @@ public:
bool isDynamic(const ParserWalker &walker) const;
int4 transfer(const vector<HandleTpl *> &params);
bool isZeroSize(void) const { return size.isZero(); }
bool operator==(const VarnodeTpl &op2) const;
bool operator!=(const VarnodeTpl &op2) const;
bool operator<(const VarnodeTpl &op2) const;
void setOffset(uintb constVal) { offset = ConstTpl(ConstTpl::real,constVal); }
void setRelative(uintb constVal) { offset = ConstTpl(ConstTpl::j_relative,constVal); }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -180,6 +180,75 @@ SubtableSymbol *WithBlock::getCurrentSubtable(const list<WithBlock> &stack)
return (SubtableSymbol *)0;
}
void ConsistencyChecker::OptimizeRecord::copyFromExcludingSize(ConsistencyChecker::OptimizeRecord &that)
{
this->writeop = that.writeop;
this->readop = that.readop;
this->inslot = that.inslot;
this->writecount = that.writecount;
this->readcount = that.readcount;
this->writesection = that.writesection;
this->readsection = that.readsection;
this->opttype = that.opttype;
}
void ConsistencyChecker::OptimizeRecord::update(int4 opIdx, int4 slotIdx, int4 secNum)
{
if (slotIdx >= 0) {
updateRead(opIdx, slotIdx, secNum);
}
else {
updateWrite(opIdx, secNum);
}
}
void ConsistencyChecker::OptimizeRecord::updateRead(int4 i, int4 inslot, int4 secNum)
{
this->readop = i;
this->readcount++;
this->inslot = inslot;
this->readsection = secNum;
}
void ConsistencyChecker::OptimizeRecord::updateWrite(int4 i, int4 secNum)
{
this->writeop = i;
this->writecount++;
this->writesection = secNum;
}
void ConsistencyChecker::OptimizeRecord::updateExport()
{
this->writeop = 0;
this->readop = 0;
this->writecount = 2;
this->readcount = 2;
this->readsection = -2;
this->writesection = -2;
}
void ConsistencyChecker::OptimizeRecord::updateCombine(ConsistencyChecker::OptimizeRecord &that)
{
if (that.writecount != 0) {
this->writeop = that.writeop;
this->writesection = that.writesection;
}
if (that.readcount != 0) {
this->readop = that.readop;
this->inslot = that.inslot;
this->readsection = that.readsection;
}
this->writecount += that.writecount;
this->readcount += that.readcount;
// opttype is not relevant here
}
/// \brief Construct the consistency checker and optimizer
///
/// \param sleigh is the parsed SLEIGH spec
@ -1129,6 +1198,90 @@ void ConsistencyChecker::setPostOrder(SubtableSymbol *root)
}
}
map<uintb,ConsistencyChecker::OptimizeRecord>::iterator ConsistencyChecker::UniqueState::lesserIter(uintb offset)
{
if (recs.begin() == recs.end()) {
return recs.end();
}
map<uintb,OptimizeRecord>::iterator iter;
iter = recs.lower_bound(offset);
if (iter == recs.begin()) {
return recs.end();
}
return std::prev(iter);
}
ConsistencyChecker::OptimizeRecord ConsistencyChecker::UniqueState::coalesce(vector<ConsistencyChecker::OptimizeRecord*> &records)
{
uintb minOff = -1;
uintb maxOff = -1;
vector<OptimizeRecord*>::iterator iter;
for (iter = records.begin(); iter != records.end(); ++iter) {
if (minOff == -1 || (*iter)->offset < minOff) {
minOff = (*iter)->offset;
}
if (maxOff == -1 || (*iter)->offset + (*iter)->size > maxOff) {
maxOff = (*iter)->offset + (*iter)->size;
}
}
OptimizeRecord result(minOff, maxOff - minOff);
for (iter = records.begin(); iter != records.end(); ++iter) {
result.updateCombine(**iter);
}
return result;
}
void ConsistencyChecker::UniqueState::set(uintb offset, int4 size, OptimizeRecord &rec)
{
vector<OptimizeRecord*> records;
getDefinitions(records, offset, size);
records.push_back(&rec);
OptimizeRecord coalesced = coalesce(records);
recs.erase(recs.lower_bound(coalesced.offset), recs.lower_bound(coalesced.offset+coalesced.size));
recs.insert(pair<uint4,OptimizeRecord>(coalesced.offset, coalesced));
}
void ConsistencyChecker::UniqueState::getDefinitions(vector<ConsistencyChecker::OptimizeRecord*> &result, uintb offset, int4 size)
{
if (size == 0) {
size = 1;
}
map<uintb,OptimizeRecord>::iterator iter;
iter = lesserIter(offset);
uintb cursor = offset;
if (iter != recs.end() && endOf(iter) > offset) {
OptimizeRecord &preRec = iter->second;
cursor = endOf(iter);
result.push_back(&preRec);
}
uintb end = offset + size;
iter = recs.lower_bound(offset);
while (iter != recs.end() && iter->first < end) {
if (iter->first > cursor) {
// The iterator becomes invalid with this insertion, so take the new one.
iter = recs.insert(pair<uint4,OptimizeRecord>(cursor,OptimizeRecord(cursor, iter->first - cursor))).first;
result.push_back(&iter->second);
iter++; // Put the (now valid) iterator back to where it was.
}
// No need to truncate, as we're just counting a read
result.push_back(&iter->second);
cursor = endOf(iter);
iter++;
}
if (end > cursor) {
iter = recs.insert(pair<uint4,OptimizeRecord>(cursor,OptimizeRecord(cursor, end - cursor))).first;
result.push_back(&iter->second);
}
}
/// \brief Test whether two given Varnodes intersect
///
/// This test must be conservative. If it can't explicitly prove that the
@ -1222,30 +1375,31 @@ bool ConsistencyChecker::readWriteInterference(const VarnodeTpl *vn,const OpTpl
/// If the Varnode is in the \e unique space, an OptimizationRecord for it is looked
/// up based on its offset. Information about how a p-code operator uses the Varnode
/// is accumulated in the record.
/// \param recs is collection of OptimizationRecords associated with temporary Varnodes
/// \param state is collection of OptimizationRecords associated with temporary Varnodes
/// \param vn is the given Varnode to check (which may or may not be temporary)
/// \param i is the index of the operator using the Varnode (within its p-code section)
/// \param inslot is the \e slot index of the Varnode within its operator
/// \param secnum is the section number containing the operator
void ConsistencyChecker::examineVn(map<uintb,OptimizeRecord> &recs,
void ConsistencyChecker::examineVn(UniqueState &state,
const VarnodeTpl *vn,uint4 i,int4 inslot,int4 secnum)
{
if (vn == (const VarnodeTpl *)0) return;
if (!vn->getSpace().isUniqueSpace()) return;
if (vn->getOffset().getType() != ConstTpl::real) return;
map<uintb,OptimizeRecord>::iterator iter;
iter = recs.insert( pair<uint4,OptimizeRecord>(vn->getOffset().getReal(),OptimizeRecord())).first;
if (inslot>=0) {
(*iter).second.readop = i;
(*iter).second.readcount += 1;
(*iter).second.inslot = inslot;
(*iter).second.readsection = secnum;
uintb offset = vn->getOffset().getReal();
int4 size = vn->getSize().getReal();
if (inslot >= 0) {
vector<OptimizeRecord*> defs;
state.getDefinitions(defs,offset,size);
for (vector<OptimizeRecord*>::iterator iter=defs.begin();iter!=defs.end();++iter) {
(*iter)->updateRead(i,inslot,secnum);
}
}
else {
(*iter).second.writeop = i;
(*iter).second.writecount += 1;
(*iter).second.writesection = secnum;
OptimizeRecord rec(offset,size);
rec.updateWrite(i,secnum);
state.set(offset,size,rec);
}
}
@ -1254,9 +1408,9 @@ void ConsistencyChecker::examineVn(map<uintb,OptimizeRecord> &recs,
/// For each temporary Varnode, count how many times it is read from or written to
/// in the given section of p-code operators.
/// \param ct is the given Constructor
/// \param recs is the (initially empty) collection of count records
/// \param state is the (initially empty) collection of count records
/// \param secnum is the given p-code section number
void ConsistencyChecker::optimizeGather1(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const
void ConsistencyChecker::optimizeGather1(Constructor *ct,UniqueState &state,int4 secnum) const
{
ConstructTpl *tpl;
@ -1271,10 +1425,10 @@ void ConsistencyChecker::optimizeGather1(Constructor *ct,map<uintb,OptimizeRecor
const OpTpl *op = ops[i];
for(uint4 j=0;j<op->numInput();++j) {
const VarnodeTpl *vnin = op->getIn(j);
examineVn(recs,vnin,i,j,secnum);
examineVn(state,vnin,i,j,secnum);
}
const VarnodeTpl *vn = op->getOut();
examineVn(recs,vn,i,-1,secnum);
examineVn(state,vn,i,-1,secnum);
}
}
@ -1284,9 +1438,9 @@ void ConsistencyChecker::optimizeGather1(Constructor *ct,map<uintb,OptimizeRecor
/// for the section, and if it involves a temporary, mark it as both read and written, guaranteeing
/// that the Varnode is not optimized away.
/// \param ct is the given Constructor
/// \param recs is the collection of count records
/// \param state is the collection of count records
/// \param secnum is the given p-code section number
void ConsistencyChecker::optimizeGather2(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const
void ConsistencyChecker::optimizeGather2(Constructor *ct,UniqueState &state,int4 secnum) const
{
ConstructTpl *tpl;
@ -1300,29 +1454,29 @@ void ConsistencyChecker::optimizeGather2(Constructor *ct,map<uintb,OptimizeRecor
if (hand == (HandleTpl *)0) return;
if (hand->getPtrSpace().isUniqueSpace()) {
if (hand->getPtrOffset().getType() == ConstTpl::real) {
pair<map<uintb,OptimizeRecord>::iterator,bool> res;
uintb offset = hand->getPtrOffset().getReal();
res = recs.insert( pair<uintb,OptimizeRecord>(offset,OptimizeRecord()));
(*res.first).second.writeop = 0;
(*res.first).second.readop = 0;
(*res.first).second.writecount = 2;
(*res.first).second.readcount = 2;
(*res.first).second.readsection = -2;
(*res.first).second.writesection = -2;
int4 size = hand->getPtrSize().getReal();
vector<OptimizeRecord*> defs;
state.getDefinitions(defs,offset,size);
for (vector<OptimizeRecord*>::iterator iter=defs.begin();iter!=defs.end();++iter) {
(*iter)->updateExport();
// NOTE: Could this just be updateRead?
// Technically, an exported handle could be written by the parent....
}
}
}
if (hand->getSpace().isUniqueSpace()) {
if ((hand->getPtrSpace().getType() == ConstTpl::real)&&
(hand->getPtrOffset().getType() == ConstTpl::real)) {
pair<map<uintb,OptimizeRecord>::iterator,bool> res;
uintb offset = hand->getPtrOffset().getReal();
res = recs.insert( pair<uintb,OptimizeRecord>(offset,OptimizeRecord()));
(*res.first).second.writeop = 0;
(*res.first).second.readop = 0;
(*res.first).second.writecount = 2;
(*res.first).second.readcount = 2;
(*res.first).second.readsection = -2;
(*res.first).second.writesection = -2;
int4 size = hand->getPtrSize().getReal();
vector<OptimizeRecord*> defs;
state.getDefinitions(defs,offset,size);
for (vector<OptimizeRecord*>::iterator iter=defs.begin();iter!=defs.end();++iter) {
(*iter)->updateExport();
// NOTE: Could this just be updateRead?
// Technically, an exported handle could be written by the parent....
}
}
}
}
@ -1336,14 +1490,14 @@ void ConsistencyChecker::optimizeGather2(Constructor *ct,map<uintb,OptimizeRecor
/// if propagation is forward, the Varnode must not cross another write.
/// If all the requirements pass, return the record indicating that the COPY can be removed.
/// \param ct is the Constructor owning the p-code
/// \param recs is the collection of OptimizeRecords to search
/// \param state is the collection of OptimizeRecords to search
/// \return a passing OptimizeRecord or null
const ConsistencyChecker::OptimizeRecord *ConsistencyChecker::findValidRule(Constructor *ct,
const map<uintb,OptimizeRecord> &recs) const
const UniqueState &state) const
{
map<uintb,OptimizeRecord>::const_iterator iter;
iter = recs.begin();
while(iter != recs.end()) {
iter = state.begin();
while(iter!=state.end()) {
const OptimizeRecord &currec( (*iter).second );
++iter;
if ((currec.writecount==1)&&(currec.readcount==1)&&(currec.readsection==currec.writesection)) {
@ -1354,13 +1508,27 @@ const ConsistencyChecker::OptimizeRecord *ConsistencyChecker::findValidRule(Cons
else
tpl = ct->getNamedTempl(currec.readsection);
const vector<OpTpl *> &ops( tpl->getOpvec() );
const OpTpl *op = ops[ currec.readop ];
const OpTpl *writeop = ops[ currec.writeop ];
const OpTpl *readop = ops[ currec.readop ];
if (currec.writeop >= currec.readop) // Read must come after write
throw SleighError("Read of temporary before write");
if (op->getOpcode() == CPUI_COPY) {
VarnodeTpl *writevn = writeop->getOut();
VarnodeTpl *readvn = readop->getIn(currec.inslot);
// Because the record can change size and position, we have to check if the varnode
// "connecting" the write and read ops is actually the same varnode. If not, then we can't
// optimize it out.
// There may be an opportunity here to re-write the size/offset when either the write or read
// op is a COPY, but I'll leave that for later discussion.
// Actually, maybe not. If the truncate would be of a handle, we can't.
if (*writevn != *readvn) {
continue;
}
if (readop->getOpcode() == CPUI_COPY) {
bool saverecord = true;
currec.opttype = 0; // Read op is a COPY
const VarnodeTpl *vn = op->getOut();
const VarnodeTpl *vn = readop->getOut();
for(int4 i=currec.writeop+1;i<currec.readop;++i) { // Check for interference between write and read
if (readWriteInterference(vn,ops[i],true)) {
saverecord = false;
@ -1370,11 +1538,10 @@ const ConsistencyChecker::OptimizeRecord *ConsistencyChecker::findValidRule(Cons
if (saverecord)
return &currec;
}
op = ops[ currec.writeop ];
if (op->getOpcode() == CPUI_COPY) {
if (writeop->getOpcode() == CPUI_COPY) {
bool saverecord = true;
currec.opttype = 1; // Write op is a COPY
const VarnodeTpl *vn = op->getIn(0);
const VarnodeTpl *vn = writeop->getIn(0);
for(int4 i=currec.writeop+1;i<currec.readop;++i) { // Check for interference between write and read
if (readWriteInterference(vn,ops[i],false)) {
saverecord = false;
@ -1431,13 +1598,13 @@ void ConsistencyChecker::applyOptimization(Constructor *ct,const OptimizeRecord
/// An error message is issued if a temporary is read but not written.
/// A warning may be issued if a temporary is written but not read.
/// \param ct is the Constructor
/// \param recs is the collection of records associated with each temporary Varnode
void ConsistencyChecker::checkUnusedTemps(Constructor *ct,const map<uintb,OptimizeRecord> &recs)
/// \param state is the collection of records associated with each temporary Varnode
void ConsistencyChecker::checkUnusedTemps(Constructor *ct,const UniqueState &state)
{
map<uintb,OptimizeRecord>::const_iterator iter;
iter = recs.begin();
while(iter != recs.end()) {
iter = state.begin();
while(iter != state.end()) {
const OptimizeRecord &currec( (*iter).second );
if (currec.readcount == 0) {
if (printdeadwarning)
@ -1485,19 +1652,19 @@ void ConsistencyChecker::optimize(Constructor *ct)
{
const OptimizeRecord *currec;
map<uintb,OptimizeRecord> recs;
UniqueState state;
int4 numsections = ct->getNumSections();
do {
recs.clear();
state.clear();
for(int4 i=-1;i<numsections;++i) {
optimizeGather1(ct,recs,i);
optimizeGather2(ct,recs,i);
optimizeGather1(ct,state,i);
optimizeGather2(ct,state,i);
}
currec = findValidRule(ct,recs);
currec = findValidRule(ct,state);
if (currec != (const OptimizeRecord *)0)
applyOptimization(ct,*currec);
} while(currec != (const OptimizeRecord *)0);
checkUnusedTemps(ct,recs);
checkUnusedTemps(ct,state);
}
/// Warnings or errors for individual violations may be printed, depending on settings.
@ -1589,6 +1756,13 @@ void ConsistencyChecker::optimizeAll(void)
}
}
ostream& operator<<(ostream &os, const ConsistencyChecker::OptimizeRecord &rec) {
os << "{writeop=" << rec.writeop << " readop=" << rec.readop << " inslot=" << rec.inslot <<
" writecount=" << rec.writecount << " readcount=" << rec.readcount <<
" opttype=" << rec.opttype << "}";
return os;
}
/// Sort based on the containing Varnode, then on the bit boundary
/// \param op2 is a field to compare with \b this
/// \return \b true if \b this should be sorted before the other field

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -23,12 +23,14 @@
#include "filemanage.hh"
#include <iostream>
#include <sstream>
#include <string>
namespace ghidra {
using std::cout;
using std::cerr;
using std::out_of_range;
using std::string;
/// \brief A helper class to associate a \e named Constructor section with its symbol scope
///
@ -137,26 +139,51 @@ class SleighCompile;
/// This class searches for unnecessary truncations and extensions, temporary varnodes that are either dead,
/// read before written, or that exceed the standard allocation size.
class ConsistencyChecker {
public:
/// \brief Description of how a temporary register is being used within a Constructor
///
/// This counts reads and writes of the register. If the register is read only once, the
/// particular p-code op and input slot reading it is recorded. If the register is written
/// only once, the particular p-code op writing it is recorded.
struct OptimizeRecord {
int4 writeop; ///< Index of the (last) p-code op writing to register (or -1)
int4 readop; ///< Index of the (last) p-code op reading the register (or -1)
int4 inslot; ///< Input slot of p-code op reading the register (or -1)
int4 writecount; ///< Number of times the register is written
int4 readcount; ///< Number of times the register is read
int4 writesection; ///< Section containing (last) p-code op writing to the register (or -2)
int4 readsection; ///< Section containing (last) p-code op reading the register (or -2)
mutable int4 opttype; ///< 0 = register read by a COPY, 1 = register written by a COPY (-1 otherwise)
uintb offset; ///< Offset of the varnode address
int4 size; ///< Size in bytes of the varnode or piece (immutable)
int4 writeop; ///< Index of the (last) p-code op writing to register (or -1)
int4 readop; ///< Index of the (last) p-code op reading the register (or -1)
int4 inslot; ///< Input slot of p-code op reading the register (or -1)
int4 writecount; ///< Number of times the register is written
int4 readcount; ///< Number of times the register is read
int4 writesection; ///< Section containing (last) p-code op writing to the register (or -2)
int4 readsection; ///< Section containing (last) p-code op reading the register (or -2)
mutable int4 opttype; ///< 0 = register read by a COPY, 1 = register written by a COPY (-1 otherwise)
/// \brief Construct a record, initializing counts
OptimizeRecord(void) {
writeop = -1; readop = -1; inslot=-1; writecount=0; readcount=0; writesection=-2; readsection=-2; opttype=-1; }
OptimizeRecord(uintb offset, int4 size) {
this->offset = offset;
this->size = size;
writeop = -1; readop = -1; inslot=-1; writecount=0; readcount=0; writesection=-2; readsection=-2; opttype=-1;
}
void copyFromExcludingSize(OptimizeRecord &that);
void update(int4 opIdx, int4 slotIdx, int4 secNum);
void updateRead(int4 i, int4 inslot, int4 secNum);
void updateWrite(int4 i, int4 secNum);
void updateExport();
void updateCombine(OptimizeRecord &that);
};
private:
class UniqueState {
map<uintb,OptimizeRecord> recs;
static uintb endOf(map<uintb,OptimizeRecord>::iterator &iter) { return iter->first + iter->second.size; }
OptimizeRecord coalesce(vector<OptimizeRecord*> &records);
map<uintb,OptimizeRecord>::iterator lesserIter(uintb offset);
public:
void clear(void) { recs.clear(); }
void set(uintb offset, int4 size, OptimizeRecord &rec);
void getDefinitions(vector<OptimizeRecord*> &result, uintb offset, int4 size);
map<uintb,OptimizeRecord>::const_iterator begin(void) const { return recs.begin(); }
map<uintb,OptimizeRecord>::const_iterator end(void) const { return recs.end(); }
};
SleighCompile *compiler; ///< Parsed form of the SLEIGH file being examined
int4 unnecessarypcode; ///< Count of unnecessary extension/truncation operations
int4 readnowrite; ///< Count of temporary registers that are read but not written
@ -185,14 +212,14 @@ class ConsistencyChecker {
void setPostOrder(SubtableSymbol *root);
// Optimization routines
static void examineVn(map<uintb,OptimizeRecord> &recs,const VarnodeTpl *vn,uint4 i,int4 inslot,int4 secnum);
static void examineVn(UniqueState &state,const VarnodeTpl *vn,uint4 i,int4 inslot,int4 secnum);
static bool possibleIntersection(const VarnodeTpl *vn1,const VarnodeTpl *vn2);
bool readWriteInterference(const VarnodeTpl *vn,const OpTpl *op,bool checkread) const;
void optimizeGather1(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const;
void optimizeGather2(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const;
const OptimizeRecord *findValidRule(Constructor *ct,const map<uintb,OptimizeRecord> &recs) const;
void optimizeGather1(Constructor *ct,UniqueState &state,int4 secnum) const;
void optimizeGather2(Constructor *ct,UniqueState &state,int4 secnum) const;
const OptimizeRecord *findValidRule(Constructor *ct,const UniqueState &state) const;
void applyOptimization(Constructor *ct,const OptimizeRecord &rec);
void checkUnusedTemps(Constructor *ct,const map<uintb,OptimizeRecord> &recs);
void checkUnusedTemps(Constructor *ct,const UniqueState &state);
void checkLargeTemporaries(Constructor *ct,ConstructTpl *ctpl);
void optimize(Constructor *ct);
public:
@ -458,6 +485,8 @@ public:
int4 run_compilation(const string &filein,const string &fileout);
};
ostream& operator<<(ostream &os, const ConsistencyChecker::OptimizeRecord &rec);
extern SleighCompile *slgh; ///< A global reference to the SLEIGH compiler accessible to the parse functions
extern int yydebug; ///< Debug state for the SLEIGH parse functions