Merge remote-tracking branch 'origin/GP-4871_Int2FloatCasting'

(Closes #6760)
This commit is contained in:
Ryan Kurtz 2024-09-03 06:37:25 -04:00
commit 834cba1065
16 changed files with 408 additions and 16 deletions

View File

@ -25,6 +25,7 @@ src/decompile/datatests/doublemove.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/floatconv.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|

View File

@ -33,7 +33,7 @@ using std::sqrt;
vector<ArchitectureCapability *> ArchitectureCapability::thelist;
const uint4 ArchitectureCapability::majorversion = 6;
const uint4 ArchitectureCapability::minorversion = 0;
const uint4 ArchitectureCapability::minorversion = 1;
AttributeId ATTRIB_ADDRESS = AttributeId("address",148);
AttributeId ATTRIB_ADJUSTVMA = AttributeId("adjustvma",103);

View File

@ -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.
@ -814,6 +814,37 @@ FlowBlock *FlowBlock::findCommonBlock(const vector<FlowBlock *> &blockSet)
return res;
}
/// \brief Find conditional block that decides between the given control-flow edges
///
/// There must be a unique path from the conditional block through the first edge, and
/// a second unique path through the second edge. Otherwise null is returned. The index of the
/// output block from the conditional that flows to the first edge is passed back.
/// \param bl1 is the destination block for the first given control-flow edge
/// \param edge1 is the input slot for the first edge
/// \param bl2 is the destination block for the second given control-flow edge
/// \param edge2 is the input slot for the second edge
/// \param slot1 will hold the output slot leading to the first control-flow edge
/// \return the conditional FlowBlock if it exists or null
FlowBlock *FlowBlock::findCondition(FlowBlock *bl1,int4 edge1,FlowBlock *bl2,int4 edge2,int4 &slot1)
{
FlowBlock *cond = bl1->getIn(edge1);
while (cond->sizeOut() != 2) {
if (cond->sizeOut() != 1) return (FlowBlock *)0;
bl1 = cond;
edge1 = 0;
cond = bl1->getIn(0);
}
while (cond != bl2->getIn(edge2)) {
bl2 = bl2->getIn(edge2);
if (bl2->sizeOut() != 1) return (FlowBlock *)0;
edge2 = 0;
}
slot1 = bl1->getInRevIndex(edge1);
return cond;
}
/// Add the given FlowBlock to the list and make \b this the parent
/// Update \b index so that it has the minimum over all components
/// \param bl is the given FlowBlock

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -344,6 +344,7 @@ public:
static bool compareFinalOrder(const FlowBlock *bl1,const FlowBlock *bl2); ///< Final FlowBlock comparison
static FlowBlock *findCommonBlock(FlowBlock *bl1,FlowBlock *bl2); ///< Find the common dominator of two FlowBlocks
static FlowBlock *findCommonBlock(const vector<FlowBlock *> &blockSet); ///< Find common dominator of multiple FlowBlocks
static FlowBlock *findCondition(FlowBlock *bl1,int4 edge1,FlowBlock *bl2,int4 edge2,int4 &slot1);
};
/// \brief A control-flow block built out of sub-components

View File

@ -3776,6 +3776,12 @@ void ActionDeadCode::propagateConsumed(vector<Varnode *> &worklist)
case CPUI_CALL:
case CPUI_CALLIND:
break; // Call output doesn't indicate consumption of inputs
case CPUI_FLOAT_INT2FLOAT:
a = 0;
if (outc != 0)
a = coveringmask(op->getIn(0)->getNZMask());
pushConsumed(a,op->getIn(0), worklist);
break;
default:
a = (outc==0) ? 0 : ~((uintb)0); // all or nothing
for(int4 i=0;i<op->numInput();++i)
@ -5538,6 +5544,8 @@ void ActionDatabase::universalAction(Architecture *conf)
actprop->addRule( new RuleSubfloatConvert("floatprecision") );
actprop->addRule( new RuleFloatCast("floatprecision") );
actprop->addRule( new RuleIgnoreNan("floatprecision") );
actprop->addRule( new RuleUnsigned2Float("analysis") );
actprop->addRule( new RuleInt2FloatCollapse("analysis") );
actprop->addRule( new RulePtraddUndo("typerecovery") );
actprop->addRule( new RulePtrsubUndo("typerecovery") );
actprop->addRule( new RuleSegment("segment") );

View File

