Bug 956402 - OdinMonkey: refactoring: add Float to NumLit (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Mon, 06 Jan 2014 10:17:57 -0600
changeset 162191 5568609fa907c87e48d5cb78bd612cf6f7402949
parent 162190 6c4c65228af1b71e1daa3ae3c737957836d693d2
child 162192 71c810816820a0e4a7b6c6f9e80e8e41080268e9
push idunknown
push userunknown
push dateunknown
reviewersbbouvier
bugs956402
milestone29.0a1
Bug 956402 - OdinMonkey: refactoring: add Float to NumLit (r=bbouvier)
js/src/jit/AsmJS.cpp
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -490,17 +490,17 @@ class RetType
         Double = Type::Double,
         Float = Type::Float
     };
 
   private:
     Which which_;
 
   public:
-    RetType() {}
+    RetType() : which_(Which(-1)) {}
     RetType(Which w) : which_(w) {}
     RetType(AsmJSCoercion coercion) {
         switch (coercion) {
           case AsmJS_ToInt32: which_ = Signed; break;
           case AsmJS_ToNumber: which_ = Double; break;
           case AsmJS_FRound: which_ = Float; break;
         }
     }
@@ -587,35 +587,34 @@ class VarType
     }
     MIRType toMIRType() const {
         switch(which_) {
           case Int:     return MIRType_Int32;
           case Double:  return MIRType_Double;
           case Float:   return MIRType_Float32;
         }
         MOZ_ASSUME_UNREACHABLE("VarType can only be Int, Double or Float");
-        return MIRType_None;
     }
     AsmJSCoercion toCoercion() const {
         switch(which_) {
           case Int:     return AsmJS_ToInt32;
           case Double:  return AsmJS_ToNumber;
           case Float:   return AsmJS_FRound;
         }
         MOZ_ASSUME_UNREACHABLE("VarType can only be Int, Double or Float");
-        return AsmJS_ToInt32;
     }
     static VarType FromMIRType(MIRType type) {
         JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double || type == MIRType_Float32);
         switch(type) {
           case MIRType_Int32:   return Int;
           case MIRType_Float32: return Float;
           case MIRType_Double:  return Double;
-          default: MOZ_ASSUME_UNREACHABLE("FromMIRType MIR type not handled"); return Int;
+          default:;
         }
