FloatEvaluation.h

Go to the documentation of this file.
00001 //===-- FloatEvaluation.h ---------------------------------------*- C++ -*-===//
00002 //
00003 //                     The KLEE Symbolic Virtual Machine
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 // FIXME: Ditch this and use APFloat.
00011 
00012 #ifndef KLEE_UTIL_FLOATS_H
00013 #define KLEE_UTIL_FLOATS_H
00014 
00015 #include "klee/util/Bits.h"     //bits64::truncateToNBits
00016 #include "IntEvaluation.h" //ints::sext
00017 
00018 #include "llvm/Support/MathExtras.h"
00019 
00020 namespace klee {
00021 namespace floats {
00022 
00023 // ********************************** //
00024 // *** Pack uint64_t into FP types ** //
00025 // ********************************** //
00026 
00027 // interpret the 64 bits as a double instead of a uint64_t
00028 inline double UInt64AsDouble( uint64_t bits ) {
00029   double ret;
00030   assert( sizeof(bits) == sizeof(ret) );
00031   memcpy( &ret, &bits, sizeof bits );
00032   return ret;
00033 }
00034 
00035 // interpret the first 32 bits as a float instead of a uint64_t
00036 inline float UInt64AsFloat( uint64_t bits ) {
00037   uint32_t tmp = bits; // ensure that we read correct bytes
00038   float ret;
00039   assert( sizeof(tmp) == sizeof(ret) );
00040   memcpy( &ret, &tmp, sizeof tmp );
00041   return ret;
00042 }
00043 
00044 
00045 // ********************************** //
00046 // *** Pack FP types into uint64_t ** //
00047 // ********************************** //
00048 
00049 // interpret the 64 bits as a uint64_t instead of a double
00050 inline uint64_t DoubleAsUInt64( double d ) {
00051   uint64_t ret;
00052   assert( sizeof(d) == sizeof(ret) );
00053   memcpy( &ret, &d, sizeof d );
00054   return ret;
00055 }
00056 
00057 // interpret the 32 bits as a uint64_t instead of as a float (add 32 0s)
00058 inline uint64_t FloatAsUInt64( float f ) {
00059   uint32_t tmp;
00060   assert( sizeof(tmp) == sizeof(f) );
00061   memcpy( &tmp, &f, sizeof f );
00062   return (uint64_t)tmp;
00063 }
00064 
00065 
00066 // ********************************** //
00067 // ************ Constants *********** //
00068 // ********************************** //
00069 
00070 const unsigned FLT_BITS = 32;
00071 const unsigned DBL_BITS = 64;
00072 
00073 
00074 
00075 // ********************************** //
00076 // ***** LLVM Binary Operations ***** //
00077 // ********************************** //
00078 
00079 // add of l and r
00080 inline uint64_t add(uint64_t l, uint64_t r, unsigned inWidth) {
00081   switch( inWidth ) {
00082   case FLT_BITS: return bits64::truncateToNBits(FloatAsUInt64(UInt64AsFloat(l)  + UInt64AsFloat(r)),  FLT_BITS);
00083   case DBL_BITS: return bits64::truncateToNBits(DoubleAsUInt64(UInt64AsDouble(l) + UInt64AsDouble(r)), DBL_BITS);
00084   default: assert(0 && "invalid floating point width");
00085   }
00086 }
00087 
00088 // difference of l and r
00089 inline uint64_t sub(uint64_t l, uint64_t r, unsigned inWidth) {
00090   switch( inWidth ) {
00091   case FLT_BITS: return bits64::truncateToNBits(FloatAsUInt64(UInt64AsFloat(l)  - UInt64AsFloat(r)),  FLT_BITS);
00092   case DBL_BITS: return bits64::truncateToNBits(DoubleAsUInt64(UInt64AsDouble(l) - UInt64AsDouble(r)), DBL_BITS);
00093   default: assert(0 && "invalid floating point width");
00094   }
00095 }
00096 
00097 // product of l and r
00098 inline uint64_t mul(uint64_t l, uint64_t r, unsigned inWidth) {
00099   switch( inWidth ) {
00100   case FLT_BITS: return bits64::truncateToNBits(FloatAsUInt64(UInt64AsFloat(l)  * UInt64AsFloat(r)),  FLT_BITS);
00101   case DBL_BITS: return bits64::truncateToNBits(DoubleAsUInt64(UInt64AsDouble(l) * UInt64AsDouble(r)), DBL_BITS);
00102   default: assert(0 && "invalid floating point width");
00103   }
00104 }
00105 
00106 // signed divide of l by r
00107 inline uint64_t div(uint64_t l, uint64_t r, unsigned inWidth) {
00108   switch( inWidth ) {
00109   case FLT_BITS: return bits64::truncateToNBits(FloatAsUInt64(UInt64AsFloat(l)  / UInt64AsFloat(r)),  FLT_BITS);
00110   case DBL_BITS: return bits64::truncateToNBits(DoubleAsUInt64(UInt64AsDouble(l) / UInt64AsDouble(r)), DBL_BITS);
00111   default: assert(0 && "invalid floating point width");
00112   }
00113 }
00114 
00115 // signed modulo of l by r
00116 inline uint64_t mod(uint64_t l, uint64_t r, unsigned inWidth) {
00117   switch( inWidth ) {
00118   case FLT_BITS: return bits64::truncateToNBits(FloatAsUInt64( fmod(UInt64AsFloat(l),  UInt64AsFloat(r)) ), FLT_BITS);
00119   case DBL_BITS: return bits64::truncateToNBits(DoubleAsUInt64( fmod(UInt64AsDouble(l), UInt64AsDouble(r)) ), DBL_BITS);
00120   default: assert(0 && "invalid floating point width");
00121   }
00122 }
00123 
00124 
00125 // ********************************** //
00126 // *** LLVM Comparison Operations *** //
00127 // ********************************** //
00128 
00129 // determine if l represents NaN
00130 inline bool isNaN(uint64_t l, unsigned inWidth) {
00131   switch( inWidth ) {
00132   case FLT_BITS: return llvm::IsNAN( UInt64AsFloat(l) );
00133   case DBL_BITS: return llvm::IsNAN( UInt64AsDouble(l) );
00134   default: assert(0 && "invalid floating point width");
00135   }
00136 }
00137 
00138 inline uint64_t eq(uint64_t l, uint64_t r, unsigned inWidth) {
00139   switch( inWidth ) {
00140   case FLT_BITS: return UInt64AsFloat(l)  == UInt64AsFloat(r);
00141   case DBL_BITS: return UInt64AsDouble(l) == UInt64AsDouble(r);
00142   default: assert(0 && "invalid floating point width");
00143   }
00144 }
00145 
00146 inline uint64_t ne(uint64_t l, uint64_t r, unsigned inWidth) {
00147   switch( inWidth ) {
00148   case FLT_BITS: return UInt64AsFloat(l)  != UInt64AsFloat(r);
00149   case DBL_BITS: return UInt64AsDouble(l) != UInt64AsDouble(r);
00150   default: assert(0 && "invalid floating point width");
00151   }
00152 }
00153 
00154 inline uint64_t lt(uint64_t l, uint64_t r, unsigned inWidth) {
00155   switch( inWidth ) {
00156   case FLT_BITS: return UInt64AsFloat(l)  < UInt64AsFloat(r);
00157   case DBL_BITS: return UInt64AsDouble(l) < UInt64AsDouble(r);
00158   default: assert(0 && "invalid floating point width");
00159   }
00160 }
00161 
00162 inline uint64_t le(uint64_t l, uint64_t r, unsigned inWidth) {
00163   switch( inWidth ) {
00164   case FLT_BITS: return UInt64AsFloat(l)  <= UInt64AsFloat(r);
00165   case DBL_BITS: return UInt64AsDouble(l) <= UInt64AsDouble(r);
00166   default: assert(0 && "invalid floating point width");
00167   }
00168 }
00169 
00170 inline uint64_t gt(uint64_t l, uint64_t r, unsigned inWidth) {
00171   switch( inWidth ) {
00172   case FLT_BITS: return UInt64AsFloat(l)  > UInt64AsFloat(r);
00173   case DBL_BITS: return UInt64AsDouble(l) > UInt64AsDouble(r);
00174   default: assert(0 && "invalid floating point width");
00175   }
00176 }
00177 
00178 inline uint64_t ge(uint64_t l, uint64_t r, unsigned inWidth) {
00179   switch( inWidth ) {
00180   case FLT_BITS: return UInt64AsFloat(l)  >= UInt64AsFloat(r);
00181   case DBL_BITS: return UInt64AsDouble(l) >= UInt64AsDouble(r);
00182   default: assert(0 && "invalid floating point width");
00183   }
00184 }
00185 
00186 
00187 // ********************************** //
00188 // *** LLVM Conversion Operations *** //
00189 // ********************************** //
00190 
00191 // truncation of l (which must be a double) to float (casts a double to a float)
00192 inline uint64_t trunc(uint64_t l, unsigned outWidth, unsigned inWidth) {
00193   // FIXME: Investigate this, should this not happen? Was a quick
00194   // patch for busybox.
00195   if (inWidth==64 && outWidth==64) {
00196     return l;
00197   } else {
00198     assert(inWidth==64 && "can only truncate from a 64-bit double");
00199     assert(outWidth==32 && "can only truncate to a 32-bit float");
00200     float trunc = (float)UInt64AsDouble(l);
00201     return bits64::truncateToNBits(FloatAsUInt64(trunc), outWidth);
00202   }
00203 }
00204 
00205 // extension of l (which must be a float) to double (casts a float to a double)
00206 inline uint64_t ext(uint64_t l, unsigned outWidth, unsigned inWidth) {
00207   // FIXME: Investigate this, should this not happen? Was a quick
00208   // patch for busybox.
00209   if (inWidth==64 && outWidth==64) {
00210     return l;
00211   } else {
00212     assert(inWidth==32 && "can only extend from a 32-bit float");
00213     assert(outWidth==64 && "can only extend to a 64-bit double");
00214     double ext = (double)UInt64AsFloat(l);
00215     return bits64::truncateToNBits(DoubleAsUInt64(ext), outWidth);
00216   }
00217 }
00218 
00219 // conversion of l to an unsigned integer, rounding towards zero
00220 inline uint64_t toUnsignedInt( uint64_t l, unsigned outWidth, unsigned inWidth ) {
00221   switch( inWidth ) {
00222   case FLT_BITS: return bits64::truncateToNBits((uint64_t)UInt64AsFloat(l),  outWidth );
00223   case DBL_BITS: return bits64::truncateToNBits((uint64_t)UInt64AsDouble(l), outWidth );
00224   default: assert(0 && "invalid floating point width");
00225   }
00226 }
00227 
00228 // conversion of l to a signed integer, rounding towards zero
00229 inline uint64_t toSignedInt( uint64_t l, unsigned outWidth, unsigned inWidth ) {
00230   switch( inWidth ) {
00231   case FLT_BITS: return bits64::truncateToNBits((int64_t)UInt64AsFloat(l),  outWidth);
00232   case DBL_BITS: return bits64::truncateToNBits((int64_t)UInt64AsDouble(l), outWidth);
00233   default: assert(0 && "invalid floating point width");
00234   }
00235 }
00236 
00237 // conversion of l, interpreted as an unsigned int, to a floating point number
00238 inline uint64_t UnsignedIntToFP( uint64_t l, unsigned outWidth ) {
00239   switch( outWidth ) {
00240   case FLT_BITS: return bits64::truncateToNBits(FloatAsUInt64((float)l),  outWidth);
00241   case DBL_BITS: return bits64::truncateToNBits(DoubleAsUInt64((double)l), outWidth);
00242   default: assert(0 && "invalid floating point width");
00243   }
00244 }
00245 
00246 // conversion of l, interpreted as a signed int, to a floating point number
00247 inline uint64_t SignedIntToFP( uint64_t l, unsigned outWidth, unsigned inWidth ) {
00248   switch( outWidth ) {
00249   case FLT_BITS: return bits64::truncateToNBits(FloatAsUInt64((float)(int64_t)ints::sext(l, 64, inWidth)), outWidth);
00250   case DBL_BITS: return bits64::truncateToNBits(DoubleAsUInt64((double)(int64_t)ints::sext(l,64, inWidth)), outWidth);
00251   default: assert(0 && "invalid floating point width");
00252   }
00253 }
00254 
00255 } // end namespace ints
00256 } // end namespace klee
00257 
00258 #endif //KLEE_UTIL_FLOATS_H

Generated on Fri Jun 5 03:31:31 2009 for klee by  doxygen 1.5.8