@ -3105,6 +3105,8 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
bool isindirect = (pieces.flags & ParameterPieces::indirectstorage) != 0;
bool ishidden = (pieces.flags & ParameterPieces::hiddenretparm) != 0;
bool istypelock = (pieces.flags & ParameterPieces::typelock) != 0;
bool isnamelock = (pieces.flags & ParameterPieces::namelock) != 0;
if (res->sym != (Symbol *)0) {
entry = res->sym->getFirstWholeMap();
if ((entry->getAddr() != pieces.addr)||(entry->getSize() != pieces.type->getSize())) {
@ -3117,12 +3119,16 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
usepoint = restricted_usepoint;
res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol();
scope->setCategory(res->sym,Symbol::function_parameter,i);
if (isindirect || ishidden) {
if (isindirect || ishidden || istypelock || isnamelock) {
uint4 mirror = 0;
if (isindirect)
mirror |= Varnode::indirectstorage;
if (ishidden)
mirror |= Varnode::hiddenretparm;
if (istypelock)
mirror |= Varnode::typelock;
if (isnamelock)
mirror |= Varnode::namelock;
scope->setAttribute(res->sym,mirror);
}
return res;
@ -3139,6 +3145,18 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
else
scope->clearAttribute(res->sym,Varnode::hiddenretparm);
}
if (res->sym->isTypeLocked() != istypelock) {
if (istypelock)
scope->setAttribute(res->sym,Varnode::typelock);
else
scope->clearAttribute(res->sym,Varnode::typelock);
}
if (res->sym->isNameLocked() != isnamelock) {
if (isnamelock)
scope->setAttribute(res->sym,Varnode::namelock);
else
scope->clearAttribute(res->sym,Varnode::namelock);
}
if ((nm.size()!=0)&&(nm!=res->sym->getName()))
scope->renameSymbol(res->sym,nm);
if (pieces.type != res->sym->getType())

View File

@ -827,6 +827,19 @@ void PrintC::opBoolNegate(const PcodeOp *op)
}
}
void PrintC::opFloatInt2Float(const PcodeOp *op)
{
const PcodeOp *zextOp = TypeOpFloatInt2Float::absorbZext(op);
const Varnode *vn0 = (zextOp != (const PcodeOp *)0) ? zextOp->getIn(0) : op->getIn(0);
Datatype *dt = op->getOut()->getHighTypeDefFacing();
if (!option_nocasts) {
pushOp(&typecast,op);
pushType(dt);
}
pushVn(vn0,op,mods);
}
void PrintC::opSubpiece(const PcodeOp *op)
{

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -322,7 +322,7 @@ public:
virtual void opFloatNeg(const PcodeOp *op) { opUnary(&unary_minus,op); }
virtual void opFloatAbs(const PcodeOp *op) { opFunc(op); }
virtual void opFloatSqrt(const PcodeOp *op) { opFunc(op); }
virtual void opFloatInt2Float(const PcodeOp *op) { opTypeCast(op); }
virtual void opFloatInt2Float(const PcodeOp *op);
virtual void opFloatFloat2Float(const PcodeOp *op) { opTypeCast(op); }
virtual void opFloatTrunc(const PcodeOp *op) { opTypeCast(op); }
virtual void opFloatCeil(const PcodeOp *op) { opFunc(op); }

View File

@ -9801,6 +9801,136 @@ int4 RuleIgnoreNan::applyOp(PcodeOp *op,Funcdata &data)
return (count > 0) ? 1 : 0;
}
/// \class RuleUnsigned2Float
/// \brief Simplify conversion: `T = int2float((X >> 1) | X & #1); T + T => int2float( zext(X) )`
///
/// Architectures like x86 can use this sequence to simulate an unsigned integer to floating-point conversion,
/// when they don't have the conversion in hardware.
void RuleUnsigned2Float::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_INT2FLOAT);
}
int4 RuleUnsigned2Float::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *invn = op->getIn(0);
if (!invn->isWritten()) return 0;
PcodeOp *orop = invn->getDef();
if (orop->code() != CPUI_INT_OR) return 0;
if (!orop->getIn(0)->isWritten() || !orop->getIn(1)->isWritten()) return 0;
PcodeOp *shiftop = orop->getIn(0)->getDef();
PcodeOp *andop;
if (shiftop->code() != CPUI_INT_RIGHT) {
andop = shiftop;
shiftop = orop->getIn(1)->getDef();
}
else {
andop = orop->getIn(1)->getDef();
}
if (shiftop->code() != CPUI_INT_RIGHT) return 0;
if (!shiftop->getIn(1)->constantMatch(1)) return 0; // Shift to right by 1 exactly to clear high-bit
Varnode *basevn = shiftop->getIn(0);
if (basevn->isFree()) return 0;
if (andop->code() == CPUI_INT_ZEXT) {
if (!andop->getIn(0)->isWritten()) return 0;
andop = andop->getIn(0)->getDef();
}
if (andop->code() != CPUI_INT_AND) return 0;
if (!andop->getIn(1)->constantMatch(1)) return 0; // Mask off least significant bit
Varnode *vn = andop->getIn(0);
if (basevn != vn) {
if (!vn->isWritten()) return 0;
PcodeOp *subop = vn->getDef();
if (subop->code() != CPUI_SUBPIECE) return 0;
if (subop->getIn(1)->getOffset() != 0) return 0;
vn = subop->getIn(0);
if (basevn != vn) return 0;
}
Varnode *outvn = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=outvn->beginDescend();iter!=outvn->endDescend();++iter) {
PcodeOp *addop = *iter;
if (addop->code() != CPUI_FLOAT_ADD) continue;
if (addop->getIn(0) != outvn) continue;
if (addop->getIn(1) != outvn) continue;
PcodeOp *zextop = data.newOp(1,addop->getAddr());
data.opSetOpcode(zextop, CPUI_INT_ZEXT);
Varnode *zextout = data.newUniqueOut(TypeOpFloatInt2Float::preferredZextSize(basevn->getSize()), zextop);
data.opSetOpcode(addop, CPUI_FLOAT_INT2FLOAT);
data.opRemoveInput(addop, 1);
data.opSetInput(zextop, basevn, 0);
data.opSetInput(addop, zextout, 0);
data.opInsertBefore(zextop, addop);
return 1;
}
return 0;
}
/// \class RuleInt2FloatCollapse
/// \brief Collapse equivalent FLOAT_INT2FLOAT computations along converging data-flow paths
///
/// Look for two code paths with different ways of calculating an unsigned integer to floating-point conversion,
/// one of which is chosen by examining the most significant bit of the integer. The two paths can be collapsed
/// into a single FLOAT_INT2FLOAT operation.
void RuleInt2FloatCollapse::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_INT2FLOAT);
}
int4 RuleInt2FloatCollapse::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(0)->isWritten()) return 0;
PcodeOp *zextop = op->getIn(0)->getDef();
if (zextop->code() != CPUI_INT_ZEXT) return 0; // Original FLOAT_INT2FLOAT must be unsigned form
Varnode *basevn = zextop->getIn(0);
if (basevn->isFree()) return 0;
PcodeOp *multiop = op->getOut()->loneDescend();
if (multiop == (PcodeOp *)0) return 0;
if (multiop->code() != CPUI_MULTIEQUAL) return 0; // Output comes together with 1 other flow
if (multiop->numInput() != 2) return 0;
int4 slot = multiop->getSlot(op->getOut());
Varnode *otherout = multiop->getIn(1-slot);
if (!otherout->isWritten()) return 0;
PcodeOp *op2 = otherout->getDef();
if (op2->code() != CPUI_FLOAT_INT2FLOAT) return 0; // The other flow must be a signed FLOAT_INT2FLOAT
if (basevn != op2->getIn(0)) return 0; // taking the same input
int4 dir2unsigned; // Control path to unsigned conversion
FlowBlock *cond = FlowBlock::findCondition(multiop->getParent(), slot, multiop->getParent(), 1-slot, dir2unsigned);
if (cond == (FlowBlock *)0) return 0;
PcodeOp *cbranch = cond->lastOp();
if (cbranch == (PcodeOp *)0 || cbranch->code() != CPUI_CBRANCH) return 0;
if (!cbranch->getIn(1)->isWritten()) return 0;
if (cbranch->isBooleanFlip()) return 0;
PcodeOp *compare = cbranch->getIn(1)->getDef();
if (compare->code() != CPUI_INT_SLESS) return 0;
if (compare->getIn(1)->constantMatch(0)) { // If condition is (basevn < 0)
if (compare->getIn(0) != basevn) return 0;
if (dir2unsigned != 1) return 0; // True branch must be the unsigned FLOAT_INT2FLOAT
}
else if (compare->getIn(0)->constantMatch(calc_mask(basevn->getSize()))) { // If condition is (-1 < basevn)
if (compare->getIn(1) != basevn) return 0;
if (dir2unsigned == 1) return 0; // True branch must be to signed FLOAT_INT2FLOAT
}
else
return 0;
BlockBasic *outbl = multiop->getParent();
data.opUninsert(multiop);
data.opSetOpcode(multiop, CPUI_FLOAT_INT2FLOAT); // Redefine the MULTIEQUAL as unsigned FLOAT_INT2FLOAT
data.opRemoveInput(multiop, 0);
PcodeOp *newzext = data.newOp(1, multiop->getAddr());
data.opSetOpcode(newzext, CPUI_INT_ZEXT);
Varnode *newout = data.newUniqueOut(TypeOpFloatInt2Float::preferredZextSize(basevn->getSize()), newzext);
data.opSetInput(newzext,basevn,0);
data.opSetInput(multiop, newout, 0);
data.opInsertBegin(multiop, outbl); // Reinsert modified MULTIEQUAL after any other MULTIEQUAL
data.opInsertBefore(newzext, multiop);
return 1;
}
/// \class RuleFuncPtrEncoding
/// \brief Eliminate ARM/THUMB style masking of the low order bits on function pointers
///

View File

@ -1568,6 +1568,28 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleUnsigned2Float : public Rule {
public:
RuleUnsigned2Float(const string &g) : Rule( g, 0, "unsigned2float") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleUnsigned2Float(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleInt2FloatCollapse : public Rule {
public:
RuleInt2FloatCollapse(const string &g) : Rule( g, 0, "int2floatcollapse") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleInt2FloatCollapse(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleFuncPtrEncoding : public Rule {
public:
RuleFuncPtrEncoding(const string &g) : Rule( g, 0, "funcptrencoding") {} ///< Constructor

View File

@ -330,6 +330,41 @@ bool SubvariableFlow::trySwitchPull(PcodeOp *op,ReplaceVarnode *rvn)
return true;
}
/// \brief Determine if the subgraph variable flows naturally into a terminal FLOAT_INT2FLOAT operation
///
/// The original data-flow must pad the logical value with zero bits, making the conversion to
/// floating-point unsigned. A PatchRecord is created that preserves the FLOAT_INT2FLOAT but inserts an
/// additional INT_ZEXT operation to preserve the unsigned nature of the conversion.
/// \param op is the FLOAT_INT2FLOAT conversion operation
/// \param rvn is the logical value flowing into the conversion
bool SubvariableFlow::tryInt2FloatPull(PcodeOp *op,ReplaceVarnode *rvn)
{
if ((rvn->mask & 1) == 0) return false; // Logical value must be justified
if ((rvn->vn->getNZMask()&~rvn->mask)!=0)
return false; // Everything outside the logical value must be zero
if (rvn->vn->getSize() == flowsize)
return false; // There must be some (zero) extension
bool pullModification = true;
if (rvn->vn->isWritten() && rvn->vn->getDef()->code() == CPUI_INT_ZEXT) {
if (rvn->vn->getSize() == TypeOpFloatInt2Float::preferredZextSize(flowsize)) {
if (rvn->vn->loneDescend() == op) {
pullModification = false; // This patch does not count as a modification
// The INT_ZEXT -> FLOAT_INT2FLOAT has the correct form and does not need to be modified.
// We indicate this by NOT incrementing pullcount, so there has to be at least one other
// terminal patch in order for doTrace() to return true.
}
}
}
patchlist.emplace_back();
patchlist.back().type = PatchRecord::int2float_patch;
patchlist.back().patchOp = op;
patchlist.back().in1 = rvn;
if (pullModification)
pullcount += 1;
return true;
}
/// Try to trace the logical variable through descendant Varnodes
/// creating new nodes in the logical subgraph and updating the worklist.
/// \param rvn is the given subgraph variable to trace
@ -586,6 +621,10 @@ bool SubvariableFlow::traceForward(ReplaceVarnode *rvn)
if (rvn->mask != 1) return false;
addBooleanPatch(op,rvn,slot);
break;
case CPUI_FLOAT_INT2FLOAT:
if (!tryInt2FloatPull(op, rvn)) return false;
hcount += 1;
break;
case CPUI_CBRANCH:
if ((bitsize != 1)||(slot != 1)) return false;
if (rvn->mask != 1) return false;
@ -1451,6 +1490,18 @@ void SubvariableFlow::doReplacement(void)
}
case PatchRecord::push_patch:
break; // Shouldn't see these here, handled earlier
case PatchRecord::int2float_patch:
{
PcodeOp *zextOp = fd->newOp(1, pullop->getAddr());
fd->opSetOpcode(zextOp, CPUI_INT_ZEXT);
Varnode *invn = getReplaceVarnode((*piter).in1);
fd->opSetInput(zextOp,invn,0);
int4 sizeout = TypeOpFloatInt2Float::preferredZextSize(invn->getSize());
Varnode *outvn = fd->newUniqueOut(sizeout, zextOp);
fd->opInsertBefore(zextOp, pullop);
fd->opSetInput(pullop, outvn, 0);
break;
}
}
}
}

View File

@ -70,7 +70,8 @@ class SubvariableFlow {
compare_patch, ///< Turn compare op inputs into logical values
parameter_patch, ///< Convert a CALL/CALLIND/RETURN/BRANCHIND parameter into logical value
extension_patch, ///< Convert op into something that copies/extends logical value, adding zero bits
push_patch ///< Convert an operator output to the logical value
push_patch, ///< Convert an operator output to the logical value
int2float_patch ///< Zero extend logical value into FLOAT_INT2FLOAT operator
};
patchtype type; ///< The type of \b this patch
PcodeOp *patchOp; ///< Op being affected
@ -101,6 +102,7 @@ class SubvariableFlow {
bool tryReturnPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot);
bool tryCallReturnPush(PcodeOp *op,ReplaceVarnode *rvn);
bool trySwitchPull(PcodeOp *op,ReplaceVarnode *rvn);
bool tryInt2FloatPull(PcodeOp *op,ReplaceVarnode *rvn);
bool traceForward(ReplaceVarnode *rvn); ///< Trace the logical data-flow forward for the given subgraph variable
bool traceBackward(ReplaceVarnode *rvn); ///< Trace the logical data-flow backward for the given subgraph variable
bool traceForwardSext(ReplaceVarnode *rvn); ///< Trace logical data-flow forward assuming sign-extensions

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -267,14 +267,14 @@ void FunctionTestCollection::restoreXml(DocumentStorage &store,const Element *el
buildProgram(store);
}
else
throw IfaceParseError("Unknown tag in <decompiletest>: "+subel->getName());
throw IfaceParseError("Unknown tag in <decompilertest>: "+subel->getName());
}
if (!sawScript)
throw IfaceParseError("Did not see <script> tag in <decompiletest>");
throw IfaceParseError("Did not see <script> tag in <decompilertest>");
if (!sawTests)
throw IfaceParseError("Did not see any <stringmatch> tags in <decompiletest>");
throw IfaceParseError("Did not see any <stringmatch> tags in <decompilertest>");
if (!sawProgram)
throw IfaceParseError("No <binaryimage> tag in <decompiletest>");
throw IfaceParseError("No <binaryimage> tag in <decompilertest>");
}
/// Pull the script and tests from a comment in \<binaryimage>

View File

@ -1784,6 +1784,63 @@ TypeOpFloatInt2Float::TypeOpFloatInt2Float(TypeFactory *t,const Translate *trans
behave = new OpBehaviorFloatInt2Float(trans);
}
Datatype *TypeOpFloatInt2Float::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
{
if (absorbZext(op) != (const PcodeOp *)0)
return (Datatype *)0; // No cast if we are absorbing an INT_ZEXT
const Varnode *vn = op->getIn(slot);
Datatype *reqtype = op->inputTypeLocal(slot);
Datatype *curtype = vn->getHighTypeReadFacing(op);
bool care_uint_int = true;
if (vn->getSize() <= sizeof(uintb)) {
uintb val = vn->getNZMask();
val >>= (8*vn->getSize() - 1);
care_uint_int = (val & 1) != 0; // If the high-bit is not set, we don't care if input is signed or unsigned
}
return castStrategy->castStandard(reqtype,curtype,care_uint_int,true);
}
/// \brief Return any INT_ZEXT PcodeOp that the given FLOAT_INT2FLOAT absorbs
///
/// FLOAT_INT2FLOAT expects a signed integer input, but if the input is produced by an INT_ZEXT, we treat
/// the FLOAT_INT2FLOAT as a conversion of the unsigned integer input to the INT_ZEXT and effectively
/// absorb the extension operation into the FLOAT_INT2FLOAT operation. If this is happening, the specific
/// INT_ZEXT operation is returned, otherwise null is returned.
/// \param op is the given FLOAT_INT2FLOAT
/// \return the absorbed INT_ZEXT or null
const PcodeOp *TypeOpFloatInt2Float::absorbZext(const PcodeOp *op)
{
const Varnode *vn0 = op->getIn(0);
if (vn0->isWritten() && vn0->isImplied()) {
const PcodeOp *zextOp = vn0->getDef();
if (zextOp->code() == CPUI_INT_ZEXT) {
return zextOp;
}
}
return (const PcodeOp *)0;
}
/// \brief Return the preferred extension size for passing a an unsigned value to FLOAT_INT2FLOAT
///
/// FLOAT_INT2FLOAT expects a signed input but can be used for unsigned conversion by first zero extending
/// the value to be converted. This method returns the preferred output size for this extension.
/// \param inSize is the size in bytes of the value to be converted
/// \return the preferred size of the INT_ZEXT output
int4 TypeOpFloatInt2Float::preferredZextSize(int4 inSize)
{
int4 outSize;
if (inSize < 4)
outSize = 4;
else if (inSize < 8)
outSize = 8;
else
outSize = inSize + 1;
return outSize;
}
TypeOpFloatFloat2Float::TypeOpFloatFloat2Float(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_FLOAT2FLOAT,"FLOAT2FLOAT",TYPE_FLOAT,TYPE_FLOAT)
{

View File

@ -695,7 +695,10 @@ public:
class TypeOpFloatInt2Float : public TypeOpFunc {
public:
TypeOpFloatInt2Float(TypeFactory *t,const Translate *trans); ///< Constructor
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opFloatInt2Float(op); }
static const PcodeOp *absorbZext(const PcodeOp *op);
static int4 preferredZextSize(int4 inSize);
};
/// \brief Information about the FLOAT_FLOAT2FLOAT op-code

View File

@ -0,0 +1,55 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!-- Tests of signed and unsigned integer to floating-point conversions -->
<bytechunk space="ram" offset="0x100000" readonly="true">
f30f1efa83ef10660fefc0f30f2ac7f3
0f59058d000000c3
</bytechunk>
<bytechunk space="ram" offset="0x1000a4" readonly="true">
6f1283ba
</bytechunk>
<bytechunk space="ram" offset="0x1000aa" readonly="true">
f30f1efa5548
89e548897de8488b45e84883e8104885
c07807f2480f2ac0eb154889c248d1ea
83e0014809c2f2480f2ac2f20f58c0f2
0f1145f8f20f104df8f20f10051f0000
00f20f59c1f20f1145f8f20f1045f85d
c3
</bytechunk>
<bytechunk space="ram" offset="0x100110" readonly="true">
fca9f1d24d6250bf
</bytechunk>
<bytechunk space="ram" offset="0x140020194" readonly="true">
4883c1f00f57c07807f2480f
2ac1eb154889c883e10148d1e84809c8
f2480f2ac0f20f58c0f20f5905170000
00c20000
</bytechunk>
<bytechunk space="ram" offset="0x1400201d8" readonly="true">
fca9f1d24d6250bf
</bytechunk>
<symbol space="ram" offset="0x100000" name="rand_calc"/>
<symbol space="ram" offset="0x1000aa" name="rand_ulong"/>
<symbol space="ram" offset="0x140020194" name="ulconv_win"/>
</binaryimage>
<script>
<com>option readonly on</com>
<com>parse line extern float4 rand_calc(uint4 fval);</com>
<com>parse line extern float8 rand_ulong(uint8 lval);</com>
<com>lo fu rand_calc</com>
<com>dec</com>
<com>print C</com>
<com>lo fu rand_ulong</com>
<com>dec</com>
<com>print C</com>
<com>lo fu ulconv_win</com>
<com>map param 0 [register,8,8] uint8 llval</com>
<com>dec</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Floating-point convert #1" min="1" max="1">return \(float4\)\(int4\)\(fval - 0x10\) \* -0.001;</stringmatch>
<stringmatch name="Floating-point convert #2" min="1" max="1">return \(float8\)\(lval - 0x10\) \* -0.001;</stringmatch>
<stringmatch name="Floating-point convert #3" min="1" max="1">return \(float8\)\(llval - 0x10\) \* -0.001;</stringmatch>
</decompilertest>