Merge remote-tracking branch 'origin/GP-4300_MoreDivOpt' (Closes #5733)

This commit is contained in:
Ryan Kurtz 2024-04-12 13:47:03 -04:00
commit cf616273c6
17 changed files with 821 additions and 228 deletions

View File

@ -86,6 +86,7 @@ model {
include "emulateutil.cc"
include "flow.cc"
include "userop.cc"
include "multiprecision.cc"
include "funcdata.cc"
include "funcdata_block.cc"
include "funcdata_varnode.cc"

View File

@ -19,6 +19,7 @@ src/decompile/datatests/convert.xml||GHIDRA||||END|
src/decompile/datatests/deadvolatile.xml||GHIDRA||||END|
src/decompile/datatests/deindirect.xml||GHIDRA||||END|
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/floatprint.xml||GHIDRA||||END|

View File

@ -80,7 +80,7 @@ CORE= xml marshal space float address pcoderaw translate opcodes globalcontext
# Additional core files for any projects that decompile
DECCORE=capability architecture options graph cover block cast typeop database cpool \
comment stringmanage modelrules fspec action loadimage grammar varnode op \
type variable varmap jumptable emulate emulateutil flow userop \
type variable varmap jumptable emulate emulateutil flow userop multiprecision \
funcdata funcdata_block funcdata_op funcdata_varnode unionresolve pcodeinject \
heritage prefersplit rangeutil ruleaction subflow blockaction merge double \
transform coreaction condexe override dynamic crc32 prettyprint \

View File

@ -831,133 +831,4 @@ int4 bit_transitions(uintb val,int4 sz)
return res;
}
/// \brief Multiply 2 unsigned 64-bit values, producing a 128-bit value
///
/// TODO: Remove once we import a full multiprecision library.
/// \param res points to the result array (2 uint8 pieces)
/// \param x is the first 64-bit value
/// \param y is the second 64-bit value
void mult64to128(uint8 *res,uint8 x,uint8 y)
{
uint8 f = x & 0xffffffff;
uint8 e = x >> 32;
uint8 d = y & 0xffffffff;
uint8 c = y >> 32;
uint8 fd = f * d;
uint8 fc = f * c;
uint8 ed = e * d;
uint8 ec = e * c;
uint8 tmp = (fd >> 32) + (fc & 0xffffffff) + (ed & 0xffffffff);
res[1] = (tmp>>32) + (fc>>32) + (ed>>32) + ec;
res[0] = (tmp<<32) + (fd & 0xffffffff);
}
/// \brief Subtract (in-place) a 128-bit value from a base 128-value
///
/// The base value is altered in place.
/// TODO: Remove once we import a full multiprecision library.
/// \param a is the base 128-bit value being subtracted from in-place
/// \param b is the other 128-bit value being subtracted
void unsignedSubtract128(uint8 *a,uint8 *b)
{
bool borrow = (a[0] < b[0]);
a[0] -= b[0];
a[1] -= b[1];
if (borrow)
a[1] -= 1;
}
/// \brief Compare two unsigned 128-bit values
///
/// TODO: Remove once we import a full multiprecision library.
/// Given a first and second value, return -1, 0, or 1 depending on whether the first value
/// is \e less, \e equal, or \e greater than the second value.
/// \param a is the first 128-bit value (as an array of 2 uint8 elements)
/// \param b is the second 128-bit value
/// \return the comparison code
int4 unsignedCompare128(uint8 *a,uint8 *b)
{
if (a[1] != b[1])
return (a[1] < b[1]) ? -1 : 1;
if (a[0] != b[0])
return (a[0] < b[0]) ? -1 : 1;
return 0;
}
/// \brief Unsigned division of a power of 2 (upto 2^127) by a 64-bit divisor
///
/// The result must be less than 2^64. The remainder is calculated.
/// \param n is the power of 2 for the numerand
/// \param divisor is the 64-bit divisor
/// \param q is the passed back 64-bit quotient
/// \param r is the passed back 64-bit remainder
/// \return 0 if successful, 1 if result is too big, 2 if divide by 0
int4 power2Divide(int4 n,uint8 divisor,uint8 &q,uint8 &r)
{
if (divisor == 0) return 2;
uint8 power = 1;
if (n < 64) {
power <<= n;
q = power / divisor;
r = power % divisor;
return 0;
}
// Divide numerand and divisor by 2^(n-63) to get approximation of result
uint8 y = divisor >> (n-64); // Most of the way on divisor
if (y == 0) return 1; // Check if result will be too big
y >>= 1; // Divide divisor by final bit
power <<= 63;
uint8 max;
if (y == 0) {
max = 0;
max -= 1; // Could be maximal
// Check if divisor is a power of 2
if ((((uint8)1) << (n-64)) == divisor)
return 1;
}
else
max = power / y + 1;
uint8 min = power / (y+1);
if (min != 0)
min -= 1;
uint8 fullpower[2];
fullpower[1] = ((uint8)1)<<(n-64);
fullpower[0] = 0;
uint8 mult[2];
mult[0] = 0;
mult[1] = 0;
uint8 tmpq = 0;
while(max > min+1) {
tmpq = max + min;
if (tmpq < min) {
tmpq = (tmpq>>1) + 0x8000000000000000L;
}
else
tmpq >>= 1;
mult64to128(mult,divisor,tmpq);
if (unsignedCompare128(fullpower,mult) < 0)
max = tmpq-1;
else
min = tmpq;
}
// min is now our putative quotient
if (tmpq != min)
mult64to128(mult,divisor,min);
unsignedSubtract128(fullpower,mult); // Calculate remainder
// min might be 1 too small
if (fullpower[1] != 0 || fullpower[0] >= divisor) {
q = min + 1;
r = fullpower[0] - divisor;
}
else {
q = min;
r = fullpower[0];
}
return 0;
}
} // End namespace ghidra

View File

@ -577,10 +577,5 @@ extern int4 count_leading_zeros(uintb val); ///< Return the number of leading z
extern uintb coveringmask(uintb val); ///< Return a mask that \e covers the given value
extern int4 bit_transitions(uintb val,int4 sz); ///< Calculate the number of bit transitions in the sized value
extern void mult64to128(uint8 *res,uint8 x,uint8 y);
extern void unsignedSubtract128(uint8 *a,uint8 *b);
extern int4 unsignedCompare128(uint8 *a,uint8 *b);
extern int4 power2Divide(int4 n,uint8 divisor,uint8 &q,uint8 &r);
} // End namespace ghidra
#endif

View File