+        MOZ_ASSUME_UNREACHABLE("FromMIRType MIR type not handled");
     }
     static VarType FromCheckedType(Type type) {
         JS_ASSERT(type.isInt() || type.isMaybeDouble() || type.isFloatish());
         if (type.isMaybeDouble())
             return Double;
         else if (type.isFloatish())
             return Float;
         else
@@ -724,197 +723,16 @@ bool operator==(const Signature &lhs, co
 
 static inline
 bool operator!=(const Signature &lhs, const Signature &rhs)
 {
     return !(lhs == rhs);
 }
 
 /*****************************************************************************/
-// Numeric literal utilities
-
-namespace {
-
-// Represents the type and value of an asm.js numeric literal.
-//
-// A literal is a double iff the literal contains an exponent or decimal point
-// (even if the fractional part is 0). Otherwise, integers may be classified:
-//  fixnum: [0, 2^31)
-//  negative int: [-2^31, 0)
-//  big unsigned: [2^31, 2^32)
-//  out of range: otherwise
-class NumLit
-{
-  public:
-    enum Which {
-        Fixnum = Type::Fixnum,
-        NegativeInt = Type::Signed,
-        BigUnsigned = Type::Unsigned,
-        Double = Type::Double,
-        OutOfRangeInt = -1
-    };
-
-  private:
-    Which which_;
-    Value v_;
-
-  public:
-    NumLit() {}
-
-    NumLit(Which w, Value v)
-      : which_(w), v_(v)
-    {}
-
-    Which which() const {
-        return which_;
-    }
-
-    int32_t toInt32() const {
-        JS_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
-        return v_.toInt32();
-    }
-
-    double toDouble() const {
-        return v_.toDouble();
-    }
-
-    Type type() const {
-        JS_ASSERT(which_ != OutOfRangeInt);
-        return Type::Which(which_);
-    }
-
-    Value value() const {
-        JS_ASSERT(which_ != OutOfRangeInt);
-        return v_;
-    }
-};
-
-} /* anonymous namespace */
-
-// Note: '-' is never rolled into the number; numbers are always positive and
-// negations must be applied manually.
-static bool
-IsNumericLiteral(ParseNode *pn)
-{
-    return pn->isKind(PNK_NUMBER) ||
-           (pn->isKind(PNK_NEG) && UnaryKid(pn)->isKind(PNK_NUMBER));
-}
-
-static NumLit
-ExtractNumericLiteral(ParseNode *pn)
-{
-    // The JS grammar treats -42 as -(42) (i.e., with separate grammar
-    // productions) for the unary - and literal 42). However, the asm.js spec
-    // recognizes -42 (modulo parens, so -(42) and -((42))) as a single literal
-    // so fold the two potential parse nodes into a single double value.
-    JS_ASSERT(IsNumericLiteral(pn));
-    ParseNode *numberNode;
-    double d;
-    if (pn->isKind(PNK_NEG)) {
-        numberNode = UnaryKid(pn);
-        d = -NumberNodeValue(numberNode);
-    } else {
-        numberNode = pn;
-        d = NumberNodeValue(numberNode);
-    }
-
-    // The asm.js spec syntactically distinguishes any literal containing a
-    // decimal point or the literal -0 as having double type.
-    if (NumberNodeHasFrac(numberNode) || IsNegativeZero(d))
-        return NumLit(NumLit::Double, DoubleValue(d));
-
-    // The syntactic checks above rule out these double values.
-    JS_ASSERT(!IsNegativeZero(d));
-    JS_ASSERT(!IsNaN(d));
-
-    // Although doubles can only *precisely* represent 53-bit integers, they
-    // can *imprecisely* represent integers much bigger than an int64_t.
-    // Furthermore, d may be inf or -inf. In both cases, casting to an int64_t
-    // is undefined, so test against the integer bounds using doubles.
-    if (d < double(INT32_MIN) || d > double(UINT32_MAX))
-        return NumLit(NumLit::OutOfRangeInt, UndefinedValue());
-
-    // With the above syntactic and range limitations, d is definitely an
-    // integer in the range [INT32_MIN, UINT32_MAX] range.
-    int64_t i64 = int64_t(d);
-    if (i64 >= 0) {
-        if (i64 <= INT32_MAX)
-            return NumLit(NumLit::Fixnum, Int32Value(i64));
-        JS_ASSERT(i64 <= UINT32_MAX);
-        return NumLit(NumLit::BigUnsigned, Int32Value(uint32_t(i64)));
-    }
-    JS_ASSERT(i64 >= INT32_MIN);
-    return NumLit(NumLit::NegativeInt, Int32Value(i64));
-}
-
-static bool
-ExtractFRoundableLiteral(ParseNode *pn, double *value)
-{
-    if (!IsNumericLiteral(pn))
-        return false;
-
-    NumLit literal = ExtractNumericLiteral(pn);
-    switch (literal.which()) {
-      case NumLit::Double:
-        *value = literal.toDouble();
-        return true;
-      case NumLit::Fixnum:
-      case NumLit::NegativeInt:
-      case NumLit::BigUnsigned:
-        literal = NumLit(NumLit::Double, DoubleValue(literal.toInt32()));
-        *value = literal.toDouble();
-        return true;
-      case NumLit::OutOfRangeInt:
-        break;
-    }
-    return false;
-}
-
-static inline bool
-IsLiteralInt(ParseNode *pn, uint32_t *u32)
-{
-    if (!IsNumericLiteral(pn))
-        return false;
-
-    NumLit literal = ExtractNumericLiteral(pn);
-    switch (literal.which()) {
-      case NumLit::Fixnum:
-      case NumLit::BigUnsigned:
-      case NumLit::NegativeInt:
-        *u32 = uint32_t(literal.toInt32());
-        return true;
-      case NumLit::Double:
-      case NumLit::OutOfRangeInt:
-        return false;
-    }
-
-    MOZ_ASSUME_UNREACHABLE("Bad literal type");
-}
-
-static inline bool
-IsBits32(ParseNode *pn, int32_t i)
-{
-    if (!IsNumericLiteral(pn))
-        return false;
-
-    NumLit literal = ExtractNumericLiteral(pn);
-    switch (literal.which()) {
-      case NumLit::Fixnum:
-      case NumLit::BigUnsigned:
-      case NumLit::NegativeInt:
-        return literal.toInt32() == i;
-      case NumLit::Double:
-      case NumLit::OutOfRangeInt:
-        return false;
-    }
-
-    MOZ_ASSUME_UNREACHABLE("Bad literal type");
-}
-
-/*****************************************************************************/
 // Typed array utilities
 
 static Type
 TypedArrayLoadType(ArrayBufferView::ViewType viewType)
 {
     switch (viewType) {
       case ArrayBufferView::TYPE_INT8:
       case ArrayBufferView::TYPE_INT16:
@@ -1842,16 +1660,242 @@ class MOZ_STACK_CLASS ModuleCompiler
         *module = module_.forget();
         return true;
     }
 };
 
 } /* anonymous namespace */
 
 /*****************************************************************************/
+// Numeric literal utilities
+
+namespace {
+
+// Represents the type and value of an asm.js numeric literal.
+//
+// A literal is a double iff the literal contains an exponent or decimal point
+// (even if the fractional part is 0). Otherwise, integers may be classified:
+//  fixnum: [0, 2^31)
+//  negative int: [-2^31, 0)
+//  big unsigned: [2^31, 2^32)
+//  out of range: otherwise
+// Lastly, a literal may be a float literal which is any double or integer
+// literal coerced with Math.fround.
+class NumLit
+{
+  public:
+    enum Which {
+        Fixnum = Type::Fixnum,
+        NegativeInt = Type::Signed,
+        BigUnsigned = Type::Unsigned,
+        Double = Type::Double,
+        Float = Type::Float,
+        OutOfRangeInt = -1
+    };
+
+  private:
+    Which which_;
+    Value v_;
+
+  public:
+    NumLit() {}
+
+    NumLit(Which w, Value v)
+      : which_(w), v_(v)
+    {}
+
+    Which which() const {
+        return which_;
+    }
+
+    int32_t toInt32() const {
+        JS_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
+        return v_.toInt32();
+    }
+
+    double toDouble() const {
+        JS_ASSERT(which_ == Double);
+        return v_.toDouble();
+    }
+
+    float toFloat() const {
+        JS_ASSERT(which_ == Float);
+        return float(v_.toDouble());
+    }
+
+    Value value() const {
+        JS_ASSERT(which_ != OutOfRangeInt);
+        return v_;
+    }
+
+    bool hasType() const {
+        return which_ != OutOfRangeInt;
+    }
+
+    Type type() const {
+        JS_ASSERT(hasType());
+        return Type::Which(which_);
+    }
+
+    VarType varType() const {
+        JS_ASSERT(hasType());
+        switch (which_) {
+          case NumLit::Fixnum:
+          case NumLit::NegativeInt:
+          case NumLit::BigUnsigned:
+            return VarType::Int;
+          case NumLit::Double:
+            return VarType::Double;
+          case NumLit::Float:
+            return VarType::Float;
+          case NumLit::OutOfRangeInt:;
+        }
+        MOZ_ASSUME_UNREACHABLE("Unexpected NumLit type");
+    }
+};
+
+} /* anonymous namespace */
+
+static bool
+IsNumericNonFloatLiteral(ParseNode *pn)
+{
+    // Note: '-' is never rolled into the number; numbers are always positive
+    // and negations must be applied manually.
+    return pn->isKind(PNK_NUMBER) ||
+           (pn->isKind(PNK_NEG) && UnaryKid(pn)->isKind(PNK_NUMBER));
+}
+
+static bool
+IsFloatCoercion(ModuleCompiler &m, ParseNode *pn, ParseNode **coercedExpr)
+{
+    if (!pn->isKind(PNK_CALL))
+        return false;
+
+    ParseNode *callee = CallCallee(pn);
+    if (!callee->isKind(PNK_NAME))
+        return false;
+
+    const ModuleCompiler::Global *global = m.lookupGlobal(callee->name());
+    if (!global ||
+        global->which() != ModuleCompiler::Global::MathBuiltin ||
+        global->mathBuiltin() != AsmJSMathBuiltin_fround)
+    {
+        return false;
+    }
+
+    if (CallArgListLength(pn) != 1)
+        return false;
+
+    if (coercedExpr)
+        *coercedExpr = CallArgList(pn);
+
+    return true;
+}
+
+static bool
+IsNumericFloatLiteral(ModuleCompiler &m, ParseNode *pn)
+{
+    ParseNode *coercedExpr;
+    if (!IsFloatCoercion(m, pn, &coercedExpr))
+        return false;
+
+    return IsNumericNonFloatLiteral(coercedExpr);
+}
+
+static bool
+IsNumericLiteral(ModuleCompiler &m, ParseNode *pn)
+{
+    return IsNumericNonFloatLiteral(pn) ||
+           IsNumericFloatLiteral(m, pn);
+}
+
+// The JS grammar treats -42 as -(42) (i.e., with separate grammar
+// productions) for the unary - and literal 42). However, the asm.js spec
+// recognizes -42 (modulo parens, so -(42) and -((42))) as a single literal
+// so fold the two potential parse nodes into a single double value.
+static double
+ExtractNumericNonFloatValue(ParseNode **pn)
+{
+    JS_ASSERT(IsNumericNonFloatLiteral(*pn));
+
+    if ((*pn)->isKind(PNK_NEG)) {
+        *pn = UnaryKid(*pn);
+        return -NumberNodeValue(*pn);
+    }
+
+    return NumberNodeValue(*pn);
+}
+
+static NumLit
+ExtractNumericLiteral(ModuleCompiler &m, ParseNode *pn)
+{
+    JS_ASSERT(IsNumericLiteral(m, pn));
+
+    // Float literals are explicitly coerced and thus the coerced literal may be
+    // any valid (non-float) numeric literal.
+    if (pn->isKind(PNK_CALL)) {
+        pn = CallArgList(pn);
+        double d = ExtractNumericNonFloatValue(&pn);
+        return NumLit(NumLit::Float, DoubleValue(d));
+    }
+
+    double d = ExtractNumericNonFloatValue(&pn);
+
+    // The asm.js spec syntactically distinguishes any literal containing a
+    // decimal point or the literal -0 as having double type.
+    if (NumberNodeHasFrac(pn) || IsNegativeZero(d))
+        return NumLit(NumLit::Double, DoubleValue(d));
+
+    // The syntactic checks above rule out these double values.
+    JS_ASSERT(!IsNegativeZero(d));
+    JS_ASSERT(!IsNaN(d));
+
+    // Although doubles can only *precisely* represent 53-bit integers, they
+    // can *imprecisely* represent integers much bigger than an int64_t.
+    // Furthermore, d may be inf or -inf. In both cases, casting to an int64_t
+    // is undefined, so test against the integer bounds using doubles.
+    if (d < double(INT32_MIN) || d > double(UINT32_MAX))
+        return NumLit(NumLit::OutOfRangeInt, UndefinedValue());
+
+    // With the above syntactic and range limitations, d is definitely an
+    // integer in the range [INT32_MIN, UINT32_MAX] range.
+    int64_t i64 = int64_t(d);
+    if (i64 >= 0) {
+        if (i64 <= INT32_MAX)
+            return NumLit(NumLit::Fixnum, Int32Value(i64));
+        JS_ASSERT(i64 <= UINT32_MAX);
+        return NumLit(NumLit::BigUnsigned, Int32Value(uint32_t(i64)));
+    }
+    JS_ASSERT(i64 >= INT32_MIN);
+    return NumLit(NumLit::NegativeInt, Int32Value(i64));
+}
+
+static inline bool
+IsLiteralInt(ModuleCompiler &m, ParseNode *pn, uint32_t *u32)
+{
+    if (!IsNumericLiteral(m, pn))
+        return false;
+
+    NumLit literal = ExtractNumericLiteral(m, pn);
+    switch (literal.which()) {
+      case NumLit::Fixnum:
+      case NumLit::BigUnsigned:
+      case NumLit::NegativeInt:
+        *u32 = uint32_t(literal.toInt32());
+        return true;
+      case NumLit::Double:
+      case NumLit::Float:
+      case NumLit::OutOfRangeInt:
+        return false;
+    }
+
+    MOZ_ASSUME_UNREACHABLE("Bad literal type");
+}
+
+/*****************************************************************************/
 
 namespace {
 
 // Encapsulates the compilation of a single function in an asm.js module. The
 // function compiler handles the creation and final backend compilation of the
 // MIR graph. Also see ModuleCompiler comment.
 class FunctionCompiler
 {
@@ -2060,32 +2104,21 @@ class FunctionCompiler
     {
         if (locals_.has(name))
             return nullptr;
         return m_.lookupGlobal(name);
     }
 
     /***************************** Code generation (after local scope setup) */
 
-    MDefinition *constant(const Value &v)
+    MDefinition *constant(Value v, Type t)
     {
         if (!curBlock_)
             return nullptr;
-        JS_ASSERT(v.isNumber());
-        MConstant *constant = MConstant::New(alloc(), v);
-        curBlock_->add(constant);
-        return constant;
-    }
-
-    MDefinition *constantFloat(float f)
-    {
-        if (!curBlock_)
-            return nullptr;
-
-        MConstant *constant = MConstant::NewAsmJS(alloc(), DoubleValue(double(f)), MIRType_Float32);
+        MConstant *constant = MConstant::NewAsmJS(alloc(), v, t.toMIRType());
         curBlock_->add(constant);
         return constant;
     }
 
     template <class T>
     MDefinition *unary(MDefinition *op)
     {
         if (!curBlock_)
@@ -2921,96 +2954,54 @@ CheckPrecedingStatements(ModuleCompiler 
 
     return true;
 }
 
 static bool
 CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
                                 bool isConst)
 {
-    NumLit literal = ExtractNumericLiteral(initNode);
-    VarType type;
-    switch (literal.which()) {
-      case NumLit::Fixnum:
-      case NumLit::NegativeInt:
-      case NumLit::BigUnsigned:
-        type = VarType::Int;
-        break;
-      case NumLit::Double:
-        type = VarType::Double;
-        break;
-      case NumLit::OutOfRangeInt:
+    NumLit literal = ExtractNumericLiteral(m, initNode);
+    if (!literal.hasType())
         return m.fail(initNode, "global initializer is out of representable integer range");
-    }
-    return m.addGlobalVarInitConstant(varName, type, literal.value(), isConst);
-}
-
-static bool
-CheckFloat32Coercion(ModuleCompiler &m, ParseNode *callNode, ParseNode **coercedExpr,
-                     const char* errorMessage)
-{
-    JS_ASSERT(callNode->isKind(PNK_CALL));
-
-    ParseNode *callee = CallCallee(callNode);
-    if (!callee->isKind(PNK_NAME))
-        return m.fail(callee, errorMessage);
-
-    PropertyName *calleeName = callee->name();
-
-    const ModuleCompiler::Global *global = m.lookupGlobal(calleeName);
-    if (!global || global->which() != ModuleCompiler::Global::MathBuiltin ||
-        global->mathBuiltin() != AsmJSMathBuiltin_fround)
-    {
-        return m.fail(callee, errorMessage);
-    }
-
-    unsigned numArgs = CallArgListLength(callNode);
-    if (numArgs != 1)
-        return m.failf(callee, "fround passed %u arguments, expected one", numArgs);
-
-    if (coercedExpr)
-        *coercedExpr = CallArgList(callNode);
-    return true;
+
+    return m.addGlobalVarInitConstant(varName, literal.varType(), literal.value(), isConst);
 }
 
 static bool
 CheckTypeAnnotation(ModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *coercion,
                     ParseNode **coercedExpr = nullptr)
 {
-    static const char *errorMessage = "in coercion expression, the expression must be of the form +x, fround(x) or x|0";
     switch (coercionNode->getKind()) {
       case PNK_BITOR: {
         ParseNode *rhs = BinaryRight(coercionNode);
-
-        if (!IsNumericLiteral(rhs))
+        uint32_t i;
+        if (!IsLiteralInt(m, rhs, &i) || i != 0)
             return m.fail(rhs, "must use |0 for argument/return coercion");
-
-        NumLit rhsLiteral = ExtractNumericLiteral(rhs);
-        if (rhsLiteral.which() != NumLit::Fixnum || rhsLiteral.toInt32() != 0)
-            return m.fail(rhs, "must use |0 for argument/return coercion");
-
         *coercion = AsmJS_ToInt32;
         if (coercedExpr)
             *coercedExpr = BinaryLeft(coercionNode);
         return true;
       }
       case PNK_POS: {
         *coercion = AsmJS_ToNumber;
         if (coercedExpr)
             *coercedExpr = UnaryKid(coercionNode);
         return true;
       }
       case PNK_CALL: {
         *coercion = AsmJS_FRound;
-        return CheckFloat32Coercion(m, coercionNode, coercedExpr, errorMessage);
+        if (!IsFloatCoercion(m, coercionNode, coercedExpr))
+            return m.fail(coercionNode, "call must be to fround coercion");
+        return true;
       }
       default:;
     }
 
-    return m.fail(coercionNode, errorMessage);
+    return m.fail(coercionNode, "must be of the form +x, fround(x) or x|0");
 }
 
 static bool
 CheckGlobalVariableImportExpr(ModuleCompiler &m, PropertyName *varName, AsmJSCoercion coercion,
                               ParseNode *coercedExpr, bool isConst)
 {
     if (!coercedExpr->isKind(PNK_DOT))
         return m.failName(coercedExpr, "invalid import expression for global '%s'", varName);
@@ -3034,34 +3025,16 @@ CheckGlobalVariableInitImport(ModuleComp
     AsmJSCoercion coercion;
     ParseNode *coercedExpr;
     if (!CheckTypeAnnotation(m, initNode, &coercion, &coercedExpr))
         return false;
     return CheckGlobalVariableImportExpr(m, varName, coercion, coercedExpr, isConst);
 }
 
 static bool
-CheckGlobalVariableInitFloat32(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
-                               bool isConst)
-{
-    ParseNode *arg = nullptr;
-    if (!CheckFloat32Coercion(m, initNode, &arg, "call must be of the form fround(x)"))
-        return false;
-
-    if (IsNumericLiteral(arg)) {
-        double value;
-        if (!ExtractFRoundableLiteral(arg, &value))
-            return m.fail(arg, "float global initializer needs to be a double literal");
-        return m.addGlobalVarInitConstant(varName, VarType::Float, DoubleValue(value), isConst);
-    }
-
-    return CheckGlobalVariableImportExpr(m, varName, AsmJSCoercion::AsmJS_FRound, arg, isConst);
-}
-
-static bool
 CheckNewArrayView(ModuleCompiler &m, PropertyName *varName, ParseNode *newExpr)
 {
     ParseNode *ctorExpr = ListHead(newExpr);
     if (!ctorExpr->isKind(PNK_DOT))
         return m.fail(ctorExpr, "only valid 'new' import is 'new global.*Array(buf)'");
 
     ParseNode *base = DotBase(ctorExpr);
     PropertyName *field = DotMember(ctorExpr);
@@ -3147,25 +3120,22 @@ CheckModuleGlobal(ModuleCompiler &m, Par
 
     if (!CheckModuleLevelName(m, var, var->name()))
         return false;
 
     ParseNode *initNode = MaybeDefinitionInitializer(var);
     if (!initNode)
         return m.fail(var, "module import needs initializer");
 
-    if (IsNumericLiteral(initNode))
+    if (IsNumericLiteral(m, initNode))
         return CheckGlobalVariableInitConstant(m, var->name(), initNode, isConst);
 
-    if (initNode->isKind(PNK_BITOR) || initNode->isKind(PNK_POS))
+    if (initNode->isKind(PNK_BITOR) || initNode->isKind(PNK_POS) || initNode->isKind(PNK_CALL))
         return CheckGlobalVariableInitImport(m, var->name(), initNode, isConst);
 
-    if (initNode->isKind(PNK_CALL))
-        return CheckGlobalVariableInitFloat32(m, var->name(), initNode, isConst);
-
     if (initNode->isKind(PNK_NEW))
         return CheckNewArrayView(m, var->name(), initNode);
 
     if (initNode->isKind(PNK_DOT))
         return CheckGlobalDotImport(m, var->name(), initNode);
 
     return m.fail(initNode, "unsupported import expression");
 }
@@ -3251,28 +3221,31 @@ CheckArguments(FunctionCompiler &f, Pars
     return true;
 }
 
 static bool
 CheckFinalReturn(FunctionCompiler &f, ParseNode *stmt, RetType *retType)
 {
     if (stmt && stmt->isKind(PNK_RETURN)) {
         if (ParseNode *coercionNode = UnaryKid(stmt)) {
-            if (IsNumericLiteral(coercionNode)) {
-                switch (ExtractNumericLiteral(coercionNode).which()) {
+            if (IsNumericLiteral(f.m(), coercionNode)) {
+                switch (ExtractNumericLiteral(f.m(), coercionNode).which()) {
                   case NumLit::BigUnsigned:
                   case NumLit::OutOfRangeInt:
                     return f.fail(coercionNode, "returned literal is out of integer range");
                   case NumLit::Fixnum:
                   case NumLit::NegativeInt:
                     *retType = RetType::Signed;
                     break;
                   case NumLit::Double:
                     *retType = RetType::Double;
                     break;
+                  case NumLit::Float:
+                    *retType = RetType::Float;
+                    break;
                 }
                 return true;
             }
 
             AsmJSCoercion coercion;
             if (!CheckTypeAnnotation(f.m(), coercionNode, &coercion))
                 return false;
 
@@ -3299,47 +3272,24 @@ CheckVariable(FunctionCompiler &f, Parse
 
     if (!CheckIdentifier(f.m(), var, name))
         return false;
 
     ParseNode *initNode = MaybeDefinitionInitializer(var);
     if (!initNode)
         return f.failName(var, "var '%s' needs explicit type declaration via an initial value", name);
 
-    if (initNode->isKind(PNK_CALL)) {
-        ParseNode *coercedVar = nullptr;
-        if (!CheckFloat32Coercion(f.m(), initNode, &coercedVar, "caller in var initializer can only be fround"))
-            return false;
-
-        double value;
-        if (!ExtractFRoundableLiteral(coercedVar, &value))
-            return f.failName(coercedVar, "float initializer for '%s' needs to be a double literal", name);
-
-        return f.addVariable(var, name, VarType::Float, DoubleValue(value));
-    }
-
-    if (!IsNumericLiteral(initNode))
+    if (!IsNumericLiteral(f.m(), initNode))
         return f.failName(initNode, "initializer for '%s' needs to be a numeric literal", name);
 
-    NumLit literal = ExtractNumericLiteral(initNode);
-    VarType type;
-    switch (literal.which()) {
-      case NumLit::Fixnum:
-      case NumLit::NegativeInt:
-      case NumLit::BigUnsigned:
-        type = VarType::Int;
-        break;
-      case NumLit::Double:
-        type = VarType::Double;
-        break;
-      case NumLit::OutOfRangeInt:
+    NumLit literal = ExtractNumericLiteral(f.m(), initNode);
+    if (!literal.hasType())
         return f.failName(initNode, "initializer for '%s' is out of range", name);
-    }
-
-    return f.addVariable(var, name, type, literal.value());
+
+    return f.addVariable(var, name, literal.varType(), literal.value());
 }
 
 static bool
 CheckVariables(FunctionCompiler &f, ParseNode **stmtIter)
 {
     ParseNode *stmt = *stmtIter;
 
     for (; stmt && stmt->isKind(PNK_VAR); stmt = NextNonEmptyStatement(stmt)) {
@@ -3354,31 +3304,22 @@ CheckVariables(FunctionCompiler &f, Pars
 }
 
 static bool
 CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type);
 
 static bool
 CheckNumericLiteral(FunctionCompiler &f, ParseNode *num, MDefinition **def, Type *type)
 {
-    JS_ASSERT(IsNumericLiteral(num));
-    NumLit literal = ExtractNumericLiteral(num);
-
-    switch (literal.which()) {
-      case NumLit::Fixnum:
-      case NumLit::NegativeInt:
-      case NumLit::BigUnsigned:
-      case NumLit::Double:
-        break;
-      case NumLit::OutOfRangeInt:
+    NumLit literal = ExtractNumericLiteral(f.m(), num);
+    if (!literal.hasType())
         return f.fail(num, "numeric literal out of representable integer range");
-    }
 
     *type = literal.type();
-    *def = f.constant(literal.value());
+    *def = f.constant(literal.value(), literal.type());
     return true;
 }
 
 static bool
 CheckVarRef(FunctionCompiler &f, ParseNode *varRef, MDefinition **def, Type *type)
 {
     PropertyName *name = varRef->name();
 
@@ -3386,17 +3327,17 @@ CheckVarRef(FunctionCompiler &f, ParseNo
         *def = f.getLocalDef(*local);
         *type = local->type.toType();
         return true;
     }
 
     if (const ModuleCompiler::Global *global = f.lookupGlobal(name)) {
         switch (global->which()) {
           case ModuleCompiler::Global::Constant:
-            *def = f.constant(DoubleValue(global->constant()));
+            *def = f.constant(DoubleValue(global->constant()), Type::Double);
             *type = Type::Double;
             break;
           case ModuleCompiler::Global::Variable:
             *def = f.loadGlobalVar(*global);
             *type = global->varType().toType();
             break;
           case ModuleCompiler::Global::Function:
           case ModuleCompiler::Global::FFI:
@@ -3409,26 +3350,28 @@ CheckVarRef(FunctionCompiler &f, ParseNo
     }
 
     return f.failName(varRef, "'%s' not found in local or asm.js module scope", name);
 }
 
 static inline bool
 IsLiteralOrConstInt(FunctionCompiler &f, ParseNode *pn, uint32_t *u32)
 {
-    if (IsLiteralInt(pn, u32))
+    if (IsLiteralInt(f.m(), pn, u32))
         return true;
 
     if (pn->getKind() != PNK_NAME)
         return false;
 
     PropertyName *name = pn->name();
     const ModuleCompiler::Global *global = f.lookupGlobal(name);
-    if (!global || global->which() != ModuleCompiler::Global::Variable ||
-        !global->varIsLitConstant()) {
+    if (!global ||
+        global->which() != ModuleCompiler::Global::Variable ||
+        !global->varIsLitConstant())
+    {
         return false;
     }
 
     const Value &v = global->litConstValue();
     if (!v.isInt32())
         return false;
 
     *u32 = (uint32_t) v.toInt32();
@@ -3480,32 +3423,32 @@ CheckArrayAccess(FunctionCompiler &f, Pa
         if (pointer > (uint32_t(INT32_MAX) >> TypedArrayShift(*viewType)))
             return f.fail(indexExpr, "constant index out of range");
         pointer <<= TypedArrayShift(*viewType);
         // It is adequate to note pointer+1 rather than rounding up to the next
         // access-size boundary because access is always aligned and the constraint
         // will be rounded up to a larger alignment later.
         f.m().requireHeapLengthToBeAtLeast(uint32_t(pointer) + 1);
         *needsBoundsCheck = NO_BOUNDS_CHECK;
-        *def = f.constant(Int32Value(pointer));
+        *def = f.constant(Int32Value(pointer), Type::Int);
         return true;
     }
 
     // Mask off the low bits to account for the clearing effect of a right shift
     // followed by the left shift implicit in the array access. E.g., H32[i>>2]
     // loses the low two bits.
     int32_t mask = ~((uint32_t(1) << TypedArrayShift(*viewType)) - 1);
 
     MDefinition *pointerDef;
     if (indexExpr->isKind(PNK_RSH)) {
         ParseNode *shiftNode = BinaryRight(indexExpr);
         ParseNode *pointerNode = BinaryLeft(indexExpr);
 
         uint32_t shift;
-        if (!IsLiteralInt(shiftNode, &shift))
+        if (!IsLiteralInt(f.m(), shiftNode, &shift))
             return f.failf(shiftNode, "shift amount must be constant");
 
         unsigned requiredShift = TypedArrayShift(*viewType);
         if (shift != requiredShift)
             return f.failf(shiftNode, "shift amount must be %u", requiredShift);
 
         if (pointerNode->isKind(PNK_BITAND))
             FoldMaskedArrayIndex(f, &pointerNode, &mask, needsBoundsCheck);
@@ -3513,17 +3456,17 @@ CheckArrayAccess(FunctionCompiler &f, Pa
         // Fold a 'literal constant right shifted' now, and skip the bounds check if
         // currently possible. This handles the optimization of many of these uses without
         // the need for range analysis, and saves the generation of a MBitAnd op.
         if (IsLiteralOrConstInt(f, pointerNode, &pointer) && pointer <= uint32_t(INT32_MAX)) {
             // Cases: b[c>>n], and b[(c&m)>>n]
             pointer &= mask;
             if (pointer < f.m().minHeapLength())
                 *needsBoundsCheck = NO_BOUNDS_CHECK;
-            *def = f.constant(Int32Value(pointer));
+            *def = f.constant(Int32Value(pointer), Type::Int);
             return true;
         }
 
         Type pointerType;
         if (!CheckExpr(f, pointerNode, &pointerDef, &pointerType))
             return false;
 
         if (!pointerType.isIntish())
@@ -3551,17 +3494,17 @@ CheckArrayAccess(FunctionCompiler &f, Pa
         }
     }
 
     // Don't generate the mask op if there is no need for it which could happen for
     // a shift of zero.
     if (mask == -1)
         *def = pointerDef;
     else
-        *def = f.bitwise<MBitAnd>(pointerDef, f.constant(Int32Value(mask)));
+        *def = f.bitwise<MBitAnd>(pointerDef, f.constant(Int32Value(mask), Type::Int));
 
     return true;
 }
 
 static bool
 CheckLoadArray(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *type)
 {
     ArrayBufferView::ViewType viewType;
@@ -3917,17 +3860,17 @@ CheckFuncPtrCall(FunctionCompiler &f, Pa
 
     if (!indexExpr->isKind(PNK_BITAND))
         return f.fail(indexExpr, "function-pointer table index expression needs & mask");
 
     ParseNode *indexNode = BinaryLeft(indexExpr);
     ParseNode *maskNode = BinaryRight(indexExpr);
 
     uint32_t mask;
-    if (!IsLiteralInt(maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
+    if (!IsLiteralInt(f.m(), maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
         return f.fail(maskNode, "function-pointer table index mask value must be a power of two");
 
     MDefinition *indexDef;
     Type indexType;
     if (!CheckExpr(f, indexNode, &indexDef, &indexType))
         return false;
 
     if (!indexType.isIntish())
@@ -3979,35 +3922,21 @@ CheckFFICall(FunctionCompiler &f, ParseN
 
     *type = retType.toType();
     return true;
 }
 
 static bool CheckCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **def, Type *type);
 
 static bool
-CheckFRoundArg(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type, const char* error)
-{
-    ParseNode *arg = nullptr;
-    if (!CheckFloat32Coercion(f.m(), expr, &arg, error))
-        return false;
-
+CheckFRoundArg(FunctionCompiler &f, ParseNode *arg, MDefinition **def, Type *type)
+{
     if (arg->isKind(PNK_CALL))
         return CheckCall(f, arg, RetType::Float, def, type);
 
-    if (IsNumericLiteral(arg)) {
-        double value;
-        if (!ExtractFRoundableLiteral(arg, &value))
-            return f.fail(arg, "call to fround with literal expects the literal to be a double");
-
-        *def = f.constantFloat(value);
-        *type = Type::Float;
-        return true;
-    }
-
     MDefinition *inputDef;
     Type inputType;
     if (!CheckExpr(f, arg, &inputDef, &inputType))
         return false;
 
     if (inputType.isMaybeDouble() || inputType.isSigned())
         *def = f.unary<MToFloat32>(inputDef);
     else if (inputType.isUnsigned())
@@ -4017,22 +3946,28 @@ CheckFRoundArg(FunctionCompiler &f, Pars
     else
         return f.failf(arg, "%s is not a subtype of signed, unsigned, double? or floatish", inputType.toChars());
 
     *type = Type::Float;
     return true;
 }
 
 static bool
-CheckFRound(FunctionCompiler &f, ParseNode *callNode, RetType retType, MDefinition **def, Type *type)
-{
+CheckMathFRound(FunctionCompiler &f, ParseNode *callNode, RetType retType, MDefinition **def, Type *type)
+{
+    ParseNode *argNode = nullptr;
+    if (!IsFloatCoercion(f.m(), callNode, &argNode))
+        return f.fail(callNode, "invalid call to fround");
+
     MDefinition *operand;
     Type operandType;
-    if (!CheckFRoundArg(f, callNode, &operand, &operandType, "coercion to float should use fround"))
-        return false;
+    if (!CheckFRoundArg(f, argNode, &operand, &operandType))
+        return false;
+
+    JS_ASSERT(operandType == Type::Float);
 
     switch (retType.which()) {
       case RetType::Double:
         *def = f.unary<MToDouble>(operand);
         *type = Type::Double;
         return true;
       case RetType::Signed:
         *def = f.unary<MTruncateToInt32>(operand);
@@ -4071,17 +4006,17 @@ CheckMathBuiltinCall(FunctionCompiler &f
                      RetType retType, MDefinition **def, Type *type)
 {
     unsigned arity = 0;
     AsmJSImmKind doubleCallee, floatCallee;
     switch (mathBuiltin) {
       case AsmJSMathBuiltin_imul:   return CheckMathIMul(f, callNode, retType, def, type);
       case AsmJSMathBuiltin_abs:    return CheckMathAbs(f, callNode, retType, def, type);
       case AsmJSMathBuiltin_sqrt:   return CheckMathSqrt(f, callNode, retType, def, type);
-      case AsmJSMathBuiltin_fround: return CheckFRound(f, callNode, retType, def, type);
+      case AsmJSMathBuiltin_fround: return CheckMathFRound(f, callNode, retType, def, type);
       case AsmJSMathBuiltin_sin:    arity = 1; doubleCallee = AsmJSImm_SinD; floatCallee = AsmJSImm_SinF;      break;
       case AsmJSMathBuiltin_cos:    arity = 1; doubleCallee = AsmJSImm_CosD; floatCallee = AsmJSImm_CosF;      break;
       case AsmJSMathBuiltin_tan:    arity = 1; doubleCallee = AsmJSImm_TanD; floatCallee = AsmJSImm_TanF;      break;
       case AsmJSMathBuiltin_asin:   arity = 1; doubleCallee = AsmJSImm_ASinD; floatCallee = AsmJSImm_ASinF;    break;
       case AsmJSMathBuiltin_acos:   arity = 1; doubleCallee = AsmJSImm_ACosD; floatCallee = AsmJSImm_ACosF;    break;
       case AsmJSMathBuiltin_atan:   arity = 1; doubleCallee = AsmJSImm_ATanD; floatCallee = AsmJSImm_ATanF;    break;
       case AsmJSMathBuiltin_ceil:   arity = 1; doubleCallee = AsmJSImm_CeilD; floatCallee = AsmJSImm_CeilF;    break;
       case AsmJSMathBuiltin_floor:  arity = 1; doubleCallee = AsmJSImm_FloorD; floatCallee = AsmJSImm_FloorF;  break;
@@ -4352,30 +4287,31 @@ CheckConditional(FunctionCompiler &f, Pa
     if (!f.joinIfElse(thenBlocks, elseExpr))
         return false;
 
     *def = f.popPhiOutput();
     return true;
 }
 
 static bool
-IsValidIntMultiplyConstant(ParseNode *expr)
-{
-    if (!IsNumericLiteral(expr))
-        return false;
-
-    NumLit literal = ExtractNumericLiteral(expr);
+IsValidIntMultiplyConstant(ModuleCompiler &m, ParseNode *expr)
+{
+    if (!IsNumericLiteral(m, expr))
+        return false;
+
+    NumLit literal = ExtractNumericLiteral(m, expr);
     switch (literal.which()) {
       case NumLit::Fixnum:
       case NumLit::NegativeInt:
         if (abs(literal.toInt32()) < (1<<20))
             return true;
         return false;
       case NumLit::BigUnsigned:
       case NumLit::Double:
+      case NumLit::Float:
       case NumLit::OutOfRangeInt:
         return false;
     }
 
     MOZ_ASSUME_UNREACHABLE("Bad literal");
 }
 
 static bool
@@ -4391,17 +4327,17 @@ CheckMultiply(FunctionCompiler &f, Parse
         return false;
 
     MDefinition *rhsDef;
     Type rhsType;
     if (!CheckExpr(f, rhs, &rhsDef, &rhsType))
         return false;
 
     if (lhsType.isInt() && rhsType.isInt()) {
-        if (!IsValidIntMultiplyConstant(lhs) && !IsValidIntMultiplyConstant(rhs))
+        if (!IsValidIntMultiplyConstant(f.m(), lhs) && !IsValidIntMultiplyConstant(f.m(), rhs))
             return f.fail(star, "one arg to int multiply must be a small (-2^20, 2^20) int literal");
         *def = f.mul(lhsDef, rhsDef, MIRType_Int32, MMul::Integer);
         *type = Type::Intish;
         return true;
     }
 
     if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
         *def = f.mul(lhsDef, rhsDef, MIRType_Double, MMul::Normal);
@@ -4589,26 +4525,27 @@ CheckBitwise(FunctionCompiler &f, ParseN
       case PNK_BITAND: identityElement = -1; onlyOnRight = false; *type = Type::Signed;   break;
       case PNK_BITXOR: identityElement = 0;  onlyOnRight = false; *type = Type::Signed;   break;
       case PNK_LSH:    identityElement = 0;  onlyOnRight = true;  *type = Type::Signed;   break;
       case PNK_RSH:    identityElement = 0;  onlyOnRight = true;  *type = Type::Signed;   break;
       case PNK_URSH:   identityElement = 0;  onlyOnRight = true;  *type = Type::Unsigned; break;
       default: MOZ_ASSUME_UNREACHABLE("not a bitwise op");
     }
 
-    if (!onlyOnRight && IsBits32(lhs, identityElement)) {
+    uint32_t i;
+    if (!onlyOnRight && IsLiteralInt(f.m(), lhs, &i) && i == uint32_t(identityElement)) {
         Type rhsType;
         if (!CheckExpr(f, rhs, def, &rhsType))
             return false;
         if (!rhsType.isIntish())
             return f.failf(bitwise, "%s is not a subtype of intish", rhsType.toChars());
         return true;
     }
 
-    if (IsBits32(rhs, identityElement)) {
+    if (IsLiteralInt(f.m(), rhs, &i) && i == uint32_t(identityElement)) {
         if (bitwise->isKind(PNK_BITOR) && lhs->isKind(PNK_CALL))
             return CheckCall(f, lhs, RetType::Signed, def, type);
 
         Type lhsType;
         if (!CheckExpr(f, lhs, def, &lhsType))
             return false;
         if (!lhsType.isIntish())
             return f.failf(bitwise, "%s is not a subtype of intish", lhsType.toChars());
@@ -4641,34 +4578,37 @@ CheckBitwise(FunctionCompiler &f, ParseN
     }
 
     return true;
 }
 
 static bool
 CheckUncoercedCall(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type)
 {
-    static const char* callError = "all function calls must either be ignored (via "
-                                   "f(); or comma-expression), coerced to signed "
-                                   "(via f()|0), coerced to float (via fround(f()))"
-                                   " or coerced to double (via +f())";
-
     JS_ASSERT(expr->isKind(PNK_CALL));
-    return CheckFRoundArg(f, expr, def, type, callError);
+
+    ParseNode *arg;
+    if (!IsFloatCoercion(f.m(), expr, &arg)) {
+        return f.fail(expr, "all function calls must either be ignored (via f(); or "
+                            "comma-expression), coerced to signed (via f()|0), coerced to float "
+                            "(via fround(f())) or coerced to double (via +f())");
+    }
+
+    return CheckFRoundArg(f, arg, def, type);
 }
 
 static bool
 CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type)
 {
     JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed());
 
     if (!f.mirGen().ensureBallast())
         return false;
 
-    if (IsNumericLiteral(expr))
+    if (IsNumericLiteral(f.m(), expr))
         return CheckNumericLiteral(f, expr, def, type);
 
     switch (expr->getKind()) {
       case PNK_NAME:        return CheckVarRef(f, expr, def, type);
       case PNK_ELEM:        return CheckLoadArray(f, expr, def, type);
       case PNK_ASSIGN:      return CheckAssign(f, expr, def, type);
       case PNK_POS:         return CheckPos(f, expr, def, type);
       case PNK_NOT:         return CheckNot(f, expr, def, type);
@@ -4787,17 +4727,17 @@ CheckFor(FunctionCompiler &f, ParseNode 
     if (maybeCond) {
         Type condType;
         if (!CheckExpr(f, maybeCond, &condDef, &condType))
             return false;
 
         if (!condType.isInt())
             return f.failf(maybeCond, "%s is not a subtype of int", condType.toChars());
     } else {
-        condDef = f.constant(Int32Value(1));
+        condDef = f.constant(Int32Value(1), Type::Int);
     }
 
     MBasicBlock *afterLoop;
     if (!f.branchAndStartLoopBody(condDef, &afterLoop, body, NextNode(forStmt)))
         return false;
 
     if (!CheckStatement(f, body))
         return false;
@@ -4925,29 +4865,30 @@ CheckIf(FunctionCompiler &f, ParseNode *
     }
 
     return true;
 }
 
 static bool
 CheckCaseExpr(FunctionCompiler &f, ParseNode *caseExpr, int32_t *value)
 {
-    if (!IsNumericLiteral(caseExpr))
+    if (!IsNumericLiteral(f.m(), caseExpr))
         return f.fail(caseExpr, "switch case expression must be an integer literal");
 
-    NumLit literal = ExtractNumericLiteral(caseExpr);
+    NumLit literal = ExtractNumericLiteral(f.m(), caseExpr);
     switch (literal.which()) {
       case NumLit::Fixnum:
       case NumLit::NegativeInt:
         *value = literal.toInt32();
         break;
       case NumLit::OutOfRangeInt:
       case NumLit::BigUnsigned:
         return f.fail(caseExpr, "switch case expression out of integer range");
       case NumLit::Double:
+      case NumLit::Float:
         return f.fail(caseExpr, "switch case expression must be an integer literal");
     }
 
     return true;
 }
 
 static bool
 CheckDefaultAtEnd(FunctionCompiler &f, ParseNode *stmt)
@@ -5030,17 +4971,17 @@ CheckSwitch(FunctionCompiler &f, ParseNo
     if (!cases.resize(tableLength))
         return false;
 
     MBasicBlock *switchBlock;
     if (!f.startSwitch(switchStmt, exprDef, low, high, &switchBlock))
         return false;
 
     for (; stmt && stmt->isKind(PNK_CASE); stmt = NextNode(stmt)) {
-        int32_t caseValue = ExtractNumericLiteral(CaseExpr(stmt)).toInt32();
+        int32_t caseValue = ExtractNumericLiteral(f.m(), CaseExpr(stmt)).toInt32();
         unsigned caseIndex = caseValue - low;
 
         if (cases[caseIndex])
             return f.fail(stmt, "no duplicate case labels");
 
         if (!f.startSwitchCase(switchBlock, &cases[caseIndex], stmt))
             return false;
 
@@ -5256,17 +5197,17 @@ CheckFunction(ModuleCompiler &m, LifoAll
     RetType retType;
     if (!CheckFinalReturn(f, lastNonEmptyStmt, &retType))
         return false;
 
     if (!CheckReturnType(f, lastNonEmptyStmt, retType))
         return false;
 
     Signature sig(Move(argTypes), retType);
-    ModuleCompiler::Func *func;
+    ModuleCompiler::Func *func = nullptr;
     if (!CheckFunctionSignature(m, fn, Move(sig), FunctionName(fn), &func))
         return false;
 
     if (func->defined())
         return m.failName(fn, "function '%s' already defined", FunctionName(fn));
 
     func->define(fn->pn_pos.begin);
     func->accumulateCompileTime((PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC);