Change float comparison operators to return false for NaN (bug 6107, r=ds).
authorDavid Anderson <dvander@alliedmods.net>
Tue Apr 22 19:40:45 2014 -0700 (2014-04-22)
changeset 432760e4042f2589
parent 4326 b3425cb5ec54
child 4328 a92c3f9c0744
Change float comparison operators to return false for NaN (bug 6107, r=ds).
core/logic/smn_float.cpp
core/sm_stringutil.cpp
plugins/include/float.inc
plugins/testsuite/floats.sp
public/jit/x86/assembler-x86.h
sourcepawn/jit/BaseRuntime.cpp
sourcepawn/jit/opcodes.h
sourcepawn/jit/x86/jit_x86.cpp
sourcepawn/jit/x86/jit_x86.h
tools/checkout-deps.sh
     1.1 --- a/core/logic/smn_float.cpp	Sun Apr 20 00:37:20 2014 -0500
     1.2 +++ b/core/logic/smn_float.cpp	Tue Apr 22 19:40:45 2014 -0700
     1.3 @@ -86,6 +86,44 @@
     1.4  	return sp_ftoc(val);
     1.5  }
     1.6  
     1.7 +static cell_t sm_FloatGt(IPluginContext *pCtx, const cell_t *params)
     1.8 +{
     1.9 +	return !!(sp_ctof(params[1]) > sp_ctof(params[2]));
    1.10 +}
    1.11 +
    1.12 +static cell_t sm_FloatGe(IPluginContext *pCtx, const cell_t *params)
    1.13 +{
    1.14 +	return !!(sp_ctof(params[1]) >= sp_ctof(params[2]));
    1.15 +}
    1.16 +
    1.17 +static cell_t sm_FloatLt(IPluginContext *pCtx, const cell_t *params)
    1.18 +{
    1.19 +	return !!(sp_ctof(params[1]) < sp_ctof(params[2]));
    1.20 +}
    1.21 +
    1.22 +static cell_t sm_FloatLe(IPluginContext *pCtx, const cell_t *params)
    1.23 +{
    1.24 +	return !!(sp_ctof(params[1]) <= sp_ctof(params[2]));
    1.25 +}
    1.26 +
    1.27 +static cell_t sm_FloatEq(IPluginContext *pCtx, const cell_t *params)
    1.28 +{
    1.29 +	return !!(sp_ctof(params[1]) == sp_ctof(params[2]));
    1.30 +}
    1.31 +
    1.32 +static cell_t sm_FloatNe(IPluginContext *pCtx, const cell_t *params)
    1.33 +{
    1.34 +	return !!(sp_ctof(params[1]) != sp_ctof(params[2]));
    1.35 +}
    1.36 +
    1.37 +static cell_t sm_FloatNot(IPluginContext *pCtx, const cell_t *params)
    1.38 +{
    1.39 +	float val = sp_ctof(params[1]);
    1.40 +	if (isnan(val))
    1.41 +		return 1;
    1.42 +	return val ? 0 : 1;
    1.43 +}
    1.44 +
    1.45  static cell_t sm_FloatCompare(IPluginContext *pCtx, const cell_t *params)
    1.46  {
    1.47  	float val1 = sp_ctof(params[1]);
    1.48 @@ -361,6 +399,13 @@
    1.49  	{"RoundToCeil",		sm_RoundToCeil},
    1.50  	{"RoundToFloor",	sm_RoundToFloor},
    1.51  	{"RoundToNearest",	sm_RoundToNearest},
    1.52 +	{"__FLOAT_GT__",	sm_FloatGt},
    1.53 +	{"__FLOAT_GE__",	sm_FloatGe},
    1.54 +	{"__FLOAT_LT__",	sm_FloatGt},
    1.55 +	{"__FLOAT_LE__",	sm_FloatLe},
    1.56 +	{"__FLOAT_EQ__",	sm_FloatEq},
    1.57 +	{"__FLOAT_NE__",	sm_FloatNe},
    1.58 +	{"__FLOAT_NOT__",	sm_FloatNot},
    1.59  	{"FloatCompare",	sm_FloatCompare},
    1.60  	{"SquareRoot",		sm_SquareRoot},
    1.61  	{"Pow",				sm_Pow},
     2.1 --- a/core/sm_stringutil.cpp	Sun Apr 20 00:37:20 2014 -0500
     2.2 +++ b/core/sm_stringutil.cpp	Tue Apr 22 19:40:45 2014 -0700
     2.3 @@ -213,6 +213,11 @@
     2.4  	int significant_digits = 0;	// number of significant digits written
     2.5  	const int MAX_SIGNIFICANT_DIGITS = 16;
     2.6  
     2.7 +	if (isnan(fval)) {
     2.8 +		AddString(buf_p, maxlen, "NaN", width, prec);
     2.9 +		return;
    2.10 +	}
    2.11 +
    2.12  	// default precision
    2.13  	if (prec < 0)
    2.14  	{
     3.1 --- a/plugins/include/float.inc	Sun Apr 20 00:37:20 2014 -0500
     3.2 +++ b/plugins/include/float.inc	Tue Apr 22 19:40:45 2014 -0700
     3.3 @@ -246,10 +246,25 @@
     3.4   */
     3.5  #pragma rational Float
     3.6  
     3.7 +native bool:__FLOAT_GT__(Float:a, Float:b);
     3.8 +native bool:__FLOAT_GE__(Float:a, Float:b);
     3.9 +native bool:__FLOAT_LT__(Float:a, Float:b);
    3.10 +native bool:__FLOAT_LE__(Float:a, Float:b);
    3.11 +native bool:__FLOAT_EQ__(Float:a, Float:b);
    3.12 +native bool:__FLOAT_NE__(Float:a, Float:b);
    3.13 +native bool:__FLOAT_NOT__(Float:a);
    3.14 +
    3.15  native Float:operator*(Float:oper1, Float:oper2) = FloatMul;
    3.16  native Float:operator/(Float:oper1, Float:oper2) = FloatDiv;
    3.17  native Float:operator+(Float:oper1, Float:oper2) = FloatAdd;
    3.18  native Float:operator-(Float:oper1, Float:oper2) = FloatSub;
    3.19 +native bool:operator!(Float:oper1) = __FLOAT_NOT__;
    3.20 +native bool:operator>(Float:oper1, Float:oper2) = __FLOAT_GT__;
    3.21 +native bool:operator>=(Float:oper1, Float:oper2) = __FLOAT_GE__;
    3.22 +native bool:operator<(Float:oper1, Float:oper2) = __FLOAT_LT__;
    3.23 +native bool:operator<=(Float:oper1, Float:oper2) = __FLOAT_LE__;
    3.24 +native bool:operator!=(Float:oper1, Float:oper2) = __FLOAT_NE__;
    3.25 +native bool:operator==(Float:oper1, Float:oper2) = __FLOAT_EQ__;
    3.26  
    3.27  stock Float:operator++(Float:oper)
    3.28  {
    3.29 @@ -296,90 +311,54 @@
    3.30  	return FloatSub(float(oper1), oper2);
    3.31  }
    3.32  
    3.33 -stock bool:operator==(Float:oper1, Float:oper2)
    3.34 -{
    3.35 -	return FloatCompare(oper1, oper2) == 0;
    3.36 -}
    3.37 -
    3.38  stock bool:operator==(Float:oper1, oper2)
    3.39  {
    3.40 -	return FloatCompare(oper1, float(oper2)) == 0; 	/* "==" is commutative */
    3.41 -}
    3.42 -
    3.43 -stock bool:operator!=(Float:oper1, Float:oper2)
    3.44 -{
    3.45 -	return FloatCompare(oper1, oper2) != 0;
    3.46 +	return __FLOAT_EQ__(oper1, float(oper2));
    3.47  }
    3.48  
    3.49  stock bool:operator!=(Float:oper1, oper2)
    3.50  {
    3.51 -	return FloatCompare(oper1, float(oper2)) != 0; 	/* "==" is commutative */
    3.52 -}
    3.53 -
    3.54 -stock bool:operator>(Float:oper1, Float:oper2)
    3.55 -{
    3.56 -	return FloatCompare(oper1, oper2) > 0;
    3.57 +	return __FLOAT_NE__(oper1, float(oper2));
    3.58  }
    3.59  
    3.60  stock bool:operator>(Float:oper1, oper2)
    3.61  {
    3.62 -	return FloatCompare(oper1, float(oper2)) > 0;
    3.63 +	return __FLOAT_GT__(oper1, float(oper2));
    3.64  }
    3.65  
    3.66  stock bool:operator>(oper1, Float:oper2)
    3.67  {
    3.68 -	return FloatCompare(float(oper1), oper2) > 0;
    3.69 -}
    3.70 -
    3.71 -stock bool:operator>=(Float:oper1, Float:oper2)
    3.72 -{
    3.73 -	return FloatCompare(oper1, oper2) >= 0;
    3.74 +	return __FLOAT_GT__(float(oper1), oper2);
    3.75  }
    3.76  
    3.77  stock bool:operator>=(Float:oper1, oper2)
    3.78  {
    3.79 -	return FloatCompare(oper1, float(oper2)) >= 0;
    3.80 +	return __FLOAT_GE__(oper1, float(oper2));
    3.81  }
    3.82  
    3.83  stock bool:operator>=(oper1, Float:oper2)
    3.84  {
    3.85 -	return FloatCompare(float(oper1), oper2) >= 0;
    3.86 -}
    3.87 -
    3.88 -stock bool:operator<(Float:oper1, Float:oper2)
    3.89 -{
    3.90 -	return FloatCompare(oper1, oper2) < 0;
    3.91 +	return __FLOAT_GE__(float(oper1), oper2);
    3.92  }
    3.93  
    3.94  stock bool:operator<(Float:oper1, oper2)
    3.95  {
    3.96 -	return FloatCompare(oper1, float(oper2)) < 0;
    3.97 +	return __FLOAT_LT__(oper1, float(oper2));
    3.98  }
    3.99  
   3.100  stock bool:operator<(oper1, Float:oper2)
   3.101  {
   3.102 -	return FloatCompare(float(oper1), oper2) < 0;
   3.103 -}
   3.104 -
   3.105 -stock bool:operator<=(Float:oper1, Float:oper2)
   3.106 -{
   3.107 -	return FloatCompare(oper1, oper2) <= 0;
   3.108 +	return __FLOAT_LT__(float(oper1), oper2);
   3.109  }
   3.110  
   3.111  stock bool:operator<=(Float:oper1, oper2)
   3.112  {
   3.113 -	return FloatCompare(oper1, float(oper2)) <= 0;
   3.114 +	return __FLOAT_LE__(oper1, float(oper2));
   3.115  }
   3.116  
   3.117  stock bool:operator<=(oper1, Float:oper2)
   3.118  {
   3.119 -	return FloatCompare(float(oper1), oper2) <= 0;
   3.120 -}
   3.121 -
   3.122 -stock bool:operator!(Float:oper)
   3.123 -{
   3.124 -	return (_:oper & ((-1)/2)) == 0;		/* -1 = all bits to 1; /2 = remove most significant bit (sign)
   3.125 -											works on both 32bit and 64bit systems; no constant required */
   3.126 +	return __FLOAT_LE__(float(oper1), oper2);
   3.127  }
   3.128  
   3.129  /**
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/plugins/testsuite/floats.sp	Tue Apr 22 19:40:45 2014 -0700
     4.3 @@ -0,0 +1,81 @@
     4.4 +public OnPluginStart()
     4.5 +{
     4.6 +  RegServerCmd("test_floats", TestFloats)
     4.7 +}
     4.8 +
     4.9 +check(bool:got, bool:expect, const String:message[]="")
    4.10 +{
    4.11 +  if (got != expect) {
    4.12 +    ThrowError("Check failed", message)
    4.13 +  }
    4.14 +}
    4.15 +
    4.16 +public Action:TestFloats(args)
    4.17 +{
    4.18 +  new Float:x = 5.3
    4.19 +  new Float:y = 10.2
    4.20 +
    4.21 +  check(x < y, true)
    4.22 +  check(x <= y, true)
    4.23 +  check(x > y, false)
    4.24 +  check(x >= y, false)
    4.25 +  check(x == y, false)
    4.26 +  check(x != y, true)
    4.27 +
    4.28 +  x = 10.5
    4.29 +  y = 2.3
    4.30 +
    4.31 +  check(x < y, false)
    4.32 +  check(x <= y, false)
    4.33 +  check(x > y, true)
    4.34 +  check(x >= y, true)
    4.35 +  check(x == y, false)
    4.36 +  check(x != y, true)
    4.37 +
    4.38 +  x = 10.5
    4.39 +  y = x
    4.40 +
    4.41 +  check(x < y, false)
    4.42 +  check(x <= y, true)
    4.43 +  check(x > y, false)
    4.44 +  check(x >= y, true)
    4.45 +  check(x == y, true)
    4.46 +  check(x != y, false)
    4.47 +
    4.48 +  x = 0.0
    4.49 +  y = 0.0
    4.50 +  new Float:nan = x / y
    4.51 +
    4.52 +  check(x < nan, false)
    4.53 +  check(x <= nan, false)
    4.54 +  check(x > nan, false)
    4.55 +  check(x >= nan, false)
    4.56 +  check(x == nan, false)
    4.57 +  check(x != nan, true)
    4.58 +  check(nan < y, false)
    4.59 +  check(nan <= y, false)
    4.60 +  check(nan > y, false)
    4.61 +  check(nan >= y, false)
    4.62 +  check(nan == y, false)
    4.63 +  check(nan != y, true)
    4.64 +  check(nan == nan, false)
    4.65 +  check(nan != nan, true)
    4.66 +
    4.67 +  x = 10.5
    4.68 +  y = 0.0
    4.69 +  check(!x, false)
    4.70 +  check(!y, true)
    4.71 +  check(!nan, true)
    4.72 +
    4.73 +  y = -2.7
    4.74 +  check(-x == -10.5, true)
    4.75 +  check(-y == 2.7, true)
    4.76 +
    4.77 +  new String:buffer[32]
    4.78 +  Format(buffer, sizeof(buffer), "%f", nan)
    4.79 +  check(StrEqual(buffer, "NaN"), true)
    4.80 +
    4.81 +  PrintToServer("Tests finished.")
    4.82 +
    4.83 +  return Plugin_Stop
    4.84 +}
     5.1 --- a/public/jit/x86/assembler-x86.h	Sun Apr 20 00:37:20 2014 -0500
     5.2 +++ b/public/jit/x86/assembler-x86.h	Tue Apr 22 19:40:45 2014 -0700
     5.3 @@ -178,7 +178,11 @@
     5.4    zero = equal,
     5.5    not_zero = not_equal,
     5.6    less_equal = not_greater,
     5.7 -  greater_equal = not_less
     5.8 +  below_equal = not_above,
     5.9 +  greater_equal = not_less,
    5.10 +  above_equal = not_below,
    5.11 +  parity = even_parity,
    5.12 +  not_parity = odd_parity
    5.13  };
    5.14  
    5.15  enum Scale {
    5.16 @@ -625,6 +629,9 @@
    5.17    void fsubr32(const Operand &src) {
    5.18      emit1(0xd8, 5, src);
    5.19    }
    5.20 +  void fldz() {
    5.21 +    emit2(0xd9, 0xee);
    5.22 +  }
    5.23  
    5.24    // Compare st0 with stN.
    5.25    void fucomip(FpuRegister other) {
    5.26 @@ -802,11 +809,16 @@
    5.27      assert(Features().sse);
    5.28      emit3(0xf3, 0x0f, 0x5e, dest.code, src);
    5.29    }
    5.30 -  void ucomiss(FloatRegister left, Register right) {
    5.31 -    emit2(0x0f, 0x2e, left.code, right.code);
    5.32 +  void xorps(FloatRegister dest, FloatRegister src) {
    5.33 +    assert(Features().sse);
    5.34 +    emit2(0x0f, 0x57, src.code, dest.code);
    5.35    }
    5.36 -  void ucomiss(FloatRegister left, const Operand &right) {
    5.37 -    emit2(0x0f, 0x2e, left.code, right);
    5.38 +
    5.39 +  void ucomiss(FloatRegister left, FloatRegister right) {
    5.40 +    emit2(0x0f, 0x2e, right.code, left.code);
    5.41 +  }
    5.42 +  void ucomiss(const Operand &left, FloatRegister right) {
    5.43 +    emit2(0x0f, 0x2e, right.code, left);
    5.44    }
    5.45  
    5.46    // SSE2-only instructions.
     6.1 --- a/sourcepawn/jit/BaseRuntime.cpp	Sun Apr 20 00:37:20 2014 -0500
     6.2 +++ b/sourcepawn/jit/BaseRuntime.cpp	Tue Apr 22 19:40:45 2014 -0700
     6.3 @@ -75,45 +75,47 @@
     6.4    free(m_plugin.name);
     6.5  }
     6.6  
     6.7 +struct NativeMapping {
     6.8 +  const char *name;
     6.9 +  unsigned opcode;
    6.10 +};
    6.11 +
    6.12 +static const NativeMapping sNativeMap[] = {
    6.13 +  { "FloatAbs",       OP_FABS },
    6.14 +  { "FloatAdd",       OP_FLOATADD },
    6.15 +  { "FloatSub",       OP_FLOATSUB },
    6.16 +  { "FloatMul",       OP_FLOATMUL },
    6.17 +  { "FloatDiv",       OP_FLOATDIV },
    6.18 +  { "float",          OP_FLOAT },
    6.19 +  { "FloatCompare",   OP_FLOATCMP },
    6.20 +  { "RoundToCeil",    OP_RND_TO_CEIL },
    6.21 +  { "RoundToZero",    OP_RND_TO_ZERO },
    6.22 +  { "RoundToFloor",   OP_RND_TO_FLOOR },
    6.23 +  { "RoundToNearest", OP_RND_TO_NEAREST },
    6.24 +  { "__FLOAT_GT__",   OP_FLOAT_GT },
    6.25 +  { "__FLOAT_GE__",   OP_FLOAT_GE },
    6.26 +  { "__FLOAT_LT__",   OP_FLOAT_LT },
    6.27 +  { "__FLOAT_LE__",   OP_FLOAT_LE },
    6.28 +  { "__FLOAT_EQ__",   OP_FLOAT_EQ },
    6.29 +  { "__FLOAT_NE__",   OP_FLOAT_NE },
    6.30 +  { "__FLOAT_NOT__",  OP_FLOAT_NOT },
    6.31 +  { NULL,             0 },
    6.32 +};
    6.33 +
    6.34  void
    6.35  BaseRuntime::SetupFloatNativeRemapping()
    6.36  {
    6.37    float_table_ = new floattbl_t[m_plugin.num_natives];
    6.38    for (size_t i = 0; i < m_plugin.num_natives; i++) {
    6.39      const char *name = m_plugin.natives[i].name;
    6.40 -    if (!strcmp(name, "FloatAbs")) {
    6.41 -      float_table_[i].found = true;
    6.42 -      float_table_[i].index = OP_FABS;
    6.43 -    } else if (!strcmp(name, "FloatAdd")) {
    6.44 -      float_table_[i].found = true;
    6.45 -      float_table_[i].index = OP_FLOATADD;
    6.46 -    } else if (!strcmp(name, "FloatSub")) {
    6.47 -      float_table_[i].found = true;
    6.48 -      float_table_[i].index = OP_FLOATSUB;
    6.49 -    } else if (!strcmp(name, "FloatMul")) {
    6.50 -      float_table_[i].found = true;
    6.51 -      float_table_[i].index = OP_FLOATMUL;
    6.52 -    } else if (!strcmp(name, "FloatDiv")) {
    6.53 -      float_table_[i].found = true;
    6.54 -      float_table_[i].index = OP_FLOATDIV;
    6.55 -    } else if (!strcmp(name, "float")) {
    6.56 -      float_table_[i].found = true;
    6.57 -      float_table_[i].index = OP_FLOAT;
    6.58 -    } else if (!strcmp(name, "FloatCompare")) {
    6.59 -      float_table_[i].found = true;
    6.60 -      float_table_[i].index = OP_FLOATCMP;
    6.61 -    } else if (!strcmp(name, "RoundToZero")) {
    6.62 -      float_table_[i].found = true;
    6.63 -      float_table_[i].index = OP_RND_TO_ZERO;
    6.64 -    } else if (!strcmp(name, "RoundToCeil")) {
    6.65 -      float_table_[i].found = true;
    6.66 -      float_table_[i].index = OP_RND_TO_CEIL;
    6.67 -    } else if (!strcmp(name, "RoundToFloor")) {
    6.68 -      float_table_[i].found = true;
    6.69 -      float_table_[i].index = OP_RND_TO_FLOOR;
    6.70 -    } else if (!strcmp(name, "RoundToNearest")) {
    6.71 -      float_table_[i].found = true;
    6.72 -      float_table_[i].index = OP_RND_TO_NEAREST;
    6.73 +    const NativeMapping *iter = sNativeMap;
    6.74 +    while (iter->name) {
    6.75 +      if (strcmp(name, iter->name) == 0) {
    6.76 +        float_table_[i].found = true;
    6.77 +        float_table_[i].index = iter->opcode;
    6.78 +        break;
    6.79 +      }
    6.80 +      iter++;
    6.81      }
    6.82    }
    6.83  }
     7.1 --- a/sourcepawn/jit/opcodes.h	Sun Apr 20 00:37:20 2014 -0500
     7.2 +++ b/sourcepawn/jit/opcodes.h	Tue Apr 22 19:40:45 2014 -0700
     7.3 @@ -238,15 +238,22 @@
     7.4    _(ENDPROC,        "endproc")        \
     7.5    _(FABS,           "fabs")           \
     7.6    _(FLOAT,          "float")          \
     7.7 -  _(FLOATADD,       "floatadd")       \
     7.8 -  _(FLOATSUB,       "floatsub")       \
     7.9 -  _(FLOATMUL,       "floatmul")       \
    7.10 -  _(FLOATDIV,       "floatdiv")       \
    7.11 +  _(FLOATADD,       "float.add")      \
    7.12 +  _(FLOATSUB,       "float.sub")      \
    7.13 +  _(FLOATMUL,       "float.mul")      \
    7.14 +  _(FLOATDIV,       "float.div")      \
    7.15    _(RND_TO_NEAREST, "round")          \
    7.16    _(RND_TO_FLOOR,   "floor")          \
    7.17    _(RND_TO_CEIL,    "ceil")           \
    7.18    _(RND_TO_ZERO,    "rndtozero")      \
    7.19 -  _(FLOATCMP,       "floatcmp")
    7.20 +  _(FLOATCMP,       "float.cmp")      \
    7.21 +  _(FLOAT_GT,       "float.gt")       \
    7.22 +  _(FLOAT_GE,       "float.ge")       \
    7.23 +  _(FLOAT_LT,       "float.lt")       \
    7.24 +  _(FLOAT_LE,       "float.le")       \
    7.25 +  _(FLOAT_NE,       "float.ne")       \
    7.26 +  _(FLOAT_EQ,       "float.eq")       \
    7.27 +  _(FLOAT_NOT,      "float.not")
    7.28  
    7.29  enum OPCODE {
    7.30  #define _(op, text) OP_##op,
     8.1 --- a/sourcepawn/jit/x86/jit_x86.cpp	Sun Apr 20 00:37:20 2014 -0500
     8.2 +++ b/sourcepawn/jit/x86/jit_x86.cpp	Tue Apr 22 19:40:45 2014 -0700
     8.3 @@ -1085,12 +1085,16 @@
     8.4        __ addl(stk, 4);
     8.5        break;
     8.6  
     8.7 +    // This is the old float cmp, which returns ordered results. In newly
     8.8 +    // compiled code it should not be used or generated.
     8.9 +    //
    8.10 +    // Note that the checks here are inverted: the test is |rhs OP lhs|.
    8.11      case OP_FLOATCMP:
    8.12      {
    8.13        Label bl, ab, done;
    8.14        if (MacroAssemblerX86::Features().sse) {
    8.15          __ movss(xmm0, Operand(stk, 4));
    8.16 -        __ ucomiss(xmm0, Operand(stk, 0));
    8.17 +        __ ucomiss(Operand(stk, 0), xmm0);
    8.18        } else {
    8.19          __ fld32(Operand(stk, 0));
    8.20          __ fld32(Operand(stk, 4));
    8.21 @@ -1111,6 +1115,53 @@
    8.22        break;
    8.23      }
    8.24  
    8.25 +    case OP_FLOAT_GT:
    8.26 +      emitFloatCmp(above);
    8.27 +      break;
    8.28 +
    8.29 +    case OP_FLOAT_GE:
    8.30 +      emitFloatCmp(above_equal);
    8.31 +      break;
    8.32 +
    8.33 +    case OP_FLOAT_LE:
    8.34 +      emitFloatCmp(below_equal);
    8.35 +      break;
    8.36 +
    8.37 +    case OP_FLOAT_LT:
    8.38 +      emitFloatCmp(below);
    8.39 +      break;
    8.40 +
    8.41 +    case OP_FLOAT_EQ:
    8.42 +      emitFloatCmp(equal);
    8.43 +      break;
    8.44 +
    8.45 +    case OP_FLOAT_NE:
    8.46 +      emitFloatCmp(not_equal);
    8.47 +      break;
    8.48 +
    8.49 +    case OP_FLOAT_NOT:
    8.50 +    {
    8.51 +      if (MacroAssemblerX86::Features().sse) {
    8.52 +        __ xorps(xmm0, xmm0);
    8.53 +        __ ucomiss(Operand(stk, 0), xmm0);
    8.54 +      } else {
    8.55 +        __ fld32(Operand(stk, 0));
    8.56 +        __ fldz();
    8.57 +        __ fucomip(st1);
    8.58 +        __ fstp(st0);
    8.59 +      }
    8.60 +
    8.61 +      // See emitFloatCmp() - this is a shorter version.
    8.62 +      Label done;
    8.63 +      __ movl(eax, 1);
    8.64 +      __ j(parity, &done);
    8.65 +      __ set(zero, r8_al);
    8.66 +      __ bind(&done);
    8.67 +
    8.68 +      __ addl(stk, 4);
    8.69 +      break;
    8.70 +    }
    8.71 +
    8.72      case OP_STACK:
    8.73      {
    8.74        cell_t amount = readCell();
    8.75 @@ -1672,6 +1723,56 @@
    8.76  }
    8.77  
    8.78  void
    8.79 +Compiler::emitFloatCmp(ConditionCode cc)
    8.80 +{
    8.81 +  unsigned lhs = 4;
    8.82 +  unsigned rhs = 0;
    8.83 +  if (cc == below || cc == below_equal) {
    8.84 +    // NaN results in ZF=1 PF=1 CF=1
    8.85 +    //
    8.86 +    // ja/jae check for ZF,CF=0 and CF=0. If we make all relational compares
    8.87 +    // look like ja/jae, we'll guarantee all NaN comparisons will fail (which
    8.88 +    // would not be true for jb/jbe, unless we checked with jp).
    8.89 +    if (cc == below)
    8.90 +      cc = above;
    8.91 +    else
    8.92 +      cc = above_equal;
    8.93 +    rhs = 4;
    8.94 +    lhs = 0;
    8.95 +  }
    8.96 +
    8.97 +  if (MacroAssemblerX86::Features().sse) {
    8.98 +    __ movss(xmm0, Operand(stk, rhs));
    8.99 +    __ ucomiss(Operand(stk, lhs), xmm0);
   8.100 +  } else {
   8.101 +    __ fld32(Operand(stk, rhs));
   8.102 +    __ fld32(Operand(stk, lhs));
   8.103 +    __ fucomip(st1);
   8.104 +    __ fstp(st0);
   8.105 +  }
   8.106 +
   8.107 +  // An equal or not-equal needs special handling for the parity bit.
   8.108 +  if (cc == equal || cc == not_equal) {
   8.109 +    // If NaN, PF=1, ZF=1, and E/Z tests ZF=1.
   8.110 +    //
   8.111 +    // If NaN, PF=1, ZF=1 and NE/NZ tests Z=0. But, we want any != with NaNs
   8.112 +    // to return true, including NaN != NaN.
   8.113 +    //
   8.114 +    // To make checks simpler, we set |eax| to the expected value of a NaN
   8.115 +    // beforehand. This also clears the top bits of |eax| for setcc.
   8.116 +    Label done;
   8.117 +    __ movl(eax, (cc == equal) ? 0 : 1);
   8.118 +    __ j(parity, &done);
   8.119 +    __ set(cc, r8_al);
   8.120 +    __ bind(&done);
   8.121 +  } else {
   8.122 +    __ movl(eax, 0);
   8.123 +    __ set(cc, r8_al);
   8.124 +  }
   8.125 +  __ addl(stk, 8);
   8.126 +}
   8.127 +
   8.128 +void
   8.129  Compiler::emitErrorPaths()
   8.130  {
   8.131    emitErrorPath(&error_divide_by_zero_, SP_ERROR_DIVIDE_BY_ZERO);
     9.1 --- a/sourcepawn/jit/x86/jit_x86.h	Sun Apr 20 00:37:20 2014 -0500
     9.2 +++ b/sourcepawn/jit/x86/jit_x86.h	Tue Apr 22 19:40:45 2014 -0700
     9.3 @@ -105,6 +105,7 @@
     9.4    void emitCheckAddress(Register reg);
     9.5    void emitErrorPath(Label *dest, int code);
     9.6    void emitErrorPaths();
     9.7 +  void emitFloatCmp(ConditionCode cc);
     9.8  
     9.9    ExternalAddress cipAddr() {
    9.10      sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
    10.1 --- a/tools/checkout-deps.sh	Sun Apr 20 00:37:20 2014 -0500
    10.2 +++ b/tools/checkout-deps.sh	Tue Apr 22 19:40:45 2014 -0700
    10.3 @@ -57,6 +57,7 @@
    10.4      hg clone https://hg.alliedmods.net/$path/$name
    10.5    else
    10.6      cd $name
    10.7 +    sed -i 's/http:/https:/g' .hg/hgrc
    10.8      hg pull -u
    10.9      cd ..
   10.10    fi