Skip to content

Commit

Permalink
Merge branch 'floating-point'
Browse files Browse the repository at this point in the history
  • Loading branch information
regehr committed Sep 30, 2014
2 parents 90d17a5 + 0aaafbf commit e7c69cb
Show file tree
Hide file tree
Showing 26 changed files with 556 additions and 137 deletions.
74 changes: 74 additions & 0 deletions runtime/safe_math.m4
Expand Up @@ -287,4 +287,78 @@ safe_unsigned_math(uint32_t,UINT32_MAX)
safe_unsigned_math(uint64_t,UINT64_MAX)
#endif

dnl safe floating point computation, based on Pascal's suggestion

define(`safe_float_math',`

STATIC $1
FUNC_NAME(add_func_$1_f_f)($1 sf1, $1 sf2 LOG_INDEX)
{
LOG_EXEC
return
#ifndef UNSAFE_FLOAT
(fabs$2((0.5$2 * sf1) + (0.5$2 * sf2)) > (0.5$2 * $3)) ?
UNDEFINED(sf1) :
#endif
(sf1 + sf2);
}

STATIC $1
FUNC_NAME(sub_func_$1_f_f)($1 sf1, $1 sf2 LOG_INDEX)
{
LOG_EXEC
return
#ifndef UNSAFE_FLOAT
(fabs$2((0.5$2 * sf1) - (0.5$2 * sf2)) > (0.5$2 * $3)) ?
UNDEFINED(sf1) :
#endif
(sf1 - sf2);
}

STATIC $1
FUNC_NAME(mul_func_$1_f_f)($1 sf1, $1 sf2 LOG_INDEX)
{
LOG_EXEC
return
#ifndef UNSAFE_FLOAT
(fabs((0x1.0p-100$2 * sf1) * ($4 * sf2)) > (0x1.0p-100$2 * ($4 * $3))) ?
UNDEFINED(sf1) :
#endif
(sf1 * sf2);
}

STATIC $1
FUNC_NAME(div_func_$1_f_f)($1 sf1, $1 sf2 LOG_INDEX)
{
LOG_EXEC
return
#ifndef UNSAFE_FLOAT
((fabs(sf2) < 1.0$2) && (((sf2 == 0.0$2) || (fabs(($5 * sf1) / (0x1.0p100$2 * sf2))) > (0x1.0p-100$2 * ($5 * $3))))) ?
UNDEFINED(sf1) :
#endif
(sf1 / sf2);
}

')

safe_float_math(float,f,FLT_MAX,0x1.0p-28f,0x1.0p-49f)
safe_float_math(double,,DBL_MAX,0x1.0p-924,0x1.0p-974)

define(`safe_float_conversion',`
STATIC $2
FUNC_NAME(convert_func_$1_to_$2)($1 sf1 LOG_INDEX)
{
LOG_EXEC
return
#ifndef UNSAFE_FLOAT
((sf1 <= $3) || (sf1 >= $4)) ?
UNDEFINED($4) :
#endif
(($2)(sf1));
}
')

safe_float_conversion(float, int32_t, INT32_MIN, INT32_MAX)


#endif
2 changes: 2 additions & 0 deletions src/ArrayVariable.cpp
Expand Up @@ -302,6 +302,8 @@ ArrayVariable*
ArrayVariable::itemize(const std::vector<const Variable*>& indices, Block* blk) const
{
size_t i;
// Looks like this function is dead.
assert(0 && "Invoke a dead function?");
assert(collective == 0);
ArrayVariable* av = new ArrayVariable(*this);
VariableSelector::AllVars.push_back(av);
Expand Down
2 changes: 2 additions & 0 deletions src/CGOptions.cpp
Expand Up @@ -135,6 +135,7 @@ DEFINE_GETTER_SETTER_BOOL(math_notmp)
DEFINE_GETTER_SETTER_BOOL(longlong)
DEFINE_GETTER_SETTER_BOOL(int8)
DEFINE_GETTER_SETTER_BOOL(uint8)
DEFINE_GETTER_SETTER_BOOL(enable_float)
DEFINE_GETTER_SETTER_BOOL(pointers)
DEFINE_GETTER_SETTER_BOOL(arrays)
DEFINE_GETTER_SETTER_BOOL(strict_const_arrays)
Expand Down Expand Up @@ -251,6 +252,7 @@ CGOptions::set_default_settings(void)
longlong(true);
int8(true);
uint8(true);
enable_float(false);
pointers(true);
arrays(true);
strict_const_arrays(false);
Expand Down
4 changes: 4 additions & 0 deletions src/CGOptions.h
Expand Up @@ -253,6 +253,9 @@ class CGOptions {
static bool uint8(void);
static bool uint8(bool p);

static bool enable_float(void);
static bool enable_float(bool p);

static bool pointers(void);
static bool pointers(bool p);

Expand Down Expand Up @@ -532,6 +535,7 @@ class CGOptions {
static bool longlong_;
static bool int8_;
static bool uint8_;
static bool enable_float_;
static bool pointers_;
static bool arrays_;
static bool strict_const_arrays_;
Expand Down
186 changes: 124 additions & 62 deletions src/Constant.cpp
Expand Up @@ -155,12 +155,56 @@ GenerateRandomLongLongConstant(void)
static string
GenerateRandomFloatConstant(void)
{
// Generate a random floating point value with up to 10 digits of precision. (should look up precision of float/double.. 23 bits for IEEE-32?)
string val = RandomDigits(5) + "." + RandomDigits(5);
return val;
}
#endif // 0

/*
* Generate hexadecimal floating point constants [0xF.FFFFFFp-99, 0xF.FFFFFFp+99]
*/
static string
GenerateRandomFloatHexConstant(void)
{
int exp = pure_rnd_upto(100);
ostringstream oss;
oss << "0x" << RandomHexDigits(1) << "." << RandomHexDigits(6) << "p";

if (pure_rnd_flipcoin(50)) {
oss << "+";
}
else {
oss << "-";
}
oss << exp;
return oss.str();
}

/*
* Generate small hexadecimal floating point constants
*/
static string
GenerateSmallRandomFloatHexConstant(int num)
{
ostringstream oss;
if (num >= 0) {
oss << "0x";
}
else {
oss << "-0x";
num = -num;
}
oss << num << "." << RandomHexDigits(1) << "p";

if (pure_rnd_flipcoin(50)) {
oss << "+1";
}
else {
oss << "-1";
}
return oss.str();
}

static string
GenerateRandomConstantInRange(const Type* type, int bound)
{
Expand Down Expand Up @@ -247,77 +291,95 @@ GenerateRandomUnionConstant(const Type* type)
static string
GenerateRandomConstant(const Type* type)
{
string v;
string v;
if (type == 0) {
v = "0";
}
else if (type->eType == eStruct) {
v = GenerateRandomStructConstant(type);
else if (type->eType == eStruct) {
v = GenerateRandomStructConstant(type);
ERROR_GUARD("");
}
}
else if (type->eType == eUnion) {
v = GenerateRandomUnionConstant(type);
v = GenerateRandomUnionConstant(type);
ERROR_GUARD("");
}
// the only possible constant for a pointer is "0"
else if (type->eType == ePointer) {
v = "0";
}
else if (type->eType == eSimple) {
eSimpleType st = type->simple_type;
assert(st != eVoid);
//assert((eType >= 0) && (eType <= MAX_SIMPLE_TYPES));
if (pure_rnd_flipcoin(50)) {
ERROR_GUARD("");
int num = 0;
if (pure_rnd_flipcoin(50)) {
ERROR_GUARD("");
num = pure_rnd_upto(3)-1;
} else {
ERROR_GUARD("");
num = pure_rnd_upto(20)-10;
}
}
// the only possible constant for a pointer is "0"
else if (type->eType == ePointer) {
v = "0";
}
else if (type->eType == eSimple) {
eSimpleType st = type->simple_type;
assert(st != eVoid);
//assert((eType >= 0) && (eType <= MAX_SIMPLE_TYPES));
if (pure_rnd_flipcoin(50)) {
ERROR_GUARD("");
int num = 0;
if (pure_rnd_flipcoin(50)) {
ERROR_GUARD("");
num = pure_rnd_upto(3)-1;
} else {
ERROR_GUARD("");
num = pure_rnd_upto(20)-10;
}
// don't use negative number for unsigned type, as this causes
//trouble for some static analyzers
ostringstream oss;
switch (type->simple_type) {
case eUChar: oss << (unsigned int)(unsigned char)num; break;
case eUShort: oss << (unsigned short)num; break;
case eUInt: oss << (unsigned int)num; break;
case eULong:
case eULongLong:
if (!CGOptions::longlong()) {
oss << (unsigned int)num;
} else {
oss << ((type->simple_type == eULong) ? (unsigned long)num : (unsigned INT64)num);
}
break;
default: oss << num; break;
}
if (CGOptions::ccomp())
v = oss.str() + (type->is_signed() ? "" : "U");
else
v = oss.str() + (type->is_signed() ? "L" : "UL");
} else {
ostringstream oss;
switch (st) {
case eUChar:
oss << (unsigned int)(unsigned char)num;
break;
case eUShort:
oss << (unsigned short)num;
break;
case eUInt:
oss << (unsigned int)num;
break;
case eULong:
case eULongLong:
if (!CGOptions::longlong()) {
oss << (unsigned int)num;
} else {
oss << ((type->simple_type == eULong) ? (unsigned long)num : (unsigned INT64)num);
}
break;
case eFloat:
oss << GenerateSmallRandomFloatHexConstant(num);
break;
default:
oss << num;
break;
}
if (type->simple_type == eFloat) {
v = oss.str();
}
else {
if (CGOptions::ccomp())
v = oss.str() + (type->is_signed() ? "" : "U");
else
v = oss.str() + (type->is_signed() ? "L" : "UL");
}
} else {
switch (st) {
case eVoid: v = "/* void */"; break;
case eChar: v = GenerateRandomCharConstant(); break;
case eInt: v = GenerateRandomIntConstant(); break;
case eShort: v = GenerateRandomShortConstant(); break;
case eLong: v = GenerateRandomLongConstant(); break;
case eLongLong: v = GenerateRandomLongLongConstant(); break;
case eUChar: v = GenerateRandomCharConstant(); break;
case eUInt: v = GenerateRandomIntConstant(); break;
case eUShort: v = GenerateRandomShortConstant(); break;
case eULong: v = GenerateRandomLongConstant(); break;
case eULongLong: v = GenerateRandomLongLongConstant(); break;
// case eFloat: v = GenerateRandomFloatConstant(); break;
// case eDouble: v = GenerateRandomFloatConstant(); break;
case eVoid: v = "/* void */"; break;
case eChar: v = GenerateRandomCharConstant(); break;
case eInt: v = GenerateRandomIntConstant(); break;
case eShort: v = GenerateRandomShortConstant(); break;
case eLong: v = GenerateRandomLongConstant(); break;
case eLongLong: v = GenerateRandomLongLongConstant(); break;
case eUChar: v = GenerateRandomCharConstant(); break;
case eUInt: v = GenerateRandomIntConstant(); break;
case eUShort: v = GenerateRandomShortConstant(); break;
case eULong: v = GenerateRandomLongConstant(); break;
case eULongLong: v = GenerateRandomLongLongConstant(); break;
case eFloat: v = GenerateRandomFloatHexConstant(); break;
// case eDouble: v = GenerateRandomFloatConstant(); break;
default:
assert(0 && "Unsupported type!");
}
}
} else {
assert(0); // no support for types other than integers and structs for now
}
}
} else {
assert(0); // no support for types other than integers and structs for now
}
return (type->eType == eSimple && CGOptions::mark_mutable_const()) ? "(" + v + ")" : v;
}

Expand Down
2 changes: 2 additions & 0 deletions src/ExpressionVariable.cpp
Expand Up @@ -73,6 +73,8 @@ ExpressionVariable::make_random(CGContext &cg_context, const Type* type, const C
ERROR_GUARD(NULL);
if (!var)
continue;
if (!type->is_float() && var->type->is_float())
continue;
// forbid a parameter to take the address of an argument
// this is to simplify the path shortcutting delta
if (as_param && var->is_argument() && var->type->is_dereferenced_from(type)) {
Expand Down
4 changes: 4 additions & 0 deletions src/Function.cpp
Expand Up @@ -278,6 +278,10 @@ Function::choose_func(vector<Function *> funcs,
// if type = 0, we don't care
if (type && !type->is_convertable((*i)->return_type))
continue;
// Changing the behavior of is_convertable is quite dangerous.
// Making constraint here has less global effect.
//if (type && (*i)->return_type->is_float() && !type->is_float())
// continue;
if (qfer && (*i)->rv && !qfer->match((*i)->rv->qfer))
continue;
// We cannot call a function that has an as-yet unknown effect.
Expand Down

0 comments on commit e7c69cb

Please sign in to comment.