mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 05:10:16 +00:00
Merge remote-tracking branch 'origin/GP-2559_MaxFloatPrecision'
(Closes #4586, Closes #6708)
This commit is contained in:
commit
2c3a815163
@ -23,6 +23,7 @@ src/decompile/datatests/displayformat.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/divopt.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/dupptr.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/forloop1.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/forloop_loaditer.xml||GHIDRA||||END|
|
||||
|
@ -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.
|
||||
@ -563,7 +563,10 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi
|
||||
if (mode < 2)
|
||||
collectLaneSizes(vn,lanedRegister,checkLanes);
|
||||
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();
|
||||
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)
|
||||
|
||||
{
|
||||
data.setLanedRegGenerated();
|
||||
map<VarnodeData,const LanedRegister *>::const_iterator iter;
|
||||
for(int4 mode=0;mode<3;++mode) {
|
||||
bool allStorageProcessed = true;
|
||||
@ -594,6 +598,10 @@ int4 ActionLaneDivide::apply(Funcdata &data)
|
||||
bool allVarnodesProcessed = true;
|
||||
while(viter != venditer) {
|
||||
Varnode *vn = *viter;
|
||||
if (vn->hasNoDescend()) {
|
||||
++viter;
|
||||
continue;
|
||||
}
|
||||
if (processVarnode(data, vn, *lanedReg, mode)) {
|
||||
viter = data.beginLoc(sz,addr);
|
||||
venditer = data.endLoc(sz, addr); // Recalculate bounds
|
||||
@ -610,7 +618,6 @@ int4 ActionLaneDivide::apply(Funcdata &data)
|
||||
if (allStorageProcessed) break;
|
||||
}
|
||||
data.clearLanedAccessMap();
|
||||
data.setLanedRegGenerated();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1337,7 +1344,6 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
|
||||
}
|
||||
}
|
||||
}
|
||||
data.setLanedRegGenerated();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5515,6 +5521,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||
actprop->addRule( new RuleOrMultiBool("analysis") );
|
||||
actprop->addRule( new RuleXorSwap("analysis") );
|
||||
actprop->addRule( new RuleLzcountShiftBool("analysis") );
|
||||
actprop->addRule( new RuleFloatSign("analysis") );
|
||||
actprop->addRule( new RuleSubvarAnd("subvar") );
|
||||
actprop->addRule( new RuleSubvarSubpiece("subvar") );
|
||||
actprop->addRule( new RuleSplitFlow("subvar") );
|
||||
@ -5591,6 +5598,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||
actcleanup->addRule( new RuleAddUnsigned("cleanup") );
|
||||
actcleanup->addRule( new Rule2Comp2Sub("cleanup") );
|
||||
actcleanup->addRule( new RuleSubRight("cleanup") );
|
||||
actcleanup->addRule( new RuleFloatSignCleanup("cleanup") );
|
||||
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
|
||||
actcleanup->addRule( new RuleExtensionPush("cleanup") );
|
||||
actcleanup->addRule( new RulePieceStructure("cleanup") );
|
||||
|
@ -5,9 +5,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.
|
||||
@ -99,11 +99,11 @@ FloatFormat::floatclass FloatFormat::extractExpSig(double x,bool *sgn,uintb *sig
|
||||
x = -x;
|
||||
double norm = frexp(x,&e); // norm is between 1/2 and 1
|
||||
norm = ldexp(norm,8*sizeof(uintb)-1); // norm between 2^62 and 2^63
|
||||
|
||||
|
||||
*signif = (uintb)norm; // Convert to normalized integer
|
||||
*signif <<= 1;
|
||||
|
||||
e -= 1; // Consider normalization between 1 and 2
|
||||
e -= 1; // Consider normalization between 1 and 2
|
||||
*exp = e;
|
||||
return normalized;
|
||||
}
|
||||
@ -217,8 +217,9 @@ uintb FloatFormat::getNaNEncoding(bool sgn) const
|
||||
void FloatFormat::calcPrecision(void)
|
||||
|
||||
{
|
||||
float val = frac_size * 0.30103;
|
||||
decimal_precision = (int4)floor(val + 0.5);
|
||||
decimalMinPrecision = (int4)floor(frac_size * 0.30103);
|
||||
// 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
|
||||
@ -417,6 +418,47 @@ uintb FloatFormat::convertEncoding(uintb encoding,
|
||||
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
|
||||
// By converting the encoding to the host's encoding and then
|
||||
// performing the operation using the host's floating point unit
|
||||
|
@ -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.
|
||||
@ -48,7 +48,8 @@ private:
|
||||
int4 exp_size; ///< Number of bits in exponent
|
||||
int4 bias; ///< What to add to real exponent to get encoding
|
||||
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
|
||||
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);
|
||||
@ -65,13 +66,14 @@ public:
|
||||
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
|
||||
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 extractFractionalCode(uintb x) const; ///< Extract the fractional part of 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
|
||||
|
||||
string printDecimal(double host,bool forcesci) const; ///< Print given value as a decimal string
|
||||
|
||||
// Operations on floating point values
|
||||
|
||||
uintb opEqual(uintb a,uintb b) const; ///< Equality comparison (==)
|
||||
|
@ -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.
|
||||
@ -1388,19 +1388,11 @@ void PrintC::push_float(uintb val,int4 sz,tagtype tag,const Varnode *vn,const Pc
|
||||
token = "NAN";
|
||||
}
|
||||
else {
|
||||
ostringstream t;
|
||||
if ((mods & force_scinote)!=0) {
|
||||
t.setf( ios::scientific ); // Set to scientific notation
|
||||
t.precision(format->getDecimalPrecision()-1);
|
||||
t << floatval;
|
||||
token = t.str();
|
||||
token = format->printDecimal(floatval, true);
|
||||
}
|
||||
else {
|
||||
// Try to print "minimal" accurate representation of the float
|
||||
t.unsetf( ios::floatfield ); // Use "default" notation
|
||||
t.precision(format->getDecimalPrecision());
|
||||
t << floatval;
|
||||
token = t.str();
|
||||
token = format->printDecimal(floatval, false);
|
||||
bool looksLikeFloat = false;
|
||||
for(int4 i=0;i<token.size();++i) {
|
||||
char c = token[i];
|
||||
|
@ -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.
|
||||
@ -10453,4 +10453,93 @@ int4 RuleLzcountShiftBool::applyOp(PcodeOp *op,Funcdata &data)
|
||||
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
|
||||
|
@ -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.
|
||||
@ -1644,5 +1644,27 @@ public:
|
||||
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
|
||||
#endif
|
||||
|
@ -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.
|
||||
@ -34,10 +34,13 @@ AttributeId ATTRIB_PIECE = AttributeId("piece",94); // Open slots 94-102
|
||||
void AddrSpace::calcScaleMask(void)
|
||||
|
||||
{
|
||||
pointerLowerBound = (addressSize < 3) ? 0x100: 0x1000;
|
||||
highest = calc_mask(addressSize); // Maximum address
|
||||
highest = highest * wordsize + (wordsize-1); // Maximum byte address
|
||||
pointerLowerBound = 0;
|
||||
pointerUpperBound = highest;
|
||||
uintb bufferSize = (addressSize < 3) ? 0x100 : 0x1000;
|
||||
pointerLowerBound += bufferSize;
|
||||
pointerUpperBound -= bufferSize;
|
||||
}
|
||||
|
||||
/// 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)
|
||||
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
|
||||
///
|
||||
@ -2636,6 +2762,14 @@ bool SubfloatFlow::traceForward(TransformVar *rvn)
|
||||
if ((outvn!=(Varnode *)0)&&(outvn->isMark()))
|
||||
continue;
|
||||
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_FLOAT_CEIL:
|
||||
case CPUI_FLOAT_FLOOR:
|
||||
@ -2643,11 +2777,6 @@ bool SubfloatFlow::traceForward(TransformVar *rvn)
|
||||
case CPUI_FLOAT_NEG:
|
||||
case CPUI_FLOAT_ABS:
|
||||
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);
|
||||
TransformVar *outrvn = setReplacement(outvn);
|
||||
@ -2670,6 +2799,8 @@ bool SubfloatFlow::traceForward(TransformVar *rvn)
|
||||
case CPUI_FLOAT_LESS:
|
||||
case CPUI_FLOAT_LESSEQUAL:
|
||||
{
|
||||
if (exceedsPrecision(op))
|
||||
return false;
|
||||
int4 slot = op->getSlot(vn);
|
||||
TransformVar *rvn2 = setReplacement(op->getIn(1-slot));
|
||||
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
|
||||
|
||||
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_FLOAT_CEIL:
|
||||
case CPUI_FLOAT_FLOOR:
|
||||
@ -2722,10 +2860,6 @@ bool SubfloatFlow::traceBackward(TransformVar *rvn)
|
||||
case CPUI_FLOAT_NEG:
|
||||
case CPUI_FLOAT_ABS:
|
||||
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 = rvn->getDef();
|
||||
@ -3013,6 +3147,29 @@ bool LaneDivide::buildMultiequal(PcodeOp *op,TransformVar *outVars,int4 numLanes
|
||||
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
|
||||
///
|
||||
/// 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 outVars is the output placeholders for the RIGHT 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 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
|
||||
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;
|
||||
}
|
||||
|
||||
/// \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
|
||||
///
|
||||
/// 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_XOR:
|
||||
case CPUI_MULTIEQUAL:
|
||||
case CPUI_INDIRECT:
|
||||
{
|
||||
TransformVar *outRvn = setReplacement(outvn,numLanes,skipLanes);
|
||||
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))
|
||||
return false;
|
||||
break;
|
||||
case CPUI_INDIRECT:
|
||||
if (!buildIndirect(op, rvn, numLanes, skipLanes))
|
||||
return false;
|
||||
break;
|
||||
case CPUI_SUBPIECE:
|
||||
{
|
||||
Varnode *inVn = op->getIn(0);
|
||||
@ -3305,6 +3546,14 @@ bool LaneDivide::traceBackward(TransformVar *rvn,int4 numLanes,int4 skipLanes)
|
||||
if (!buildRightShift(op, rvn, numLanes, skipLanes))
|
||||
return false;
|
||||
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:
|
||||
return false;
|
||||
}
|
||||
|
@ -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.
|
||||
@ -211,10 +211,24 @@ public:
|
||||
/// and then rewrites the data-flow in terms of the lower precision, eliminating the
|
||||
/// precision conversions.
|
||||
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 terminatorCount; ///< Number of terminating nodes reachable via the root
|
||||
const FloatFormat *format; ///< The floating-point format of the logical value
|
||||
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);
|
||||
bool traceForward(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);
|
||||
bool buildPiece(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 buildLoad(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 traceBackward(TransformVar *rvn,int4 numLanes,int4 skipLanes);
|
||||
bool processNextWork(void); ///< Process the next Varnode on the work list
|
||||
|
@ -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.
|
||||
@ -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 opc is the op-code value the new object will represent
|
||||
/// \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,
|
||||
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;
|
||||
if (invn->isSpacebase()) {
|
||||
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,
|
||||
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;
|
||||
if (invn->isSpacebase()) {
|
||||
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
|
||||
|
@ -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.
|
||||
@ -177,6 +177,9 @@ public:
|
||||
|
||||
/// \brief Toggle Java specific aspects of the op-code information
|
||||
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
|
||||
|
@ -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>quit</com>
|
||||
</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 #3" min="1" max="1">floatv3 = -0.001;</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 #12" min="1" max="1">double5 = INFINITY;</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>
|
||||
|
@ -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.
|
||||
@ -165,6 +165,35 @@ TEST(double_encoding_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) {
|
||||
FloatFormat ff(4);
|
||||
// IEEE754 recommends "round to nearest even" for binary formats, like single and double
|
||||
|
Loading…
Reference in New Issue
Block a user