@ -1600,6 +1600,15 @@ void ParamListStandardOut::initialize(void)
}
}
/// \brief Find the return value storage using the older \e fallback method
///
/// Given the active set of trial locations that might hold (pieces of) the return value, calculate
/// the best matching ParamEntry from \b this ParamList and mark all the trials that are contained
/// in the ParamEntry as \e used. If \b firstOnly is \b true, the ParamList is assumed to contain
/// partial storage locations that might get used for return values split storage. In this case,
/// only the first ParamEntry in a storage class is allowed to match.
/// \param active is the set of active trials
/// \param firstOnly is \b true if only the first entry in a storage class can match
void ParamListStandardOut::fillinMapFallback(ParamActive *active,bool firstOnly) const
{

View File

@ -286,6 +286,7 @@ public:
Varnode *newUnique(int4 s,Datatype *ct=(Datatype *)0); ///< Create a new \e temporary Varnode
Varnode *newCodeRef(const Address &m); ///< Create a code address \e annotation Varnode
Varnode *setInputVarnode(Varnode *vn); ///< Mark a Varnode as an input to the function
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
void adjustInputVarnodes(const Address &addr,int4 sz);
void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode

View File

@ -372,6 +372,36 @@ Varnode *Funcdata::setInputVarnode(Varnode *vn)
return vn;
}
/// Construct a constant Varnode up to 128 bits, using INT_ZEXT and PIECE if necessary.
/// This method is temporary until we have full extended precision constants.
/// \param s is the size of the Varnode in bytes
/// \param val is the 128-bit value in 2 64-bit chunks
/// \param op is point before which any new PcodeOp should get inserted
/// \return the new effective constant Varnode
Varnode *Funcdata::newExtendedConstant(int4 s,uint8 *val,PcodeOp *op)
{
if (s <= 8)
return newConstant(s, val[0]);
Varnode *newConstVn;
if (val[1] == 0) {
PcodeOp *extOp = newOp(1,op->getAddr());
opSetOpcode(extOp,CPUI_INT_ZEXT);
newConstVn = newUniqueOut(s,extOp);
opSetInput(extOp,newConstant(8,val[0]),0);
opInsertBefore(extOp,op);
}
else {
PcodeOp *pieceOp = newOp(2,op->getAddr());
opSetOpcode(pieceOp,CPUI_PIECE);
newConstVn = newUniqueOut(s,pieceOp);
opSetInput(pieceOp,newConstant(8,val[1]),0); // Most significant piece
opSetInput(pieceOp,newConstant(8,val[0]),1); // Least significant piece
opInsertBefore(pieceOp,op);
}
return newConstVn;
}
/// \brief Adjust input Varnodes contained in the given range
///
/// After this call, a single \e input Varnode will exist that fills the given range.

View File

@ -54,6 +54,7 @@ class PrimitiveExtractor {
union_invalid = 16 ///< Unions are treated as an illegal element
};
public:
/// \brief A primitive data-type and its offset within the containing data-type
class Primitive {
public:
Datatype *dt; ///< Primitive data-type
@ -71,7 +72,7 @@ public:
PrimitiveExtractor(Datatype *dt,bool unionIllegal,int4 offset,int4 max); ///< Constructor
int4 size(void) const { return primitives.size(); } ///< Return the number of primitives extracted
const Primitive &get(int4 i) const { return primitives[i]; } ///< Get a particular primitive
bool isValid(void) const { return (flags & invalid) == 0; }
bool isValid(void) const { return (flags & invalid) == 0; } ///< Return \b true if primitives were successfully extracted
bool containsUnknown(void) const { return (flags & unknown_element)!=0; } ///< Are there \b unknown elements
bool isAligned(void) const { return (flags & unaligned)==0; } ///< Are all elements aligned
bool containsHoles(void) const { return (flags & extra_space)!=0; } ///< Is there empty space that is not padding

View File

@ -0,0 +1,334 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "multiprecision.hh"
namespace ghidra {
extern int4 count_leading_zeros(uintb val); ///< Return the number of leading zero bits in the given value
/// \brief Multi-precision logical left shift by a constant amount
///
/// \b in and \b out arrays are specified and can point to the same storage.
/// \param num is the number 64-bit words in the extended precision integers
/// \param in is the 128-bit value to shift
/// \param out is the container for the 128-bit result
/// \param sa is the number of bits to shift
static void leftshift(int4 num,uint8 *in,uint8 *out,int4 sa)
{
int4 inIndex = num - 1 - sa / 64;
sa = sa % 64;
int4 outIndex = num - 1;
if (sa == 0) {
for(;inIndex>=0;--inIndex) {
out[outIndex--] = in[inIndex];
}
for(;outIndex>=0;--outIndex) {
out[outIndex] = 0;
}
}
else {
for(;inIndex>0;--inIndex) {
out[outIndex--] = (in[inIndex] << sa) | (in[inIndex-1] >> (64-sa));
}
out[outIndex--] = in[0] << sa;
for(;outIndex>=0;--outIndex) {
out[outIndex] = 0;
}
}
}
/// \param in is the 128-bit input (as 2 64-bit words)
/// \param out will hold the 128-bit result
/// \param sa is the number of bits to shift
void leftshift128(uint8 *in,uint8 *out,int4 sa)
{
leftshift(2,in,out,sa);
}
/// \brief Compare two multi-precision unsigned integers
///
/// -1, 0, or 1 is returned depending on if the first integer is less than, equal to, or greater than
/// the second integer.
/// \param num is the number 64-bit words in the extended precision integers
/// \param in1 is the first integer to compare
/// \param in2 is the second integer to compare
/// \return -1, 0, or 1
static inline int4 ucompare(int4 num,uint8 *in1,uint8 *in2)
{
for(int4 i=num-1;i>=0;--i) {
if (in1[i] != in2[i])
return (in1[i] < in2[i]) ? -1 : 1;
}
return 0;
}
/// \param in1 is the first 128-bit value (as 2 64-bit words) to compare
/// \param in2 is the second 128-bit value
/// \return \b true if the first value is less than the second value
bool uless128(uint8 *in1,uint8 *in2)
{
return ucompare(2,in1,in2) < 0;
}
/// \param in1 is the first 128-bit value (as 2 64-bit words) to compare
/// \param in2 is the second 128-bit value
/// \return \b true if the first value is less than or equal to the second value
bool ulessequal128(uint8 *in1,uint8 *in2)
{
return ucompare(2,in1,in2) <= 0;
}
/// \brief Multi-precision add operation
///
/// \param num is the number 64-bit words in the extended precision integers
/// \param in1 is the first integer
/// \param in2 is the integer added to the first
/// \param out is where the add result is stored
static inline void add(int4 num,uint8 *in1,uint8 *in2,uint8 *out)
{
uint8 carry = 0;
for(int4 i=0;i<num;++i) {
uint8 tmp = in2[i] + carry;
uint8 tmp2 = in1[i] + tmp;
out[i] = tmp2;
carry = (tmp < in2[i] || tmp2 < tmp) ? 1 : 0;
}
}
/// \param in1 is the first 128-bit value (as 2 64-bit words) to add
/// \param in2 is the second 128-bit value to add
/// \param out will hold the 128-bit result
void add128(uint8 *in1,uint8 *in2,uint8 *out)
{
add(2,in1,in2,out);
}
/// \brief Multi-precision subtract operation
///
/// \param num is the number 64-bit words in the extended precision integers
/// \param in1 is the first integer
/// \param in2 is the integer subtracted from the first
/// \param out is where the subtraction result is stored
static inline void subtract(int4 num,uint8 *in1,uint8 *in2,uint8 *out)
{
uint8 borrow = 0;
for(int4 i=0;i<num;++i) {
uint8 tmp = in2[i] + borrow;
borrow = (tmp < in2[i] || in1[i] < tmp) ? 1: 0;
out[i] = in1[i] - tmp;
}
}
/// \param in1 is the first 128-bit value (as 2 64-bit words)
/// \param in2 is the second 128-bit value to subtract
/// \param out will hold the 128-bit result
void subtract128(uint8 *in1,uint8 *in2,uint8 *out)
{
subtract(2,in1,in2,out);
}
/// \brief Split an array of 64-bit words into an array of 32-bit words
///
/// The arrays must already be allocated. The least significant half of each 64-bit word is put
/// into the 32-bit word array first. The index of the most significant non-zero 32-bit word is
/// calculated and returned as the \e effective size of the resulting array.
/// \param num is the number of 64-bit words to split
/// \param val is the array of 64-bit words
/// \param res is the array that will hold the 32-bit words
/// \return the effective size of the 32-bit word array
static int4 split64_32(int4 num,uint8 *val,uint4 *res)
{
int4 m = 0;
for(int4 i=0;i<num;++i) {
uint4 hi = val[i] >> 32;
uint4 lo = val[i] & 0xffffffff;
if (hi != 0)
m = i*2 + 2;
else if (lo != 0)
m = i*2 + 1;
res[i*2] = lo;
res[i*2+1] = hi;
}
return m;
}
/// \brief Pack an array of 32-bit words into an array of 64-bit words
///
/// The arrays must already be allocated. The 64-bit word array is padded out with zeroes if
/// the specified size exceeds the provided number of 32-bit words.
/// \param num is the number of 64-bit words in the resulting array
/// \param max is the number of 32-bit words to pack
/// \param out is the array of 64-bit words
/// \param in is the array of 32-bit words
static void pack32_64(int4 num,int4 max,uint8 *out,uint4 *in)
{
int4 j = num * 2 - 1;
for(int4 i=num-1;i>=0;--i) {
uint8 val;
val = (j<max) ? in[j] : 0;
val <<= 32;
j -= 1;
if (j < max)
val |= in[j];
j -= 1;
out[i] = val;
}
}
/// \brief Logical shift left for an extended integer in 32-bit word arrays
///
/// \param arr is the array of 32-bit words
/// \param size is the number of words in the array
/// \param sa is the number of bits to shift
static void shift_left(uint4 *arr,int4 size,int4 sa)
{
if (sa == 0) return;
for (int4 i = size - 1; i > 0; --i)
arr[i] = (arr[i] << sa) | (arr[i-1] >> (32-sa));
arr[0] = arr[0] << sa;
}
/// \brief Logical shift right for an extended integer in 32-bit word arrays
///
/// \param arr is the array of 32-bit words
/// \param size is the number of words in the array
/// \param sa is the number of bits to shift
static void shift_right(uint4 *arr,int4 size,int4 sa)
{
if (sa == 0) return;
for(int4 i=0;i<size-1;++i)
arr[i] = (arr[i] >> sa) | (arr[i+1] << (32-sa));
arr[size-1] = arr[size -1] >> sa;
}
/// \brief Knuth's algorithm d, for integer division
///
/// The numerator and denominator, expressed in 32-bit \e digits, are provided.
/// The algorithm calculates the quotient and the remainder is left in the array originally
/// containing the numerator.
/// \param m is the number of 32-bit digits in the numerator
/// \param n is the number of 32-bit digits in the denominator
/// \param u is the numerator and will hold the remainder
/// \param v is the denominator
/// \param q will hold the final quotient
static void knuth_algorithm_d(int4 m,int4 n,uint4 *u,uint4 *v,uint4 *q)
{
int4 s = count_leading_zeros(v[n-1]) - 8*(sizeof(uintb)-sizeof(uint4));
shift_left(v,n,s);
shift_left(u,m,s);
for(int4 j=m-n-1;j>=0;--j) {
uint8 tmp = ((uint8)u[n+j] << 32) + u[n-1+j];
uint8 qhat = tmp / v[n-1];
uint8 rhat = tmp % v[n-1];
do {
if (qhat <= 0xffffffff && qhat * v[n-2] <= (rhat << 32) + u[n-2+j])
break;
qhat -= 1;
rhat += v[n-1];
} while(rhat <= 0xffffffff);
uint8 carry = 0;
int8 t;
for (int4 i=0;i<n;++i) {
tmp = qhat*v[i];
t = u[i+j] - carry - (tmp & 0xffffffff);
u[i+j] = t;
carry = (tmp >> 32) - (t >> 32);
}
t = u[j+n] - carry;
u[j+n] = t;
q[j] = qhat;
if (t < 0) {
q[j] -= 1;
carry = 0;
for(int4 i=0;i<n;++i) {
tmp = u[i+j] + (v[i] + carry);
u[i+j] = tmp;
carry = tmp >> 32;
}
u[j+n] += carry;
}
}
shift_right(u,m,s);
}
/// \param numer holds the 2 64-bit words of the numerator
/// \param denom holds the 2 words of the denominator
/// \param quotient_res will hold the 2 words of the quotient
/// \param remainder_res will hold the 2 words of the remainder
void udiv128(uint8 *numer,uint8 *denom,uint8 *quotient_res,uint8 *remainder_res)
{
if (numer[1] == 0 && denom[1] == 0) {
quotient_res[0] = numer[0] / denom[0];
quotient_res[1] = 0;
remainder_res[0] = numer[0] % denom[0];
remainder_res[1] = 0;
return;
}
uint4 v[4];
uint4 u[5]; // Array needs one more entry for normalization overflow
uint4 q[4];
int4 n = split64_32(2,denom,v);
if (n == 0) {
throw LowlevelError("divide by 0");
}
int4 m = split64_32(2,numer,u);
if ( m < n || ( (n==m) && u[n-1] < v[n-1])) {
// denominator is smaller than the numerator, quotient is 0
quotient_res[0] = 0;
quotient_res[1] = 0;
remainder_res[0] = numer[0];
remainder_res[1] = numer[1];
return;
}
u[m] = 0;
m += 1; // Extend u array by 1 to account for normalization
if (n == 1) {
uint4 d = v[0];
uint4 rem = 0;
for(int4 i=m-1;i>=0;--i) {
uint8 tmp = ((uint8)rem << 32) + u[i];
q[i] = tmp / d;
u[i] = 0;
rem = tmp % d;
}
u[0] = rem; // Last carry is final remainder
}
else {
knuth_algorithm_d(m,n,u,v,q);
}
pack32_64(2,m-n,quotient_res,q);
pack32_64(2,m-1,remainder_res,u);
}
} // End namespace ghidra

View File

@ -0,0 +1,42 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file multiprecision.hh
/// \brief Multi-precision integers
#ifndef __CPUI_MULTIPRECISION__
#define __CPUI_MULTIPRECISION__
#include "error.hh"
namespace ghidra {
extern void leftshift128(uint8 *in,uint8 *out,int4 sa); ///< 128-bit INT_LEFT operation with constant shift amount
extern bool uless128(uint8 *in1,uint8 *in2); ///< 128-bit INT_LESS operation
extern bool ulessequal128(uint8 *in1,uint8 *in2); ///< 128-bit INT_LESSEQUAL operation
extern void udiv128(uint8 *numer,uint8 *denom,uint8 *quotient_res,uint8 *remainder_res); ///< 128-bit INT_DIV
extern void add128(uint8 *in1,uint8 *in2,uint8 *out); ///< 128-bit INT_ADD operation
extern void subtract128(uint8 *in1,uint8 *in2,uint8 *out); ///< 128-bit INT_SUB operation
/// \brief Set a 128-bit value (2 64-bit words) from a 64-bit value
///
/// \param res will hold the 128-bit value
/// \param val is the 64-bit value to set from
inline void set_u128(uint8 *res,uint8 val) {
res[0] = val;
res[1] = 0;
}
} // End namespace ghidra
#endif

View File

@ -17,6 +17,7 @@
#include "coreaction.hh"
#include "subflow.hh"
#include "rangeutil.hh"
#include "multiprecision.hh"
namespace ghidra {
@ -1884,8 +1885,12 @@ int4 RuleDoubleShift::applyOp(PcodeOp *op,Funcdata &data)
}
else if (sa1 == sa2 && size <= sizeof(uintb)) { // FIXME: precision
mask = calc_mask(size);
if (opc1 == CPUI_INT_LEFT)
if (opc1 == CPUI_INT_LEFT) {
// The INT_LEFT is highly likely to be a multiply, so don't collapse to an INT_AND if there
// are other uses of the intermediate value.
if (secvn->loneDescend() == (PcodeOp *)0) return 0;
mask = (mask<<sa1) & mask;
}
else
mask = (mask>>sa1) & mask;
newvn = data.newConstant(size,mask);
@ -7359,16 +7364,15 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
OpCode shiftopc;
PcodeOp *subop = findSubshift(op,n,shiftopc);
if (subop == (PcodeOp *)0) return 0;
// TODO: Cannot currently support 128-bit arithmetic, except in special case of 2^64
if (n > 64) return 0;
if (n > 127) return 0; // Up to 128-bits
Varnode *multvn = subop->getIn(0);
if (!multvn->isWritten()) return 0;
PcodeOp *multop = multvn->getDef();
if (multop->code() != CPUI_INT_MULT) return 0;
uintb multConst;
int4 constExtType = multop->getIn(1)->isConstantExtended(multConst);
if (constExtType < 0) return 0;
uint8 multConst[2];
if (!multop->getIn(1)->isConstantExtended(multConst))
return 0;
Varnode *extvn = multop->getIn(0);
if (!extvn->isWritten()) return 0;
@ -7381,20 +7385,10 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
if (op->code()==CPUI_INT_RIGHT) return 0;
}
uintb newc;
if (n < 64 || (extvn->getSize() <= 8)) {
uintb pow = 1;
pow <<= n; // Calculate 2^n
newc = multConst + pow;
}
else {
if (constExtType != 2) return 0; // TODO: Can't currently represent
if (!signbit_negative(multConst,8)) return 0;
// Adding 2^64 to a sign-extended 64-bit value with its sign set, causes all the
// set extension bits to be cancelled out, converting it into a
// zero-extended 64-bit value.
constExtType = 1; // Set extension of constant to INT_ZEXT
}
uint8 power[2];
set_u128(power, 1);
leftshift128(power,power,n); // power = 2^n
add128(multConst,power,multConst); // multConst += 2^n
Varnode *x = extop->getIn(0);
list<PcodeOp *>::const_iterator iter;
@ -7405,17 +7399,7 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
continue;
// Construct the new constant
Varnode *newConstVn;
if (constExtType == 0)
newConstVn = data.newConstant(extvn->getSize(),newc);
else {
// Create new extension of the constant
PcodeOp *newExtOp = data.newOp(1,op->getAddr());
data.opSetOpcode(newExtOp,(constExtType==1) ? CPUI_INT_ZEXT : CPUI_INT_SEXT);
newConstVn = data.newUniqueOut(extvn->getSize(),newExtOp);
data.opSetInput(newExtOp,data.newConstant(8,multConst),0);
data.opInsertBefore(newExtOp,op);
}
Varnode *newConstVn = data.newExtendedConstant(extvn->getSize(), multConst, op);
// Construct the new multiply
PcodeOp *newmultop = data.newOp(2,op->getAddr());
@ -7532,7 +7516,8 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
if (!multvn->isWritten()) return 0;
PcodeOp *multop = multvn->getDef();
if (multop->code() != CPUI_INT_MULT) return 0;
if (!multop->getIn(1)->isConstant()) return 0;
uint8 multConst[2];
if (!multop->getIn(1)->isConstantExtended(multConst)) return 0;
Varnode *zextvn = multop->getIn(0);
if (!zextvn->isWritten()) return 0;
PcodeOp *zextop = zextvn->getDef();
@ -7545,14 +7530,16 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
if (addop->code() != CPUI_INT_ADD) continue;
if ((addop->getIn(0)!=z)&&(addop->getIn(1)!=z)) continue;
uintb pow = 1;
pow <<= n; // Calculate 2^n
uintb newc = multop->getIn(1)->getOffset() + pow;
uint8 pow[2];
set_u128(pow, 1);
leftshift128(pow,pow,n); // Calculate 2^n
add128(multConst, pow, multConst); // multConst = multConst + 2^n
PcodeOp *newmultop = data.newOp(2,op->getAddr());
data.opSetOpcode(newmultop,CPUI_INT_MULT);
Varnode *newmultvn = data.newUniqueOut(zextvn->getSize(),newmultop);
data.opSetInput(newmultop,zextvn,0);
data.opSetInput(newmultop,data.newConstant(zextvn->getSize(),newc),1);
Varnode *newConstVn = data.newExtendedConstant(zextvn->getSize(), multConst, op);
data.opSetInput(newmultop,newConstVn,1);
data.opInsertBefore(newmultop,op);
PcodeOp *newshiftop = data.newOp(2,op->getAddr());
@ -7591,7 +7578,7 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
/// \param xsize will hold the number of (non-zero) bits in the numerand
/// \param extopc holds whether the extension is INT_ZEXT or INT_SEXT
/// \return the extended numerand if possible, or the unextended numerand, or NULL
Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &extopc)
Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uint8 *y,int4 &xsize,OpCode &extopc)
{
PcodeOp *curOp = op;
@ -7621,18 +7608,22 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e
if (curOp->code() != CPUI_INT_MULT) return (Varnode *)0; // There MUST be an INT_MULT
Varnode *inVn = curOp->getIn(0);
if (!inVn->isWritten()) return (Varnode *)0;
if (inVn->isConstantExtended(y) >= 0) {
if (inVn->isConstantExtended(y)) {
inVn = curOp->getIn(1);
if (!inVn->isWritten()) return (Varnode *)0;
}
else if (curOp->getIn(1)->isConstantExtended(y) < 0)
else if (!curOp->getIn(1)->isConstantExtended(y))
return (Varnode *)0; // There MUST be a constant
Varnode *resVn;
PcodeOp *extOp = inVn->getDef();
extopc = extOp->code();
if (extopc != CPUI_INT_SEXT) {
uintb nzMask = inVn->getNZMask();
uintb nzMask;
if (extopc == CPUI_INT_ZEXT)
nzMask = extOp->getIn(0)->getNZMask();
else
nzMask = inVn->getNZMask();
xsize = 8*sizeof(uintb) - count_leading_zeros(nzMask);
if (xsize == 0) return (Varnode *)0;
if (xsize > 4*inVn->getSize()) return (Varnode *)0;
@ -7672,44 +7663,50 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e
/// Do some additional checks on the parameters as an optimized encoding
/// of a divisor.
/// \param n is the power of 2
/// \param y is the multiplicative coefficient
/// \param y is the (up to 128-bit) multiplicative coefficient
/// \param xsize is the maximum power of 2
/// \return the divisor or 0 if the checks fail
uintb RuleDivOpt::calcDivisor(uintb n,uint8 y,int4 xsize)
uintb RuleDivOpt::calcDivisor(uintb n,uint8 *y,int4 xsize)
{
if (n > 127) return 0; // Not enough precision
if (y <= 1) return 0; // Boundary cases are wrong form
if (n > 127 || xsize > 64) return 0; // Not enough precision
uint8 power[2];
uint8 q[2];
uint8 r[2];
set_u128(power, 1);
if (ulessequal128(y, power)) // Boundary cases, y <= 1, are wrong form
return 0;
uint8 d,r;
uint8 power;
if (n < 64) {
power = ((uint8)1) << n;
d = power / (y-1);
r = power % (y-1);
subtract128(y, power, y); // y = y - 1
leftshift128(power, power, n); // power = 2^n
udiv128(power, y, q, r);
if (0 != q[1])
return 0; // Result is bigger than 64-bits
if (uless128(y,q)) return 0; // if y < q
uint8 diff = 0;
if (!uless128(r,q)) { // if r >= q
// Its possible y is 1 too big giving us a q that is smaller by 1 than the correct value
q[0] += 1; // Adjust to bigger q
subtract128(r,y,r); // and remainder for the smaller y
add128(r, q, r);
if (!uless128(r,q)) return 0;
diff = q[0]; // Using y that is off by one adds extra error, affecting allowable maxx
}
else {
if (0 != power2Divide(n,y-1,d,r))
return 0; // Result is bigger than 64-bits
}
if (d>=y) return 0;
if (r >= d) return 0;
// The optimization of division to multiplication
// by the reciprocal holds true, if the maximum value
// of x times the remainder is less than 2^n
uint8 maxx = 1;
maxx <<= xsize;
// of x times q-r is less than 2^n
uint8 maxx = (xsize == 64) ? 0 : ((uint8)1) << xsize;
maxx -= 1; // Maximum possible x value
uint8 tmp;
if (n < 64)
tmp = power / (d-r); // r < d => divisor is non-zero
else {
uint8 unused;
if (0 != power2Divide(n,d-r,tmp,unused))
return (uintb)d; // tmp is bigger than 2^64 > maxx
}
if (tmp<=maxx) return 0;
return (uintb)d;
uint8 tmp[2];
uint8 denom[2];
diff += q[0] - r[0];
set_u128(denom,diff);
udiv128(power,denom, tmp, r);
if (0 != tmp[1])
return (uintb)q[0]; // tmp is bigger than 2^64 > maxx
if (tmp[0]<=maxx) return 0;
return (uintb)q[0];
}
/// \brief Replace sign-bit extractions from the first given Varnode with the second Varnode
@ -7785,7 +7782,7 @@ bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
Varnode *cvn = superOp->getIn(1);
if (!cvn->isConstant()) return true; // Might be a form where constant has propagated yet
int4 n,xsize;
uintb y;
uint8 y[2];
OpCode extopc;
Varnode *inVn = findForm(superOp, n, y, xsize, extopc);
if (inVn != (Varnode *)0) return true;
@ -7797,8 +7794,8 @@ bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
/// \brief Convert INT_MULT and shift forms into INT_DIV or INT_SDIV
///
/// The unsigned and signed variants are:
/// - `sub( (zext(V)*c)>>n, 0) => V / (2^n/(c-1))`
/// - `sub( (sext(V)*c)s>>n, 0) => V s/ (2^n/(c-1))`
/// - `sub( (zext(V)*c), d) >> e => V / (2^n/(c-1)) where n = d*8 + e`
/// - `sub( (sext(V)*c), d) s>> e => V s/ (2^n/(c-1)) where n = d*8 + e`
void RuleDivOpt::getOpList(vector<uint4> &oplist) const
{
@ -7811,7 +7808,7 @@ int4 RuleDivOpt::applyOp(PcodeOp *op,Funcdata &data)
{
int4 n,xsize;
uintb y;
uint8 y[2];
OpCode extOpc;
Varnode *inVn = findForm(op,n,y,xsize,extOpc);
if (inVn == (Varnode *)0) return 0;

View File

@ -1264,7 +1264,7 @@ public:
};
class RuleDivOpt : public Rule {
static uintb calcDivisor(uintb n,uint8 y,int4 xsize); ///< Calculate the divisor
static uintb calcDivisor(uintb n,uint8 *y,int4 xsize); ///< Calculate the divisor
static void moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data);
static bool checkFormOverlap(PcodeOp *op); ///< If form rooted at given PcodeOp is superseded by an overlapping form
public:
@ -1275,7 +1275,7 @@ public:
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
static Varnode *findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &extopc);
static Varnode *findForm(PcodeOp *op,int4 &n,uint8 *y,int4 &xsize,OpCode &extopc);
};
class RuleSignDiv2 : public Rule {

View File

@ -3706,6 +3706,7 @@ static void findSlaSpecs(vector<string> &res, const string &dir, const string &s
/// \param enforceLocalKeyWord is \b true to force all local variable definitions to use the \b local keyword
/// \param largeTemporaryWarning is \b true for individual warnings about temporary varnodes that are too large
/// \param caseSensitiveRegisterNames is \b true if register names are allowed to be case sensitive
/// \param debugOutput is \b true if the output file is written using the debug (XML) form of the .sla format
void SleighCompile::setAllOptions(const map<string,string> &defines, bool unnecessaryPcodeWarning,
bool lenientConflict, bool allCollisionWarning,
bool allNopWarning,bool deadTempWarning,bool enforceLocalKeyWord,

View File

@ -780,37 +780,55 @@ void Varnode::printRawHeritage(ostream &s,int4 depth) const
s << endl;
}
/// If \b this is a constant, or is extended (INT_ZEXT,INT_SEXT) from a constant,
/// the \e value of the constant is passed back and a non-negative integer is returned, either:
/// - 0 for a normal constant Varnode
/// - 1 for a zero extension (INT_ZEXT) of a normal constant
/// - 2 for a sign extension (INT_SEXT) of a normal constant
/// \param val is a reference to the constant value that is passed back
/// \return the extension code (or -1 if \b this cannot be interpreted as a constant)
int4 Varnode::isConstantExtended(uintb &val) const
/// If \b this is a constant, or is extended (INT_ZEXT,INT_SEXT,PIECE) from a constant,
/// the \e value of the constant (currently up to 128 bits) is passed back and \b true is returned.
/// \param val will hold the 128-bit constant value
/// \return \b true if a constant was recovered
bool Varnode::isConstantExtended(uint8 *val) const
{
if (isConstant()) {
val = getOffset();
return 0;
val[0] = getOffset();
val[1] = 0;
return true;
}
if (!isWritten()) return -1;
if (!isWritten() || size <= 8) return false;
if (size > 16) return false; // Currently only up to 128-bit values
OpCode opc = def->code();
if (opc == CPUI_INT_ZEXT) {
Varnode *vn0 = def->getIn(0);
if (vn0->isConstant()) {
val = vn0->getOffset();
return 1;
val[0] = vn0->getOffset();
val[1] = 0;
return true;
}
}
else if (opc == CPUI_INT_SEXT) {
Varnode *vn0 = def->getIn(0);
if (vn0->isConstant()) {
val = vn0->getOffset();
return 2;
val[0] = vn0->getOffset();
if (vn0->getSize() < 8)
val[0] = sign_extend(val[0], vn0->getSize(), size);
val[1] = (signbit_negative(val[0], 8)) ? 0xffffffffffffffffL : 0;
return true;
}
}
return -1;
else if (opc == CPUI_PIECE) {
Varnode *vnlo = def->getIn(1);
if (vnlo->isConstant()) {
val[0] = vnlo->getOffset();
Varnode *vnhi = def->getIn(0);
if (vnhi->isConstant()) {
val[1] = vnhi->getOffset();
if (vnlo->getSize() == 8)
return true;
val[0] |= val[1] << 8*vnlo->getSize();
val[1] >>= 8*(8-vnlo->getSize());
return true;
}
}
}
return false;
}
/// Make an initial determination of the Datatype of this Varnode. If a Datatype is already

View File

@ -290,7 +290,7 @@ public:
return (loc.getOffset() == val);
}
int4 isConstantExtended(uintb &val) const; ///< Is \b this an (extended) constant
bool isConstantExtended(uint8 *val) const; ///< Is \b this an (extended) constant
/// Return \b true if this Varnode is linked into the SSA tree
bool isHeritageKnown(void) const { return ((flags&(Varnode::insert|Varnode::constant|Varnode::annotation))!=0); }
bool isTypeLock(void) const { return ((flags&Varnode::typelock)!=0); } ///< Does \b this have a locked Datatype?

View File

@ -0,0 +1,292 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!-- Examples of optimized division and modulo for constants
81 89 91 93 95 97 99 101 103 107 111 112 115 119 121 123 125 -->
<bytechunk space="ram" offset="0x100000" readonly="true">
f30f1efa48ba53069e6ecd0f8b94488b
0f4889c848f7e24829d148d1e94801ca
488b4f0848c1ea064889c848891748ba
e10217b8c0052e7048f7e24829d148d1
e94801ca488b4f1048c1ea064889c848
89570848ba176881166881166848f7e2
4829d148d1e94801ca488b4f1848c1ea
064889c84889571048ba175860810516
586048f7e24829d148d1e94801ca488b
4f2048c1ea064889c84889571848ba31
d28e150823ed5848f7e24829d148d1e9
4801ca488b4f2848c1ea064889c84889
572048bad151812fae7ed05148f7e248
29d148d1e94801ca488b4f3048c1ea06
4889c84889572848ba15a8f52b056afd
4a48f7e24829d148d1e94801ca488b4f
3848c1ea064889c84889573048bae5ae
9f2d56866f4448f7e24829d148d1e948
01ca488b4f4048c1ea064889c8488957
3848bac527904acecb223e48f7e24829
d148d1e94801ca488b4f4848c1ea0648
89c84889574048ba6ff60bb1a2343e32
48f7e24829d148d1e94801ca488b4f50
48c1ea064889c84889574848bab95073
12880b352748f7e24829d148d1e94801
ca48b9942449922449922448c1ea0648
895750488b575848c1ea044889d048f7
e1488b4f604889c84889575848ba07cf
1128da6af01c48f7e24829d148d1e948
01ca488b4f6848c1ea064889c8488957
6048ba5d13815c13815c1348f7e24829
d148d1e94801ca488b4f7048c1ea0648
89c84889576848bae3fdc869be56cf0e
48f7e24829d148d1e94801ca488b4f78
48c1ea064889c84889577048ba11680a
81a610680a48f7e24829d148d1e94801
ca48c1ea0648895778488b8f80000000
48ba77be9f1a2fdd24064889c848f7e2
4829d148d1e94801ca48c1ea06488997
80000000c30000000000000000000000
f30f1efa48ba9581a75bf3c32265488b
0f4889c848c1f93f48f7ea48c1fa0548
29ca488b4f0848891748ba71810b5ce0
0217b84889c848f7ea4801ca48c1f93f
48c1fa064829ca488b4f104889570848
ba032dd0022dd0022d4889c848c1f93f
48f7ea48c1fa044829ca488b4f184889
571048ba030b2cb0c0020b2c4889c848
c1f93f48f7ea48c1fa044829ca488b4f
204889571848ba1969c70a849176ac48
89c848f7ea4801ca48c1f93f48c1fa06
4829ca488b4f284889572048bae9a8c0
17573fe8a84889c848f7ea4801ca48c1
f93f48c1fa064829ca488b4f30488957
2848ba0bd4fa9502b57ea54889c848f7
ea4801ca48c1f93f48c1fa064829ca48
8b4f384889573048ba73d7cf162bc337
a24889c848f7ea4801ca48c1f93f48c1
fa064829ca488b4f404889573848bae3
134825e765119f4889c848f7ea4801ca
48c1f93f48c1fa064829ca488b4f4848
89574048ba67bf102b4ae323134889c8
48c1f93f48f7ea48c1fa034829ca488b
4f504889574848ba5da83909c4859a93
4889c848f7ea4801ca48c1f93f48c1fa
064829ca488b4f584889575048ba2549
9224499224494889c848c1f93f48f7ea
48c1fa054829ca488b4f604889575848
bae13902455b0d9e234889c848c1f93f
48f7ea48c1fa044829ca488b4f684889
576048baaf8940ae8940ae894889c848
f7ea4801ca48c1f93f48c1fa064829ca
488b4f704889576848ba793f729aafd5
b3434889c848f7ea48c1f93f48c1fa05
4829ca488b4f784889577048ba093485
40530834854889c848f7ea4801ca48c1
f93f48c1fa064829ca48895778488b8f
8000000048bacff753e3a59bc4204889
c848c1f93f48f7ea48c1fa044829ca48
899780000000c3000000000000000000
f30f1efa488b0f488b775848ba53069e
6ecd0f8b944889c848f7e24889c84829
d048d1e84801c248c1ea06488d04d248
bae10217b8c0052e70488d04c04829c1
48890f488b4f084889c848f7e24889c8
4829d048d1e84801c248c1ea06488d04
92488d0442488d04c248ba1768811668
8116684829c148894f08488b4f104889
c848f7e24889c84829d048d1e84801c2
48c1ea06486bd25b4829d148ba175860
810516586048894f10488b4f184889c8
48f7e24889c84829d048d1e84801c248
c1ea06488d14524889d048c1e0054829
d048ba31d28e150823ed584829c14889
4f18488b4f204889c848f7e24889c848
29d048d1e84801c248c1ea06488d0452
48c1e0054829d048bad151812fae7ed0
514829c148894f20488b4f284889c848
f7e24889c84829d048d1e84801c248c1
ea06488d045248c1e0054801c24829d1
48ba15a8f52b056afd4a48894f28488b
4f304889c848f7e24889c84829d048d1
e84801c248c1ea06488d04524889c248
c1e2054801d048bae5ae9f2d56866f44
4829c148894f30488b4f384889c848f7
e24889c84829d048d1e84801c248c1ea
06488d0492488d0480488d048248bac5
27904acecb223e4829c148894f38488b
4f404889c848f7e24889c84829d048d1
e84801c248c1ea06486bd2674829d148
ba6ff60bb1a2343e3248894f40488b4f
484889c848f7e24889c84829d048d1e8
4801c248c1ea06486bd26b4829d148ba
b9507312880b352748894f48488b4f50
4889c848f7e24889c84829d048d1e848
01c248c1ea06486bd26f4829d14889f2
48c1ea0448894f5048b9942449922449
92244889d048f7e1488d0cd500000000
4829d148ba07cf1128da6af01c48c1e1
044829ce488b4f60488977584889c848
f7e24889c84829d048d1e84801c248c1
ea06486bd2734829d148ba5d13815c13
815c1348894f60488b4f684889c848f7
e24889c84829d048d1e84801c248c1ea
06486bd2774829d148bae3fdc869be56
cf0e48894f68488b4f704889c848f7e2
4889c84829d048d1e84801c248c1ea06
4889d048c1e0044829d0488d04c248ba
11680a81a610680a4829c148894f7048
8b4f784889c848f7e24889c84829d048
d1e84801c248c1ea06486bd27b4829d1
48ba77be9f1a2fdd240648894f78488b
8f800000004889c848f7e24889c84829
d048d1e84801c248c1ea064889d048c1
e0054829d0488d04824829c148898f80
000000c3000000000000000000000000
f30f1efa48ba9581a75bf3c32265488b
0f4889c848f7ea4889c848c1f83f48c1
fa054829c2488d04d248ba71810b5ce0
0217b8488d04c04829c148890f488b4f
084889c848f7ea4889c848c1f83f4801
ca48c1fa064829c2488d0492488d0442
488d04c248ba032dd0022dd0022d4829
c148894f08488b4f104889c848f7ea48
89c848c1f83f48c1fa044829c2486bd2
5b4829d148ba030b2cb0c0020b2c4889
4f10488b4f184889c848f7ea4889c848
c1f83f48c1fa044829c2488d14524889
d048c1e0054829d048ba1969c70a8491
76ac4829c148894f18488b4f204889c8
48f7ea4889c848c1f83f4801ca48c1fa
064829c2488d045248c1e0054829d048
bae9a8c017573fe8a84829c148894f20
488b4f284889c848f7ea4889c848c1f8
3f4801ca48c1fa064829c2488d045248
c1e0054801c24829d148ba0bd4fa9502
b57ea548894f28488b4f304889c848f7
ea4889c848c1f83f4801ca48c1fa0648
29c2488d04524889c248c1e2054801d0
48ba73d7cf162bc337a24829c148894f
30488b4f384889c848f7ea4889c848c1
f83f4801ca48c1fa064829c2488d0492
488d0480488d048248bae3134825e765
119f4829c148894f38488b4f404889c8
48f7ea4889c848c1f83f4801ca48c1fa
064829c2486bd2674829d148ba67bf10
2b4ae3231348894f40488b4f484889c8
48f7ea4889c848c1f83f48c1fa034829
c2486bd26b4829d148ba5da83909c485
9a9348894f48488b4f504889c848f7ea
4889c848c1f83f4801ca48c1fa064829
c2486bd26f4829d148ba254992244992
244948894f50488b4f584889c848f7ea
4889c848c1f83f48c1fa054829c2488d
04d5000000004829d048bae13902455b
0d9e2348c1e0044829c148894f58488b
4f604889c848f7ea4889c848c1f83f48
c1fa044829c2486bd2734829d148baaf
8940ae8940ae8948894f60488b4f6848
89c848f7ea4889c848c1f83f4801ca48
c1fa064829c2486bd2774829d148ba79
3f729aafd5b34348894f68488b4f7048
89c848f7ea4889c848c1fa0548c1f83f
4829c24889d048c1e0044829d0488d04
c248ba09348540530834854829c14889
4f70488b4f784889c848f7ea4889c848
c1f83f4801ca48c1fa064829c2486bd2
7b4829d148bacff753e3a59bc4204889
4f78488b8f800000004889c848f7ea48
89c848c1f83f48c1fa044829c24889d0
48c1e0054829d0488d04824829c14889
8f80000000c3
</bytechunk>
<symbol space="ram" offset="0x100000" name="divoptu"/>
<symbol space="ram" offset="0x100280" name="divopti"/>
<symbol space="ram" offset="0x100500" name="modoptu"/>
<symbol space="ram" offset="0x100880" name="modopti"/>
</binaryimage>
<script>
<com>option integerformat dec</com>
<com>parse line extern void divoptu(uint8 *divu);</com>
<com>lo fu divoptu</com>
<com>decompile</com>
<com>print C</com>
<com>parse line extern void divopti(int8 *divi);</com>
<com>lo fu divopti</com>
<com>decompile</com>
<com>print C</com>
<com>parse line extern void modoptu(uint8 *modu);</com>
<com>lo fu modoptu</com>
<com>decompile</com>
<com>print C</com>
<com>parse line extern void modopti(int8 *modi);</com>
<com>lo fu modopti</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Unsigned Division #1" min="1" max="1">\*divu = \*divu / 81;</stringmatch>
<stringmatch name="Unsigned Division #2" min="1" max="1">divu\[1\] = divu\[1\] / 89;</stringmatch>
<stringmatch name="Unsigned Division #3" min="1" max="1">divu\[2\] = divu\[2\] / 91;</stringmatch>
<stringmatch name="Unsigned Division #4" min="1" max="1">divu\[3\] = divu\[3\] / 93;</stringmatch>
<stringmatch name="Unsigned Division #5" min="1" max="1">divu\[4\] = divu\[4\] / 95;</stringmatch>
<stringmatch name="Unsigned Division #6" min="1" max="1">divu\[5\] = divu\[5\] / 97;</stringmatch>
<stringmatch name="Unsigned Division #7" min="1" max="1">divu\[6\] = divu\[6\] / 99;</stringmatch>
<stringmatch name="Unsigned Division #8" min="1" max="1">divu\[7\] = divu\[7\] / 101;</stringmatch>
<stringmatch name="Unsigned Division #9" min="1" max="1">divu\[8\] = divu\[8\] / 103;</stringmatch>
<stringmatch name="Unsigned Division #10" min="1" max="1">divu\[9\] = divu\[9\] / 107;</stringmatch>
<stringmatch name="Unsigned Division #11" min="1" max="1">divu\[10\] = divu\[10\] / 111;</stringmatch>
<stringmatch name="Unsigned Division #12" min="1" max="1">divu\[11\] = divu\[11\] / 112;</stringmatch>
<stringmatch name="Unsigned Division #13" min="1" max="1">divu\[12\] = divu\[12\] / 115;</stringmatch>
<stringmatch name="Unsigned Division #14" min="1" max="1">divu\[13\] = divu\[13\] / 119;</stringmatch>
<stringmatch name="Unsigned Division #15" min="1" max="1">divu\[14\] = divu\[14\] / 121;</stringmatch>
<stringmatch name="Unsigned Division #16" min="1" max="1">divu\[15\] = divu\[15\] / 123;</stringmatch>
<stringmatch name="Unsigned Division #17" min="1" max="1">divu\[16\] = divu\[16\] / 125;</stringmatch>
<stringmatch name="Signed Division #1" min="1" max="1">\*divi = \*divi / 81;</stringmatch>
<stringmatch name="Signed Division #2" min="1" max="1">divi\[1\] = divi\[1\] / 89;</stringmatch>
<stringmatch name="Signed Division #3" min="1" max="1">divi\[2\] = divi\[2\] / 91;</stringmatch>
<stringmatch name="Signed Division #4" min="1" max="1">divi\[3\] = divi\[3\] / 93;</stringmatch>
<stringmatch name="Signed Division #5" min="1" max="1">divi\[4\] = divi\[4\] / 95;</stringmatch>
<stringmatch name="Signed Division #6" min="1" max="1">divi\[5\] = divi\[5\] / 97;</stringmatch>
<stringmatch name="Signed Division #7" min="1" max="1">divi\[6\] = divi\[6\] / 99;</stringmatch>
<stringmatch name="Signed Division #8" min="1" max="1">divi\[7\] = divi\[7\] / 101;</stringmatch>
<stringmatch name="Signed Division #9" min="1" max="1">divi\[8\] = divi\[8\] / 103;</stringmatch>
<stringmatch name="Signed Division #10" min="1" max="1">divi\[9\] = divi\[9\] / 107;</stringmatch>
<stringmatch name="Signed Division #11" min="1" max="1">divi\[10\] = divi\[10\] / 111;</stringmatch>
<stringmatch name="Signed Division #12" min="1" max="1">divi\[11\] = divi\[11\] / 112;</stringmatch>
<stringmatch name="Signed Division #13" min="1" max="1">divi\[12\] = divi\[12\] / 115;</stringmatch>
<stringmatch name="Signed Division #14" min="1" max="1">divi\[13\] = divi\[13\] / 119;</stringmatch>
<stringmatch name="Signed Division #15" min="1" max="1">divi\[14\] = divi\[14\] / 121;</stringmatch>
<stringmatch name="Signed Division #16" min="1" max="1">divi\[15\] = divi\[15\] / 123;</stringmatch>
<stringmatch name="Signed Division #17" min="1" max="1">divi\[16\] = divi\[16\] / 125;</stringmatch>
<stringmatch name="Unsigned Modulo #1" min="1" max="1">\*modu = \*modu % 81;</stringmatch>
<stringmatch name="Unsigned Modulo #2" min="1" max="1">modu\[1\] = modu\[1\] % 89;</stringmatch>
<stringmatch name="Unsigned Modulo #3" min="1" max="1">modu\[2\] = modu\[2\] % 91;</stringmatch>
<stringmatch name="Unsigned Modulo #4" min="1" max="1">modu\[3\] = modu\[3\] % 93;</stringmatch>
<stringmatch name="Unsigned Modulo #5" min="1" max="1">modu\[4\] = modu\[4\] % 95;</stringmatch>
<stringmatch name="Unsigned Modulo #6" min="1" max="1">modu\[5\] = modu\[5\] % 97;</stringmatch>
<stringmatch name="Unsigned Modulo #7" min="1" max="1">modu\[6\] = modu\[6\] % 99;</stringmatch>
<stringmatch name="Unsigned Modulo #8" min="1" max="1">modu\[7\] = modu\[7\] % 101;</stringmatch>
<stringmatch name="Unsigned Modulo #9" min="1" max="1">modu\[8\] = modu\[8\] % 103;</stringmatch>
<stringmatch name="Unsigned Modulo #10" min="1" max="1">modu\[9\] = modu\[9\] % 107;</stringmatch>
<stringmatch name="Unsigned Modulo #11" min="1" max="1">modu\[10\] = modu\[10\] % 111;</stringmatch>
<stringmatch name="Unsigned Modulo #12" min="1" max="1">modu\[11\] = modu\[11\] % 112;</stringmatch>
<stringmatch name="Unsigned Modulo #13" min="1" max="1">modu\[12\] = modu\[12\] % 115;</stringmatch>
<stringmatch name="Unsigned Modulo #14" min="1" max="1">modu\[13\] = modu\[13\] % 119;</stringmatch>
<stringmatch name="Unsigned Modulo #15" min="1" max="1">modu\[14\] = modu\[14\] % 121;</stringmatch>
<stringmatch name="Unsigned Modulo #16" min="1" max="1">modu\[15\] = modu\[15\] % 123;</stringmatch>
<stringmatch name="Unsigned Modulo #17" min="1" max="1">modu\[16\] = modu\[16\] % 125;</stringmatch>
<stringmatch name="Signed Modulo #1" min="1" max="1">\*modi = \*modi % 81;</stringmatch>
<stringmatch name="Signed Modulo #2" min="1" max="1">modi\[1\] = modi\[1\] % 89;</stringmatch>
<stringmatch name="Signed Modulo #3" min="1" max="1">modi\[2\] = modi\[2\] % 91;</stringmatch>
<stringmatch name="Signed Modulo #4" min="1" max="1">modi\[3\] = modi\[3\] % 93;</stringmatch>
<stringmatch name="Signed Modulo #5" min="1" max="1">modi\[4\] = modi\[4\] % 95;</stringmatch>
<stringmatch name="Signed Modulo #6" min="1" max="1">modi\[5\] = modi\[5\] % 97;</stringmatch>
<stringmatch name="Signed Modulo #7" min="1" max="1">modi\[6\] = modi\[6\] % 99;</stringmatch>
<stringmatch name="Signed Modulo #8" min="1" max="1">modi\[7\] = modi\[7\] % 101;</stringmatch>
<stringmatch name="Signed Modulo #9" min="1" max="1">modi\[8\] = modi\[8\] % 103;</stringmatch>
<stringmatch name="Signed Modulo #10" min="1" max="1">modi\[9\] = modi\[9\] % 107;</stringmatch>
<stringmatch name="Signed Modulo #11" min="1" max="1">modi\[10\] = modi\[10\] % 111;</stringmatch>
<stringmatch name="Signed Modulo #12" min="1" max="1">modi\[11\] = modi\[11\] % 112;</stringmatch>
<stringmatch name="Signed Modulo #13" min="1" max="1">modi\[12\] = modi\[12\] % 115;</stringmatch>
<stringmatch name="Signed Modulo #14" min="1" max="1">modi\[13\] = modi\[13\] % 119;</stringmatch>
<stringmatch name="Signed Modulo #15" min="1" max="1">modi\[14\] = modi\[14\] % 121;</stringmatch>
<stringmatch name="Signed Modulo #16" min="1" max="1">modi\[15\] = modi\[15\] % 123;</stringmatch>
<stringmatch name="Signed Modulo #17" min="1" max="1">modi\[16\] = modi\[16\] % 125;</stringmatch>
</decompilertest>