mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-2559 Calculate maximum precision reaching floating-point operations
This commit is contained in:
parent
be305db930
commit
520dc99b11
15 changed files with 602 additions and 57 deletions
|
@ -23,6 +23,7 @@ src/decompile/datatests/displayformat.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/divopt.xml||GHIDRA||||END|
|
src/decompile/datatests/divopt.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
|
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/elseif.xml||GHIDRA||||END|
|
src/decompile/datatests/elseif.xml||GHIDRA||||END|
|
||||||
|
src/decompile/datatests/floatcast.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/floatprint.xml||GHIDRA||||END|
|
src/decompile/datatests/floatprint.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/forloop1.xml||GHIDRA||||END|
|
src/decompile/datatests/forloop1.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/forloop_loaditer.xml||GHIDRA||||END|
|
src/decompile/datatests/forloop_loaditer.xml||GHIDRA||||END|
|
||||||
|
|
|
@ -563,7 +563,10 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi
|
||||||
if (mode < 2)
|
if (mode < 2)
|
||||||
collectLaneSizes(vn,lanedRegister,checkLanes);
|
collectLaneSizes(vn,lanedRegister,checkLanes);
|
||||||
else {
|
else {
|
||||||
checkLanes.addLaneSize(4); // Default lane size
|
int4 defaultSize = data.getArch()->types->getSizeOfPointer(); // Default lane size
|
||||||
|
if (defaultSize != 4)
|
||||||
|
defaultSize = 8;
|
||||||
|
checkLanes.addLaneSize(defaultSize);
|
||||||
}
|
}
|
||||||
LanedRegister::const_iterator enditer = checkLanes.end();
|
LanedRegister::const_iterator enditer = checkLanes.end();
|
||||||
for(LanedRegister::const_iterator iter=checkLanes.begin();iter!=enditer;++iter) {
|
for(LanedRegister::const_iterator iter=checkLanes.begin();iter!=enditer;++iter) {
|
||||||
|
@ -582,6 +585,7 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi
|
||||||
int4 ActionLaneDivide::apply(Funcdata &data)
|
int4 ActionLaneDivide::apply(Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
data.setLanedRegGenerated();
|
||||||
map<VarnodeData,const LanedRegister *>::const_iterator iter;
|
map<VarnodeData,const LanedRegister *>::const_iterator iter;
|
||||||
for(int4 mode=0;mode<3;++mode) {
|
for(int4 mode=0;mode<3;++mode) {
|
||||||
bool allStorageProcessed = true;
|
bool allStorageProcessed = true;
|
||||||
|
@ -594,6 +598,10 @@ int4 ActionLaneDivide::apply(Funcdata &data)
|
||||||
bool allVarnodesProcessed = true;
|
bool allVarnodesProcessed = true;
|
||||||
while(viter != venditer) {
|
while(viter != venditer) {
|
||||||
Varnode *vn = *viter;
|
Varnode *vn = *viter;
|
||||||
|
if (vn->hasNoDescend()) {
|
||||||
|
++viter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (processVarnode(data, vn, *lanedReg, mode)) {
|
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
|
||||||
|
@ -610,7 +618,6 @@ int4 ActionLaneDivide::apply(Funcdata &data)
|
||||||
if (allStorageProcessed) break;
|
if (allStorageProcessed) break;
|
||||||
}
|
}
|
||||||
data.clearLanedAccessMap();
|
data.clearLanedAccessMap();
|
||||||
data.setLanedRegGenerated();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1337,7 +1344,6 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.setLanedRegGenerated();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5515,6 +5521,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||||
actprop->addRule( new RuleOrMultiBool("analysis") );
|
actprop->addRule( new RuleOrMultiBool("analysis") );
|
||||||
actprop->addRule( new RuleXorSwap("analysis") );
|
actprop->addRule( new RuleXorSwap("analysis") );
|
||||||
actprop->addRule( new RuleLzcountShiftBool("analysis") );
|
actprop->addRule( new RuleLzcountShiftBool("analysis") );
|
||||||
|
actprop->addRule( new RuleFloatSign("analysis") );
|
||||||
actprop->addRule( new RuleSubvarAnd("subvar") );
|
actprop->addRule( new RuleSubvarAnd("subvar") );
|
||||||
actprop->addRule( new RuleSubvarSubpiece("subvar") );
|
actprop->addRule( new RuleSubvarSubpiece("subvar") );
|
||||||
actprop->addRule( new RuleSplitFlow("subvar") );
|
actprop->addRule( new RuleSplitFlow("subvar") );
|
||||||
|
@ -5591,6 +5598,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||||
actcleanup->addRule( new RuleAddUnsigned("cleanup") );
|
actcleanup->addRule( new RuleAddUnsigned("cleanup") );
|
||||||
actcleanup->addRule( new Rule2Comp2Sub("cleanup") );
|
actcleanup->addRule( new Rule2Comp2Sub("cleanup") );
|
||||||
actcleanup->addRule( new RuleSubRight("cleanup") );
|
actcleanup->addRule( new RuleSubRight("cleanup") );
|
||||||
|
actcleanup->addRule( new RuleFloatSignCleanup("cleanup") );
|
||||||
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
|
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
|
||||||
actcleanup->addRule( new RuleExtensionPush("cleanup") );
|
actcleanup->addRule( new RuleExtensionPush("cleanup") );
|
||||||
actcleanup->addRule( new RulePieceStructure("cleanup") );
|
actcleanup->addRule( new RulePieceStructure("cleanup") );
|
||||||
|
|
|
@ -217,8 +217,9 @@ uintb FloatFormat::getNaNEncoding(bool sgn) const
|
||||||
void FloatFormat::calcPrecision(void)
|
void FloatFormat::calcPrecision(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
float val = frac_size * 0.30103;
|
decimalMinPrecision = (int4)floor(frac_size * 0.30103);
|
||||||
decimal_precision = (int4)floor(val + 0.5);
|
// Precision needed to guarantee IEEE 754 binary -> decimal -> binary round trip conversion
|
||||||
|
decimalMaxPrecision = (int4)ceil((frac_size + 1) * 0.30103) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param encoding is the encoding value
|
/// \param encoding is the encoding value
|
||||||
|
@ -417,6 +418,47 @@ uintb FloatFormat::convertEncoding(uintb encoding,
|
||||||
return setSign(res, sgn);
|
return setSign(res, sgn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The string should be printed with the minimum number of digits to uniquely specify the underlying
|
||||||
|
/// binary value. This currently only works for the 32-bit and 64-bit IEEE 754 formats.
|
||||||
|
/// If the \b forcesci parameter is \b true, the string will always be printed using scientific notation.
|
||||||
|
/// \param host is the given value already converted to the host's \b double format.
|
||||||
|
/// \param forcesci is \b true if the value should be printed in scientific notation.
|
||||||
|
/// \return the decimal representation as a string
|
||||||
|
string FloatFormat::printDecimal(double host,bool forcesci) const
|
||||||
|
|
||||||
|
{
|
||||||
|
string res;
|
||||||
|
for(int4 prec=decimalMinPrecision;;++prec) {
|
||||||
|
ostringstream s;
|
||||||
|
if (forcesci) {
|
||||||
|
s.setf( ios::scientific ); // Set to scientific notation
|
||||||
|
s.precision(prec-1); // scientific doesn't include first digit in precision count
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.unsetf( ios::floatfield ); // Use "default" notation to allow fewer digits to be printed if possible
|
||||||
|
s.precision(prec);
|
||||||
|
}
|
||||||
|
s << host;
|
||||||
|
if (prec == decimalMaxPrecision) {
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
res = s.str();
|
||||||
|
double roundtrip = 0.0;
|
||||||
|
istringstream t(res);
|
||||||
|
if (size <= 4) {
|
||||||
|
float tmp = 0.0;
|
||||||
|
t >> tmp;
|
||||||
|
roundtrip = tmp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t >> roundtrip;
|
||||||
|
}
|
||||||
|
if (roundtrip == host)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// Currently we emulate floating point operations on the target
|
// Currently we emulate floating point operations on the target
|
||||||
// By converting the encoding to the host's encoding and then
|
// By converting the encoding to the host's encoding and then
|
||||||
// performing the operation using the host's floating point unit
|
// performing the operation using the host's floating point unit
|
||||||
|
|
|
@ -48,7 +48,8 @@ private:
|
||||||
int4 exp_size; ///< Number of bits in exponent
|
int4 exp_size; ///< Number of bits in exponent
|
||||||
int4 bias; ///< What to add to real exponent to get encoding
|
int4 bias; ///< What to add to real exponent to get encoding
|
||||||
int4 maxexponent; ///< Maximum possible exponent
|
int4 maxexponent; ///< Maximum possible exponent
|
||||||
int4 decimal_precision; ///< Number of decimal digits of precision
|
int4 decimalMinPrecision; ///< Minimum decimal digits of precision guaranteed by the format
|
||||||
|
int4 decimalMaxPrecision; ///< Maximum decimal digits of precision needed to uniquely represent value
|
||||||
bool jbitimplied; ///< Set to \b true if integer bit of 1 is assumed
|
bool jbitimplied; ///< Set to \b true if integer bit of 1 is assumed
|
||||||
static double createFloat(bool sign,uintb signif,int4 exp); ///< Create a double given sign, fractional, and exponent
|
static double createFloat(bool sign,uintb signif,int4 exp); ///< Create a double given sign, fractional, and exponent
|
||||||
static floatclass extractExpSig(double x,bool *sgn,uintb *signif,int4 *exp);
|
static floatclass extractExpSig(double x,bool *sgn,uintb *signif,int4 *exp);
|
||||||
|
@ -65,13 +66,14 @@ public:
|
||||||
int4 getSize(void) const { return size; } ///< Get the size of the encoding in bytes
|
int4 getSize(void) const { return size; } ///< Get the size of the encoding in bytes
|
||||||
double getHostFloat(uintb encoding,floatclass *type) const; ///< Convert an encoding into host's double
|
double getHostFloat(uintb encoding,floatclass *type) const; ///< Convert an encoding into host's double
|
||||||
uintb getEncoding(double host) const; ///< Convert host's double into \b this encoding
|
uintb getEncoding(double host) const; ///< Convert host's double into \b this encoding
|
||||||
int4 getDecimalPrecision(void) const { return decimal_precision; } ///< Get number of digits of precision
|
|
||||||
uintb convertEncoding(uintb encoding,const FloatFormat *formin) const; ///< Convert between two different formats
|
uintb convertEncoding(uintb encoding,const FloatFormat *formin) const; ///< Convert between two different formats
|
||||||
|
|
||||||
uintb extractFractionalCode(uintb x) const; ///< Extract the fractional part of the encoding
|
uintb extractFractionalCode(uintb x) const; ///< Extract the fractional part of the encoding
|
||||||
bool extractSign(uintb x) const; ///< Extract the sign bit from the encoding
|
bool extractSign(uintb x) const; ///< Extract the sign bit from the encoding
|
||||||
int4 extractExponentCode(uintb x) const; ///< Extract the exponent from the encoding
|
int4 extractExponentCode(uintb x) const; ///< Extract the exponent from the encoding
|
||||||
|
|
||||||
|
string printDecimal(double host,bool forcesci) const; ///< Print given value as a decimal string
|
||||||
|
|
||||||
// Operations on floating point values
|
// Operations on floating point values
|
||||||
|
|
||||||
uintb opEqual(uintb a,uintb b) const; ///< Equality comparison (==)
|
uintb opEqual(uintb a,uintb b) const; ///< Equality comparison (==)
|
||||||
|
|
|
@ -1388,19 +1388,11 @@ void PrintC::push_float(uintb val,int4 sz,tagtype tag,const Varnode *vn,const Pc
|
||||||
token = "NAN";
|
token = "NAN";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ostringstream t;
|
|
||||||
if ((mods & force_scinote)!=0) {
|
if ((mods & force_scinote)!=0) {
|
||||||
t.setf( ios::scientific ); // Set to scientific notation
|
token = format->printDecimal(floatval, true);
|
||||||
t.precision(format->getDecimalPrecision()-1);
|
|
||||||
t << floatval;
|
|
||||||
token = t.str();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Try to print "minimal" accurate representation of the float
|
token = format->printDecimal(floatval, false);
|
||||||
t.unsetf( ios::floatfield ); // Use "default" notation
|
|
||||||
t.precision(format->getDecimalPrecision());
|
|
||||||
t << floatval;
|
|
||||||
token = t.str();
|
|
||||||
bool looksLikeFloat = false;
|
bool looksLikeFloat = false;
|
||||||
for(int4 i=0;i<token.size();++i) {
|
for(int4 i=0;i<token.size();++i) {
|
||||||
char c = token[i];
|
char c = token[i];
|
||||||
|
|
|
@ -10453,4 +10453,93 @@ int4 RuleLzcountShiftBool::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \class RuleFloatSign
|
||||||
|
/// \brief Convert floating-point \e sign bit manipulation into FLOAT_ABS or FLOAT_NEG
|
||||||
|
///
|
||||||
|
/// Transform floating-point specific operations
|
||||||
|
/// -- `x & 0x7fffffff => ABS(f)`
|
||||||
|
/// -- 'x ^ 0x80000000 => -f`
|
||||||
|
///
|
||||||
|
/// A Varnode is determined to be floating-point by participation in other floating-point operations,
|
||||||
|
/// not based on the data-type of the Varnode.
|
||||||
|
void RuleFloatSign::getOpList(vector<uint4> &oplist) const
|
||||||
|
|
||||||
|
{
|
||||||
|
uint4 list[] = { CPUI_FLOAT_EQUAL, CPUI_FLOAT_NOTEQUAL, CPUI_FLOAT_LESS, CPUI_FLOAT_LESSEQUAL, CPUI_FLOAT_NAN,
|
||||||
|
CPUI_FLOAT_ADD, CPUI_FLOAT_DIV, CPUI_FLOAT_MULT, CPUI_FLOAT_SUB, CPUI_FLOAT_NEG, CPUI_FLOAT_ABS,
|
||||||
|
CPUI_FLOAT_SQRT, CPUI_FLOAT_FLOAT2FLOAT, CPUI_FLOAT_CEIL, CPUI_FLOAT_FLOOR, CPUI_FLOAT_ROUND,
|
||||||
|
CPUI_FLOAT_INT2FLOAT, CPUI_FLOAT_TRUNC };
|
||||||
|
oplist.insert(oplist.end(),list,list+18);
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 RuleFloatSign::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 res = 0;
|
||||||
|
OpCode opc = op->code();
|
||||||
|
if (opc != CPUI_FLOAT_INT2FLOAT) {
|
||||||
|
Varnode *vn = op->getIn(0);
|
||||||
|
if (vn->isWritten()) {
|
||||||
|
PcodeOp *signOp = vn->getDef();
|
||||||
|
OpCode resCode = TypeOp::floatSignManipulation(signOp);
|
||||||
|
if (resCode != CPUI_MAX) {
|
||||||
|
data.opRemoveInput(signOp, 1);
|
||||||
|
data.opSetOpcode(signOp, resCode);
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (op->numInput() == 2) {
|
||||||
|
vn = op->getIn(1);
|
||||||
|
if (vn->isWritten()) {
|
||||||
|
PcodeOp *signOp = vn->getDef();
|
||||||
|
OpCode resCode = TypeOp::floatSignManipulation(signOp);
|
||||||
|
if (resCode != CPUI_MAX) {
|
||||||
|
data.opRemoveInput(signOp, 1);
|
||||||
|
data.opSetOpcode(signOp, resCode);
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (op->isBoolOutput() || opc == CPUI_FLOAT_TRUNC)
|
||||||
|
return res;
|
||||||
|
list<PcodeOp *>::const_iterator iter;
|
||||||
|
Varnode *outvn = op->getOut();
|
||||||
|
for(iter=outvn->beginDescend();iter!=outvn->endDescend();++iter) {
|
||||||
|
PcodeOp *readOp = *iter;
|
||||||
|
OpCode resCode = TypeOp::floatSignManipulation(readOp);
|
||||||
|
if (resCode != CPUI_MAX) {
|
||||||
|
data.opRemoveInput(readOp, 1);
|
||||||
|
data.opSetOpcode(readOp, resCode);
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \class RuleFloatSignCleanup
|
||||||
|
/// \brief Convert floating-point \e sign bit manipulation into FLOAT_ABS or FLOAT_NEG
|
||||||
|
///
|
||||||
|
/// A Varnode is determined to be floating-point by examining its data-type.
|
||||||
|
void RuleFloatSignCleanup::getOpList(vector<uint4> &oplist) const
|
||||||
|
|
||||||
|
{
|
||||||
|
oplist.push_back(CPUI_INT_AND);
|
||||||
|
oplist.push_back(CPUI_INT_XOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 RuleFloatSignCleanup::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (op->getOut()->getType()->getMetatype() != TYPE_FLOAT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
OpCode opc = TypeOp::floatSignManipulation(op);
|
||||||
|
if (opc == CPUI_MAX)
|
||||||
|
return 0;
|
||||||
|
data.opRemoveInput(op, 1);
|
||||||
|
data.opSetOpcode(op, opc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
} // End namespace ghidra
|
} // End namespace ghidra
|
||||||
|
|
|
@ -1644,5 +1644,27 @@ public:
|
||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RuleFloatSign : public Rule {
|
||||||
|
public:
|
||||||
|
RuleFloatSign(const string &g) : Rule( g, 0, "floatsign") {} ///< Constructor
|
||||||
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
|
if (!grouplist.contains(getGroup())) return (Rule *)0;
|
||||||
|
return new RuleFloatSign(getGroup());
|
||||||
|
}
|
||||||
|
virtual void getOpList(vector<uint4> &oplist) const;
|
||||||
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RuleFloatSignCleanup : public Rule {
|
||||||
|
public:
|
||||||
|
RuleFloatSignCleanup(const string &g) : Rule( g, 0, "floatsigncleanup") {} ///< Constructor
|
||||||
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
|
if (!grouplist.contains(getGroup())) return (Rule *)0;
|
||||||
|
return new RuleFloatSignCleanup(getGroup());
|
||||||
|
}
|
||||||
|
virtual void getOpList(vector<uint4> &oplist) const;
|
||||||
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
|
};
|
||||||
|
|
||||||
} // End namespace ghidra
|
} // End namespace ghidra
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -34,10 +34,13 @@ AttributeId ATTRIB_PIECE = AttributeId("piece",94); // Open slots 94-102
|
||||||
void AddrSpace::calcScaleMask(void)
|
void AddrSpace::calcScaleMask(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
pointerLowerBound = (addressSize < 3) ? 0x100: 0x1000;
|
|
||||||
highest = calc_mask(addressSize); // Maximum address
|
highest = calc_mask(addressSize); // Maximum address
|
||||||
highest = highest * wordsize + (wordsize-1); // Maximum byte address
|
highest = highest * wordsize + (wordsize-1); // Maximum byte address
|
||||||
|
pointerLowerBound = 0;
|
||||||
pointerUpperBound = highest;
|
pointerUpperBound = highest;
|
||||||
|
uintb bufferSize = (addressSize < 3) ? 0x100 : 0x1000;
|
||||||
|
pointerLowerBound += bufferSize;
|
||||||
|
pointerUpperBound -= bufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize an address space with its basic attributes
|
/// Initialize an address space with its basic attributes
|
||||||
|
|
|
@ -2567,7 +2567,133 @@ Datatype *SplitDatatype::getValueDatatype(PcodeOp *loadStore,int4 size,TypeFacto
|
||||||
}
|
}
|
||||||
else if (metain == TYPE_STRUCT || metain == TYPE_ARRAY)
|
else if (metain == TYPE_STRUCT || metain == TYPE_ARRAY)
|
||||||
return tlst->getExactPiece(resType, baseOffset, size);
|
return tlst->getExactPiece(resType, baseOffset, size);
|
||||||
return (Datatype *)0;}
|
return (Datatype *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method distinguishes between a floating-point variable with \e full precision, where all the
|
||||||
|
/// storage can vary (or is unknown), versus a value that is extended from a floating-point variable with
|
||||||
|
/// smaller storage. Within the data-flow above the given Varnode, we search for the maximum
|
||||||
|
/// precision coming through MULTIEQUAL, COPY, and unary floating-point operations. Binary operations
|
||||||
|
/// like FLOAT_ADD and FLOAT_MULT are not traversed and are assumed to produce a smaller precision.
|
||||||
|
/// If the method indicates \e full precision for the given Varnode, or if the data-flow does not involve
|
||||||
|
/// binary floating-point operations, it is accurate, otherwise it may under report the precision.
|
||||||
|
/// \param vn is the given Varnode
|
||||||
|
/// \return an approximation of the maximum precision
|
||||||
|
int4 SubfloatFlow::maxPrecision(Varnode *vn)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!vn->isWritten())
|
||||||
|
return vn->getSize();
|
||||||
|
PcodeOp *op = vn->getDef();
|
||||||
|
switch(op->code()) {
|
||||||
|
case CPUI_MULTIEQUAL:
|
||||||
|
case CPUI_FLOAT_NEG:
|
||||||
|
case CPUI_FLOAT_ABS:
|
||||||
|
case CPUI_FLOAT_SQRT:
|
||||||
|
case CPUI_FLOAT_CEIL:
|
||||||
|
case CPUI_FLOAT_FLOOR:
|
||||||
|
case CPUI_FLOAT_ROUND:
|
||||||
|
case CPUI_COPY:
|
||||||
|
break;
|
||||||
|
case CPUI_FLOAT_ADD:
|
||||||
|
case CPUI_FLOAT_SUB:
|
||||||
|
case CPUI_FLOAT_MULT:
|
||||||
|
case CPUI_FLOAT_DIV:
|
||||||
|
return 0; // Delay checking other binary ops
|
||||||
|
case CPUI_FLOAT_FLOAT2FLOAT:
|
||||||
|
case CPUI_FLOAT_INT2FLOAT: // Treat integer as having precision matching its size
|
||||||
|
if (op->getIn(0)->getSize() > vn->getSize())
|
||||||
|
return vn->getSize();
|
||||||
|
return op->getIn(0)->getSize();
|
||||||
|
default:
|
||||||
|
return vn->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
map<PcodeOp *,int4>::const_iterator iter = maxPrecisionMap.find(op);
|
||||||
|
if (iter != maxPrecisionMap.end()) {
|
||||||
|
return (*iter).second;
|
||||||
|
}
|
||||||
|
vector<State> opStack;
|
||||||
|
opStack.emplace_back(op);
|
||||||
|
op->setMark();
|
||||||
|
int4 max = 0;
|
||||||
|
while(!opStack.empty()) {
|
||||||
|
State &state(opStack.back());
|
||||||
|
if (state.slot >= state.op->numInput()) {
|
||||||
|
max = state.maxPrecision;
|
||||||
|
state.op->clearMark();
|
||||||
|
maxPrecisionMap[state.op] = state.maxPrecision;
|
||||||
|
opStack.pop_back();
|
||||||
|
if (!opStack.empty()) {
|
||||||
|
opStack.back().incorporateInputSize(max);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Varnode *nextVn = state.op->getIn(state.slot);
|
||||||
|
state.slot += 1;
|
||||||
|
if (!nextVn->isWritten()) {
|
||||||
|
state.incorporateInputSize(nextVn->getSize());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PcodeOp *nextOp = nextVn->getDef();
|
||||||
|
if (nextOp->isMark()) {
|
||||||
|
continue; // Truncate the cycle edge
|
||||||
|
}
|
||||||
|
switch(nextOp->code()) {
|
||||||
|
case CPUI_MULTIEQUAL:
|
||||||
|
case CPUI_FLOAT_NEG:
|
||||||
|
case CPUI_FLOAT_ABS:
|
||||||
|
case CPUI_FLOAT_SQRT:
|
||||||
|
case CPUI_FLOAT_CEIL:
|
||||||
|
case CPUI_FLOAT_FLOOR:
|
||||||
|
case CPUI_FLOAT_ROUND:
|
||||||
|
case CPUI_COPY:
|
||||||
|
iter = maxPrecisionMap.find(nextOp);
|
||||||
|
if (iter != maxPrecisionMap.end()) {
|
||||||
|
// Seen the op before, incorporate its cached precision information
|
||||||
|
state.incorporateInputSize((*iter).second);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nextOp->setMark();
|
||||||
|
opStack.emplace_back(nextOp); // Recursively push into the new op
|
||||||
|
break;
|
||||||
|
case CPUI_FLOAT_ADD:
|
||||||
|
case CPUI_FLOAT_SUB:
|
||||||
|
case CPUI_FLOAT_MULT:
|
||||||
|
case CPUI_FLOAT_DIV:
|
||||||
|
break;
|
||||||
|
case CPUI_FLOAT_FLOAT2FLOAT:
|
||||||
|
case CPUI_FLOAT_INT2FLOAT: // Treat integer as having precision matching its size
|
||||||
|
if (nextOp->getIn(0)->getSize() > nextVn->getSize())
|
||||||
|
state.incorporateInputSize(nextVn->getSize());
|
||||||
|
else
|
||||||
|
state.incorporateInputSize(nextOp->getIn(0)->getSize());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state.incorporateInputSize(nextVn->getSize());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is called only for binary floating-point ops: FLOAT_ADD, FLOAT_MULT, FLOAT_LESS, etc.
|
||||||
|
/// If the maximum precision reaching both input operands exceeds the \b precision established
|
||||||
|
/// for \b this Rule, \b true is returned, indicating the op cannot be truncated without losing precision.
|
||||||
|
/// We count on the fact that this test is applied to all binary operations encountered during Rule application.
|
||||||
|
/// This method will correctly return \b true for the earliest operations whose inputs both exceed the
|
||||||
|
/// \b precision, but, because of the way maxPrecision() is calculated, it may incorrectly return \b false
|
||||||
|
/// for later operations.
|
||||||
|
/// \param op is the given binary floating-point PcodeOp
|
||||||
|
/// \return \b true if both input operands exceed the established \b precision
|
||||||
|
bool SubfloatFlow::exceedsPrecision(PcodeOp *op)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 val1 = maxPrecision(op->getIn(0));
|
||||||
|
int4 val2 = maxPrecision(op->getIn(1));
|
||||||
|
int4 min = (val1 < val2) ? val1 : val2;
|
||||||
|
return (min > precision);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Create and return a placeholder associated with the given Varnode
|
/// \brief Create and return a placeholder associated with the given Varnode
|
||||||
///
|
///
|
||||||
|
@ -2636,6 +2762,14 @@ bool SubfloatFlow::traceForward(TransformVar *rvn)
|
||||||
if ((outvn!=(Varnode *)0)&&(outvn->isMark()))
|
if ((outvn!=(Varnode *)0)&&(outvn->isMark()))
|
||||||
continue;
|
continue;
|
||||||
switch(op->code()) {
|
switch(op->code()) {
|
||||||
|
case CPUI_FLOAT_ADD:
|
||||||
|
case CPUI_FLOAT_SUB:
|
||||||
|
case CPUI_FLOAT_MULT:
|
||||||
|
case CPUI_FLOAT_DIV:
|
||||||
|
if (exceedsPrecision(op))
|
||||||
|
return false;
|
||||||
|
// fall through
|
||||||
|
case CPUI_MULTIEQUAL:
|
||||||
case CPUI_COPY:
|
case CPUI_COPY:
|
||||||
case CPUI_FLOAT_CEIL:
|
case CPUI_FLOAT_CEIL:
|
||||||
case CPUI_FLOAT_FLOOR:
|
case CPUI_FLOAT_FLOOR:
|
||||||
|
@ -2643,11 +2777,6 @@ bool SubfloatFlow::traceForward(TransformVar *rvn)
|
||||||
case CPUI_FLOAT_NEG:
|
case CPUI_FLOAT_NEG:
|
||||||
case CPUI_FLOAT_ABS:
|
case CPUI_FLOAT_ABS:
|
||||||
case CPUI_FLOAT_SQRT:
|
case CPUI_FLOAT_SQRT:
|
||||||
case CPUI_FLOAT_ADD:
|
|
||||||
case CPUI_FLOAT_SUB:
|
|
||||||
case CPUI_FLOAT_MULT:
|
|
||||||
case CPUI_FLOAT_DIV:
|
|
||||||
case CPUI_MULTIEQUAL:
|
|
||||||
{
|
{
|
||||||
TransformOp *rop = newOpReplace(op->numInput(), op->code(), op);
|
TransformOp *rop = newOpReplace(op->numInput(), op->code(), op);
|
||||||
TransformVar *outrvn = setReplacement(outvn);
|
TransformVar *outrvn = setReplacement(outvn);
|
||||||
|
@ -2670,6 +2799,8 @@ bool SubfloatFlow::traceForward(TransformVar *rvn)
|
||||||
case CPUI_FLOAT_LESS:
|
case CPUI_FLOAT_LESS:
|
||||||
case CPUI_FLOAT_LESSEQUAL:
|
case CPUI_FLOAT_LESSEQUAL:
|
||||||
{
|
{
|
||||||
|
if (exceedsPrecision(op))
|
||||||
|
return false;
|
||||||
int4 slot = op->getSlot(vn);
|
int4 slot = op->getSlot(vn);
|
||||||
TransformVar *rvn2 = setReplacement(op->getIn(1-slot));
|
TransformVar *rvn2 = setReplacement(op->getIn(1-slot));
|
||||||
if (rvn2 == (TransformVar *)0) return false;
|
if (rvn2 == (TransformVar *)0) return false;
|
||||||
|
@ -2715,6 +2846,13 @@ bool SubfloatFlow::traceBackward(TransformVar *rvn)
|
||||||
if (op == (PcodeOp *)0) return true; // If vn is input
|
if (op == (PcodeOp *)0) return true; // If vn is input
|
||||||
|
|
||||||
switch(op->code()) {
|
switch(op->code()) {
|
||||||
|
case CPUI_FLOAT_ADD:
|
||||||
|
case CPUI_FLOAT_SUB:
|
||||||
|
case CPUI_FLOAT_MULT:
|
||||||
|
case CPUI_FLOAT_DIV:
|
||||||
|
if (exceedsPrecision(op))
|
||||||
|
return false;
|
||||||
|
// fallthru
|
||||||
case CPUI_COPY:
|
case CPUI_COPY:
|
||||||
case CPUI_FLOAT_CEIL:
|
case CPUI_FLOAT_CEIL:
|
||||||
case CPUI_FLOAT_FLOOR:
|
case CPUI_FLOAT_FLOOR:
|
||||||
|
@ -2722,10 +2860,6 @@ bool SubfloatFlow::traceBackward(TransformVar *rvn)
|
||||||
case CPUI_FLOAT_NEG:
|
case CPUI_FLOAT_NEG:
|
||||||
case CPUI_FLOAT_ABS:
|
case CPUI_FLOAT_ABS:
|
||||||
case CPUI_FLOAT_SQRT:
|
case CPUI_FLOAT_SQRT:
|
||||||
case CPUI_FLOAT_ADD:
|
|
||||||
case CPUI_FLOAT_SUB:
|
|
||||||
case CPUI_FLOAT_MULT:
|
|
||||||
case CPUI_FLOAT_DIV:
|
|
||||||
case CPUI_MULTIEQUAL:
|
case CPUI_MULTIEQUAL:
|
||||||
{
|
{
|
||||||
TransformOp *rop = rvn->getDef();
|
TransformOp *rop = rvn->getDef();
|
||||||
|
@ -3013,6 +3147,29 @@ bool LaneDivide::buildMultiequal(PcodeOp *op,TransformVar *outVars,int4 numLanes
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Split a given CPUI_INDIRECT operation into placeholders given the output lanes
|
||||||
|
///
|
||||||
|
/// Create the CPUI_INDIRECTs for each lane, sharing the same affecting \e iop.
|
||||||
|
/// \param op is the original CPUI_MULTIEQUAL PcodeOp
|
||||||
|
/// \param outVars is the placeholder variables making up the lanes of the output
|
||||||
|
/// \param numLanes is the number of lanes in the output
|
||||||
|
/// \param skipLanes is the index of the least significant output lane within the global description
|
||||||
|
/// \return \b true if the operation was fully modeled
|
||||||
|
bool LaneDivide::buildIndirect(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes)
|
||||||
|
|
||||||
|
{
|
||||||
|
TransformVar *inVn = setReplacement(op->getIn(0), numLanes, skipLanes);
|
||||||
|
if (inVn == (TransformVar *)0) return false;
|
||||||
|
for(int4 i=0;i<numLanes;++i) {
|
||||||
|
TransformOp *rop = newOpReplace(2, CPUI_INDIRECT, op);
|
||||||
|
opSetOutput(rop, outVars + i);
|
||||||
|
opSetInput(rop,inVn + i, 0);
|
||||||
|
opSetInput(rop,newIop(op->getIn(1)),1);
|
||||||
|
rop->inheritIndirect(op);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Split a given CPUI_STORE operation into a sequence of STOREs of individual lanes
|
/// \brief Split a given CPUI_STORE operation into a sequence of STOREs of individual lanes
|
||||||
///
|
///
|
||||||
/// A new pointer is constructed for each individual lane into a temporary, then a
|
/// A new pointer is constructed for each individual lane into a temporary, then a
|
||||||
|
@ -3117,7 +3274,7 @@ bool LaneDivide::buildLoad(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4
|
||||||
/// \param op is the given CPUI_INT_RIGHT PcodeOp
|
/// \param op is the given CPUI_INT_RIGHT PcodeOp
|
||||||
/// \param outVars is the output placeholders for the RIGHT shift
|
/// \param outVars is the output placeholders for the RIGHT shift
|
||||||
/// \param numLanes is the number of lanes the shift is split into
|
/// \param numLanes is the number of lanes the shift is split into
|
||||||
/// \param skipLanes is the starting lane (within the global description) of the value being loaded
|
/// \param skipLanes is the starting lane (within the global description) of the output value
|
||||||
/// \return \b true if the CPUI_INT_RIGHT was successfully modeled on lanes
|
/// \return \b true if the CPUI_INT_RIGHT was successfully modeled on lanes
|
||||||
bool LaneDivide::buildRightShift(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes)
|
bool LaneDivide::buildRightShift(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes)
|
||||||
|
|
||||||
|
@ -3147,6 +3304,85 @@ bool LaneDivide::buildRightShift(PcodeOp *op,TransformVar *outVars,int4 numLanes
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Check that a CPUI_INT_LEFT respects the lanes then generate lane placeholders
|
||||||
|
///
|
||||||
|
/// For the given lane scheme, check that the LEFT shift is copying whole lanes to each other.
|
||||||
|
/// If so, generate the placeholder COPYs that model the shift.
|
||||||
|
/// \param op is the given CPUI_INT_LEFT PcodeOp
|
||||||
|
/// \param outVars is the output placeholders for the LEFT shift
|
||||||
|
/// \param numLanes is the number of lanes the shift is split into
|
||||||
|
/// \param skipLanes is the starting lane (within the global description) of the output value
|
||||||
|
/// \return \b true if the CPUI_INT_RIGHT was successfully modeled on lanes
|
||||||
|
bool LaneDivide::buildLeftShift(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!op->getIn(1)->isConstant()) return false;
|
||||||
|
int4 shiftSize = (int4)op->getIn(1)->getOffset();
|
||||||
|
if ((shiftSize & 7) != 0) return false; // Not a multiple of 8
|
||||||
|
shiftSize /= 8;
|
||||||
|
int4 startPos = shiftSize + description.getPosition(skipLanes);
|
||||||
|
int4 startLane = description.getBoundary(startPos);
|
||||||
|
if (startLane < 0) return false; // Shift does not end on a lane boundary
|
||||||
|
int4 destLane = startLane;
|
||||||
|
int4 srcLane = skipLanes;
|
||||||
|
while(destLane - skipLanes < numLanes) {
|
||||||
|
if (description.getSize(srcLane) != description.getSize(destLane)) return false;
|
||||||
|
srcLane += 1;
|
||||||
|
destLane += 1;
|
||||||
|
}
|
||||||
|
TransformVar *inVars = setReplacement(op->getIn(0), numLanes, skipLanes);
|
||||||
|
if (inVars == (TransformVar *)0) return false;
|
||||||
|
for(int4 zeroLane=0;zeroLane < (startLane - skipLanes);++zeroLane) {
|
||||||
|
TransformOp *rop = newOpReplace(1, CPUI_COPY, op);
|
||||||
|
opSetOutput(rop,outVars + zeroLane);
|
||||||
|
opSetInput(rop,newConstant(description.getSize(zeroLane), 0, 0),0);
|
||||||
|
}
|
||||||
|
buildUnaryOp(CPUI_COPY, op, inVars, outVars + (startLane - skipLanes), numLanes - (startLane - skipLanes));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Split a CPUI_INT_ZEXT into COPYs of lanes and COPYs of zero into lanes
|
||||||
|
///
|
||||||
|
/// If the input to the INT_ZEXT matches the lane boundaries. Placeholder COPYs are generated from
|
||||||
|
/// the input Varnode to the least significant lanes. Additional COPYs are generated which place a zero
|
||||||
|
/// in the remaining most significant lanes.
|
||||||
|
/// \param op is the given CPUI_INT_ZEXT PcodeOp
|
||||||
|
/// \param outVars is the output placeholders for the extension
|
||||||
|
/// \param numLanes is the number of lanes the extension is split into
|
||||||
|
/// \param skipLanes is the starting lane (within the global description) of the output of the extension
|
||||||
|
/// \return \b true if the CPUI_INT_ZEXT was successfully modeled on lanes
|
||||||
|
bool LaneDivide::buildZext(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 inLanes,inSkip;
|
||||||
|
Varnode *invn = op->getIn(0);
|
||||||
|
if (!description.restriction(numLanes, skipLanes, 0, invn->getSize(), inLanes, inSkip)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// inSkip should always come back as equal to skipLanes
|
||||||
|
if (inLanes == 1) {
|
||||||
|
TransformOp *rop = newOpReplace(1, CPUI_COPY, op);
|
||||||
|
TransformVar *inVar = getPreexistingVarnode(invn);
|
||||||
|
opSetInput(rop,inVar,0);
|
||||||
|
opSetOutput(rop,outVars);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TransformVar *inRvn = setReplacement(invn,inLanes,inSkip);
|
||||||
|
if (inRvn == (TransformVar *)0) return false;
|
||||||
|
for(int4 i=0;i<inLanes;++i) {
|
||||||
|
TransformOp *rop = newOpReplace(1, CPUI_COPY, op);
|
||||||
|
opSetInput(rop,inRvn+i,0);
|
||||||
|
opSetOutput(rop,outVars + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int4 i=0;i<numLanes-inLanes;++i) { // Write 0 constants to remaining lanes
|
||||||
|
TransformOp *rop = newOpReplace(1, CPUI_COPY, op);
|
||||||
|
opSetInput(rop,newConstant(description.getSize(skipLanes + inLanes + i), 0, 0),0);
|
||||||
|
opSetOutput(rop,outVars + inLanes + i);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Push the logical lanes forward through any PcodeOp reading the given variable
|
/// \brief Push the logical lanes forward through any PcodeOp reading the given variable
|
||||||
///
|
///
|
||||||
/// Determine if the logical lanes can be pushed forward naturally, and create placeholder
|
/// Determine if the logical lanes can be pushed forward naturally, and create placeholder
|
||||||
|
@ -3216,6 +3452,7 @@ bool LaneDivide::traceForward(TransformVar *rvn,int4 numLanes,int4 skipLanes)
|
||||||
case CPUI_INT_OR:
|
case CPUI_INT_OR:
|
||||||
case CPUI_INT_XOR:
|
case CPUI_INT_XOR:
|
||||||
case CPUI_MULTIEQUAL:
|
case CPUI_MULTIEQUAL:
|
||||||
|
case CPUI_INDIRECT:
|
||||||
{
|
{
|
||||||
TransformVar *outRvn = setReplacement(outvn,numLanes,skipLanes);
|
TransformVar *outRvn = setReplacement(outvn,numLanes,skipLanes);
|
||||||
if (outRvn == (TransformVar *)0) return false;
|
if (outRvn == (TransformVar *)0) return false;
|
||||||
|
@ -3281,6 +3518,10 @@ bool LaneDivide::traceBackward(TransformVar *rvn,int4 numLanes,int4 skipLanes)
|
||||||
if (!buildMultiequal(op, rvn, numLanes, skipLanes))
|
if (!buildMultiequal(op, rvn, numLanes, skipLanes))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case CPUI_INDIRECT:
|
||||||
|
if (!buildIndirect(op, rvn, numLanes, skipLanes))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
case CPUI_SUBPIECE:
|
case CPUI_SUBPIECE:
|
||||||
{
|
{
|
||||||
Varnode *inVn = op->getIn(0);
|
Varnode *inVn = op->getIn(0);
|
||||||
|
@ -3305,6 +3546,14 @@ bool LaneDivide::traceBackward(TransformVar *rvn,int4 numLanes,int4 skipLanes)
|
||||||
if (!buildRightShift(op, rvn, numLanes, skipLanes))
|
if (!buildRightShift(op, rvn, numLanes, skipLanes))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case CPUI_INT_LEFT:
|
||||||
|
if (!buildLeftShift(op, rvn, numLanes, skipLanes))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case CPUI_INT_ZEXT:
|
||||||
|
if (!buildZext(op, rvn, numLanes, skipLanes))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,10 +211,24 @@ public:
|
||||||
/// and then rewrites the data-flow in terms of the lower precision, eliminating the
|
/// and then rewrites the data-flow in terms of the lower precision, eliminating the
|
||||||
/// precision conversions.
|
/// precision conversions.
|
||||||
class SubfloatFlow : public TransformManager {
|
class SubfloatFlow : public TransformManager {
|
||||||
|
/// \brief Internal state for walking floating-point data-flow and computing precision
|
||||||
|
class State {
|
||||||
|
public:
|
||||||
|
PcodeOp *op; ///< Operation being traversed
|
||||||
|
int4 slot; ///< Input edge being traversed
|
||||||
|
int4 maxPrecision; ///< Maximum precision traversed through inputs so far
|
||||||
|
State(PcodeOp *o) {
|
||||||
|
op = o; slot = 0; maxPrecision = 0; } ///< Constructor
|
||||||
|
/// \brief Accumulate precision coming in from an input Varnode to \b this node
|
||||||
|
void incorporateInputSize(int4 sz) { maxPrecision = (maxPrecision < sz) ? sz : maxPrecision; }
|
||||||
|
};
|
||||||
int4 precision; ///< Number of bytes of precision in the logical flow
|
int4 precision; ///< Number of bytes of precision in the logical flow
|
||||||
int4 terminatorCount; ///< Number of terminating nodes reachable via the root
|
int4 terminatorCount; ///< Number of terminating nodes reachable via the root
|
||||||
const FloatFormat *format; ///< The floating-point format of the logical value
|
const FloatFormat *format; ///< The floating-point format of the logical value
|
||||||
vector<TransformVar *> worklist; ///< Current list of placeholders that still need to be traced
|
vector<TransformVar *> worklist; ///< Current list of placeholders that still need to be traced
|
||||||
|
map<PcodeOp *,int4> maxPrecisionMap; ///< Maximum precision flowing into a particular floating-point op
|
||||||
|
int4 maxPrecision(Varnode *vn); ///< Calculate maximum floating-point precision reaching a given Varnode
|
||||||
|
bool exceedsPrecision(PcodeOp *op); ///< Determine if the given op exceeds our \b precision
|
||||||
TransformVar *setReplacement(Varnode *vn);
|
TransformVar *setReplacement(Varnode *vn);
|
||||||
bool traceForward(TransformVar *rvn);
|
bool traceForward(TransformVar *rvn);
|
||||||
bool traceBackward(TransformVar *rvn);
|
bool traceBackward(TransformVar *rvn);
|
||||||
|
@ -249,9 +263,12 @@ class LaneDivide : public TransformManager {
|
||||||
void buildBinaryOp(OpCode opc,PcodeOp *op,TransformVar *in0Vars,TransformVar *in1Vars,TransformVar *outVars,int4 numLanes);
|
void buildBinaryOp(OpCode opc,PcodeOp *op,TransformVar *in0Vars,TransformVar *in1Vars,TransformVar *outVars,int4 numLanes);
|
||||||
bool buildPiece(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
bool buildPiece(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
||||||
bool buildMultiequal(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
bool buildMultiequal(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
||||||
|
bool buildIndirect(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
||||||
bool buildStore(PcodeOp *op,int4 numLanes,int4 skipLanes);
|
bool buildStore(PcodeOp *op,int4 numLanes,int4 skipLanes);
|
||||||
bool buildLoad(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
bool buildLoad(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
||||||
bool buildRightShift(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
bool buildRightShift(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
||||||
|
bool buildLeftShift(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
||||||
|
bool buildZext(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
|
||||||
bool traceForward(TransformVar *rvn,int4 numLanes,int4 skipLanes);
|
bool traceForward(TransformVar *rvn,int4 numLanes,int4 skipLanes);
|
||||||
bool traceBackward(TransformVar *rvn,int4 numLanes,int4 skipLanes);
|
bool traceBackward(TransformVar *rvn,int4 numLanes,int4 skipLanes);
|
||||||
bool processNextWork(void); ///< Process the next Varnode on the work list
|
bool processNextWork(void); ///< Process the next Varnode on the work list
|
||||||
|
|
|
@ -146,6 +146,35 @@ void TypeOp::selectJavaOperators(vector<TypeOp *> &inst,bool val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return CPUI_FLOAT_NEG if the \e sign bit is flipped, or CPUI_FLOAT_ABS if the \e sign bit is zeroed out.
|
||||||
|
/// Otherwise CPUI_MAX is returned.
|
||||||
|
/// \param op is the given PcodeOp to test
|
||||||
|
/// \return the floating-point operation the PcodeOp is equivalent to, or CPUI_MAX
|
||||||
|
OpCode TypeOp::floatSignManipulation(PcodeOp *op)
|
||||||
|
|
||||||
|
{
|
||||||
|
OpCode opc = op->code();
|
||||||
|
if (opc == CPUI_INT_AND) {
|
||||||
|
Varnode *cvn = op->getIn(1);
|
||||||
|
if (cvn->isConstant()) {
|
||||||
|
uintb val = calc_mask(cvn->getSize());
|
||||||
|
val >>= 1;
|
||||||
|
if (val == cvn->getOffset())
|
||||||
|
return CPUI_FLOAT_ABS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (opc == CPUI_INT_XOR) {
|
||||||
|
Varnode *cvn = op->getIn(1);
|
||||||
|
if (cvn->isConstant()) {
|
||||||
|
uintb val = calc_mask(cvn->getSize());
|
||||||
|
val = val ^ (val >> 1);
|
||||||
|
if (val == cvn->getOffset())
|
||||||
|
return CPUI_FLOAT_NEG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CPUI_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
/// \param t is the TypeFactory used to construct data-types
|
/// \param t is the TypeFactory used to construct data-types
|
||||||
/// \param opc is the op-code value the new object will represent
|
/// \param opc is the op-code value the new object will represent
|
||||||
/// \param n is the display name that will represent the op-code
|
/// \param n is the display name that will represent the op-code
|
||||||
|
@ -1333,7 +1362,12 @@ Datatype *TypeOpIntXor::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
|
||||||
Datatype *TypeOpIntXor::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
|
Datatype *TypeOpIntXor::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
|
||||||
int4 inslot,int4 outslot)
|
int4 inslot,int4 outslot)
|
||||||
{
|
{
|
||||||
if (!alttype->isPowerOfTwo()) return (Datatype *)0; // Only propagate flag enums
|
if (!alttype->isPowerOfTwo()) {
|
||||||
|
if (alttype->getMetatype() != TYPE_FLOAT)
|
||||||
|
return (Datatype *)0;
|
||||||
|
if (floatSignManipulation(op) == CPUI_MAX)
|
||||||
|
return (Datatype *)0;
|
||||||
|
}
|
||||||
Datatype *newtype;
|
Datatype *newtype;
|
||||||
if (invn->isSpacebase()) {
|
if (invn->isSpacebase()) {
|
||||||
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
|
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
|
||||||
|
@ -1361,7 +1395,12 @@ Datatype *TypeOpIntAnd::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
|
||||||
Datatype *TypeOpIntAnd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
|
Datatype *TypeOpIntAnd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
|
||||||
int4 inslot,int4 outslot)
|
int4 inslot,int4 outslot)
|
||||||
{
|
{
|
||||||
if (!alttype->isPowerOfTwo()) return (Datatype *)0; // Only propagate flag enums
|
if (!alttype->isPowerOfTwo()) {
|
||||||
|
if (alttype->getMetatype() != TYPE_FLOAT)
|
||||||
|
return (Datatype *)0;
|
||||||
|
if (floatSignManipulation(op) == CPUI_MAX)
|
||||||
|
return (Datatype *)0;
|
||||||
|
}
|
||||||
Datatype *newtype;
|
Datatype *newtype;
|
||||||
if (invn->isSpacebase()) {
|
if (invn->isSpacebase()) {
|
||||||
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
|
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
|
||||||
|
|
|
@ -177,6 +177,9 @@ public:
|
||||||
|
|
||||||
/// \brief Toggle Java specific aspects of the op-code information
|
/// \brief Toggle Java specific aspects of the op-code information
|
||||||
static void selectJavaOperators(vector<TypeOp *> &inst,bool val);
|
static void selectJavaOperators(vector<TypeOp *> &inst,bool val);
|
||||||
|
|
||||||
|
/// \brief Return the floating-point operation associated with the \e sign bit manipulation by the given PcodeOp
|
||||||
|
static OpCode floatSignManipulation(PcodeOp *op);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Major classes of operations
|
// Major classes of operations
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<decompilertest>
|
||||||
|
<binaryimage arch="x86:LE:64:default:gcc">
|
||||||
|
<bytechunk space="ram" offset="0x100000" readonly="true">
|
||||||
|
f30f1efa0f28d0f20f10057100000083
|
||||||
|
ff0a7408660fefc0f30f5ac2f20f1015
|
||||||
|
6400000083fe0a7408660fefd2f30f5a
|
||||||
|
d1f20f5cc2f20f5ac0c3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x10003a" readonly="true">
|
||||||
|
f30f1efaf30f
|
||||||
|
5ac983ff14741ff30f5ac0660f57054d
|
||||||
|
000000660f540d55000000660f2fc80f
|
||||||
|
97c00fb6c0c3f20f10052200000083fe
|
||||||
|
1475d8f20f100d1d000000ebce
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x100080" readonly="true">
|
||||||
|
17f25dd1adf9f13f891c09d1adf9f13f
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x100090" readonly="true">
|
||||||
|
dbccdd45cac0234033f68845cac02340
|
||||||
|
00000000000000800000000000000000
|
||||||
|
ffffffffffffff7f0000000000000000
|
||||||
|
</bytechunk>
|
||||||
|
<symbol space="ram" offset="0x100000" name="prec_conditions"/>
|
||||||
|
<symbol space="ram" offset="0x10003a" name="prec_comparison"/>
|
||||||
|
</binaryimage>
|
||||||
|
<script>
|
||||||
|
<com>option readonly on</com>
|
||||||
|
<com>parse line extern float4 prec_conditions(float4 a,float4 b,int4 cond1,int4 cond2);</com>
|
||||||
|
<com>parse line extern int4 prec_comparison(float4 c,float4 d,int4 cond1,int4 cond2);</com>
|
||||||
|
<com>lo fu prec_conditions</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu prec_comparison</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>quit</com>
|
||||||
|
</script>
|
||||||
|
<stringmatch name="Floating-point cast #1" min="1" max="1">fVar1 = \(float8\)a;</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #2" min="1" max="1">fVar2 = \(float8\)b;</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #3" min="1" max="1">fVar1 = 1\.1234567812345;</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #4" min="1" max="1">fVar2 = 1\.12345678;</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #5" min="1" max="1">return \(float4\)\(fVar1 \- fVar2\);</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #6" min="1" max="1">fVar1 = \(float8\)c;</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #7" min="1" max="1">fVar2 = \(float8\)d;</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #8" min="1" max="1">fVar1 = 9\.8765432198765;</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #9" min="1" max="1">fVar2 = 9\.87654321;</stringmatch>
|
||||||
|
<stringmatch name="Floating-point cast #10" min="1" max="1">return.*\-fVar1 < ABS\(fVar2\)</stringmatch>
|
||||||
|
</decompilertest>
|
|
@ -53,7 +53,7 @@ bbbdd7d9df7cdb3d000000000000f03f
|
||||||
<com>print C</com>
|
<com>print C</com>
|
||||||
<com>quit</com>
|
<com>quit</com>
|
||||||
</script>
|
</script>
|
||||||
<stringmatch name="Float print #1" min="1" max="1">floatv1 = 0.3333333;</stringmatch>
|
<stringmatch name="Float print #1" min="1" max="1">floatv1 = 0.33333334;</stringmatch>
|
||||||
<stringmatch name="Float print #2" min="1" max="1">floatv2 = 2.0;</stringmatch>
|
<stringmatch name="Float print #2" min="1" max="1">floatv2 = 2.0;</stringmatch>
|
||||||
<stringmatch name="Float print #3" min="1" max="1">floatv3 = -0.001;</stringmatch>
|
<stringmatch name="Float print #3" min="1" max="1">floatv3 = -0.001;</stringmatch>
|
||||||
<stringmatch name="Float print #4" min="1" max="1">floatv4 = 1e-06;</stringmatch>
|
<stringmatch name="Float print #4" min="1" max="1">floatv4 = 1e-06;</stringmatch>
|
||||||
|
@ -66,5 +66,5 @@ bbbdd7d9df7cdb3d000000000000f03f
|
||||||
<stringmatch name="Float print #11" min="1" max="1">double4 = 1e-10;</stringmatch>
|
<stringmatch name="Float print #11" min="1" max="1">double4 = 1e-10;</stringmatch>
|
||||||
<stringmatch name="Float print #12" min="1" max="1">double5 = INFINITY;</stringmatch>
|
<stringmatch name="Float print #12" min="1" max="1">double5 = INFINITY;</stringmatch>
|
||||||
<stringmatch name="Float print #13" min="1" max="1">double6 = -NAN;</stringmatch>
|
<stringmatch name="Float print #13" min="1" max="1">double6 = -NAN;</stringmatch>
|
||||||
<stringmatch name="Float print #14" min="1" max="1">double7 = 3.141592653589793e-06;</stringmatch>
|
<stringmatch name="Float print #14" min="1" max="1">double7 = 3.1415926535897933e-06;</stringmatch>
|
||||||
</decompilertest>
|
</decompilertest>
|
||||||
|
|
|
@ -165,6 +165,35 @@ TEST(double_encoding_infinity) {
|
||||||
ASSERT_DOUBLE_ENCODING(-std::numeric_limits<double>::infinity());
|
ASSERT_DOUBLE_ENCODING(-std::numeric_limits<double>::infinity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(float_decimal_precision) {
|
||||||
|
FloatFormat ff(4);
|
||||||
|
float f0 = floatFromRawBits(0x34000001);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f0, false), "1.192093e-07")
|
||||||
|
float f1 = floatFromRawBits(0x34800000);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f1, false), "2.3841858e-07")
|
||||||
|
float f2 = floatFromRawBits(0x3eaaaaab);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f2, false), "0.33333334")
|
||||||
|
float f3 = floatFromRawBits(0x3e800000);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f3, false), "0.25");
|
||||||
|
float f4 = floatFromRawBits(0x3de3ee46);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f4, false), "0.111294314")
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(double_decimal_precision) {
|
||||||
|
FloatFormat ff(8);
|
||||||
|
double f0 = doubleFromRawBits(0x3fc5555555555555);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f0, false), "0.16666666666666666");
|
||||||
|
double f1 = doubleFromRawBits(0x7fefffffffffffff);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f1, false), "1.79769313486232e+308");
|
||||||
|
double f2 = doubleFromRawBits(0x3fd555555c7dda4b);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f2, false), "0.33333334");
|
||||||
|
double f3 = doubleFromRawBits(0x3fd0000000000000);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f3, false), "0.25");
|
||||||
|
double f4 = doubleFromRawBits(0x3fb999999999999a);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f4, false), "0.1");
|
||||||
|
double f5 = doubleFromRawBits(0x3fbf7ced916872b0);
|
||||||
|
ASSERT_EQUALS(ff.printDecimal(f5, true), "1.23000000000000e-01");}
|
||||||
|
|
||||||
TEST(float_midpoint_rounding) {
|
TEST(float_midpoint_rounding) {
|
||||||
FloatFormat ff(4);
|
FloatFormat ff(4);
|
||||||
// IEEE754 recommends "round to nearest even" for binary formats, like single and double
|
// IEEE754 recommends "round to nearest even" for binary formats, like single and double
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue