mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-01 13:57:32 +00:00
Bug 904918: Odin Float32 support; p=bbouvier,dougc r=luke,sstangl
Authors: - Douglas Crosher (dougc) for the ARM backend support - Benjamin Bouvier (bbouvier) for everything else
This commit is contained in:
parent
fd36ed6219
commit
1b008d2a72
@ -270,7 +270,7 @@ private:
|
||||
OP_GROUP2_Ev1 = 0xD1,
|
||||
OP_GROUP2_EvCL = 0xD3,
|
||||
OP_FPU6 = 0xDD,
|
||||
OP_FLD32 = 0xD9,
|
||||
OP_FPU6_F32 = 0xD9,
|
||||
OP_CALL_rel32 = 0xE8,
|
||||
OP_JMP_rel32 = 0xE9,
|
||||
PRE_SSE_F2 = 0xF2,
|
||||
@ -732,7 +732,7 @@ public:
|
||||
void fld32_m(int offset, RegisterID base)
|
||||
{
|
||||
spew("fld %s0x%x(%s)", PRETTY_PRINT_OFFSET(offset), nameIReg(base));
|
||||
m_formatter.oneByteOp(OP_FLD32, FPU6_OP_FLD, base, offset);
|
||||
m_formatter.oneByteOp(OP_FPU6_F32, FPU6_OP_FLD, base, offset);
|
||||
}
|
||||
void fisttp_m(int offset, RegisterID base)
|
||||
{
|
||||
@ -747,7 +747,7 @@ public:
|
||||
void fstp32_m(int offset, RegisterID base)
|
||||
{
|
||||
spew("fstp32 %s0x%x(%s)", PRETTY_PRINT_OFFSET(offset), nameIReg(base));
|
||||
m_formatter.oneByteOp(OP_FLD32, FPU6_OP_FSTP, base, offset);
|
||||
m_formatter.oneByteOp(OP_FPU6_F32, FPU6_OP_FSTP, base, offset);
|
||||
}
|
||||
|
||||
void negl_r(RegisterID dst)
|
||||
|
@ -368,7 +368,10 @@ class Type
|
||||
public:
|
||||
enum Which {
|
||||
Double,
|
||||
Doublish,
|
||||
MaybeDouble,
|
||||
Float,
|
||||
MaybeFloat,
|
||||
Floatish,
|
||||
Fixnum,
|
||||
Int,
|
||||
Signed,
|
||||
@ -407,8 +410,20 @@ class Type
|
||||
return which_ == Double;
|
||||
}
|
||||
|
||||
bool isDoublish() const {
|
||||
return isDouble() || which_ == Doublish;
|
||||
bool isMaybeDouble() const {
|
||||
return isDouble() || which_ == MaybeDouble;
|
||||
}
|
||||
|
||||
bool isFloat() const {
|
||||
return which_ == Float;
|
||||
}
|
||||
|
||||
bool isMaybeFloat() const {
|
||||
return isFloat() || which_ == MaybeFloat;
|
||||
}
|
||||
|
||||
bool isFloatish() const {
|
||||
return isMaybeFloat() || which_ == Floatish;
|
||||
}
|
||||
|
||||
bool isVoid() const {
|
||||
@ -420,14 +435,18 @@ class Type
|
||||
}
|
||||
|
||||
bool isVarType() const {
|
||||
return isInt() || isDouble();
|
||||
return isInt() || isDouble() || isFloat();
|
||||
}
|
||||
|
||||
MIRType toMIRType() const {
|
||||
switch (which_) {
|
||||
case Double:
|
||||
case Doublish:
|
||||
case MaybeDouble:
|
||||
return MIRType_Double;
|
||||
case Float:
|
||||
case Floatish:
|
||||
case MaybeFloat:
|
||||
return MIRType_Float32;
|
||||
case Fixnum:
|
||||
case Int:
|
||||
case Signed:
|
||||
@ -442,14 +461,17 @@ class Type
|
||||
|
||||
const char *toChars() const {
|
||||
switch (which_) {
|
||||
case Double: return "double";
|
||||
case Doublish: return "doublish";
|
||||
case Fixnum: return "fixnum";
|
||||
case Int: return "int";
|
||||
case Signed: return "signed";
|
||||
case Unsigned: return "unsigned";
|
||||
case Intish: return "intish";
|
||||
case Void: return "void";
|
||||
case Double: return "double";
|
||||
case MaybeDouble: return "double?";
|
||||
case Float: return "float";
|
||||
case Floatish: return "floatish";
|
||||
case MaybeFloat: return "float?";
|
||||
case Fixnum: return "fixnum";
|
||||
case Int: return "int";
|
||||
case Signed: return "signed";
|
||||
case Unsigned: return "unsigned";
|
||||
case Intish: return "intish";
|
||||
case Void: return "void";
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Invalid Type");
|
||||
}
|
||||
@ -465,7 +487,8 @@ class RetType
|
||||
enum Which {
|
||||
Void = Type::Void,
|
||||
Signed = Type::Signed,
|
||||
Double = Type::Double
|
||||
Double = Type::Double,
|
||||
Float = Type::Float
|
||||
};
|
||||
|
||||
private:
|
||||
@ -478,6 +501,7 @@ class RetType
|
||||
switch (coercion) {
|
||||
case AsmJS_ToInt32: which_ = Signed; break;
|
||||
case AsmJS_ToNumber: which_ = Double; break;
|
||||
case AsmJS_FRound: which_ = Float; break;
|
||||
}
|
||||
}
|
||||
Which which() const {
|
||||
@ -490,6 +514,7 @@ class RetType
|
||||
switch (which_) {
|
||||
case Void: return AsmJSModule::Return_Void;
|
||||
case Signed: return AsmJSModule::Return_Int32;
|
||||
case Float: // will be converted to a Double
|
||||
case Double: return AsmJSModule::Return_Double;
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected return type");
|
||||
@ -499,6 +524,7 @@ class RetType
|
||||
case Void: return MIRType_None;
|
||||
case Signed: return MIRType_Int32;
|
||||
case Double: return MIRType_Double;
|
||||
case Float: return MIRType_Float32;
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected return type");
|
||||
}
|
||||
@ -534,7 +560,8 @@ class VarType
|
||||
public:
|
||||
enum Which {
|
||||
Int = Type::Int,
|
||||
Double = Type::Double
|
||||
Double = Type::Double,
|
||||
Float = Type::Float
|
||||
};
|
||||
|
||||
private:
|
||||
@ -549,6 +576,7 @@ class VarType
|
||||
switch (coercion) {
|
||||
case AsmJS_ToInt32: which_ = Int; break;
|
||||
case AsmJS_ToNumber: which_ = Double; break;
|
||||
case AsmJS_FRound: which_ = Float; break;
|
||||
}
|
||||
}
|
||||
Which which() const {
|
||||
@ -558,18 +586,40 @@ class VarType
|
||||
return Type::Which(which_);
|
||||
}
|
||||
MIRType toMIRType() const {
|
||||
return which_ == Int ? MIRType_Int32 : MIRType_Double;
|
||||
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 {
|
||||
return which_ == Int ? AsmJS_ToInt32 : AsmJS_ToNumber;
|
||||
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);
|
||||
return type == MIRType_Int32 ? Int : Double;
|
||||
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;
|
||||
}
|
||||
}
|
||||
static VarType FromCheckedType(Type type) {
|
||||
JS_ASSERT(type.isInt() || type.isDoublish());
|
||||
return type.isDoublish() ? Double : Int;
|
||||
JS_ASSERT(type.isInt() || type.isMaybeDouble() || type.isFloatish());
|
||||
if (type.isMaybeDouble())
|
||||
return Double;
|
||||
else if (type.isFloatish())
|
||||
return Float;
|
||||
else
|
||||
return Int;
|
||||
}
|
||||
bool operator==(VarType rhs) const { return which_ == rhs.which_; }
|
||||
bool operator!=(VarType rhs) const { return which_ != rhs.which_; }
|
||||
@ -584,6 +634,7 @@ operator<=(Type lhs, VarType rhs)
|
||||
switch (rhs.which()) {
|
||||
case VarType::Int: return lhs.isInt();
|
||||
case VarType::Double: return lhs.isDouble();
|
||||
case VarType::Float: return lhs.isFloat();
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected rhs type");
|
||||
}
|
||||
@ -706,6 +757,8 @@ class NumLit
|
||||
Value v_;
|
||||
|
||||
public:
|
||||
NumLit() {}
|
||||
|
||||
NumLit(Which w, Value v)
|
||||
: which_(w), v_(v)
|
||||
{}
|
||||
@ -792,6 +845,29 @@ ExtractNumericLiteral(ParseNode *pn)
|
||||
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)
|
||||
{
|
||||
@ -848,32 +924,9 @@ TypedArrayLoadType(ArrayBufferView::ViewType viewType)
|
||||
case ArrayBufferView::TYPE_UINT32:
|
||||
return Type::Intish;
|
||||
case ArrayBufferView::TYPE_FLOAT32:
|
||||
return Type::MaybeFloat;
|
||||
case ArrayBufferView::TYPE_FLOAT64:
|
||||
return Type::Doublish;
|
||||
default:;
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected array type");
|
||||
}
|
||||
|
||||
enum ArrayStoreEnum {
|
||||
ArrayStore_Intish,
|
||||
ArrayStore_Doublish
|
||||
};
|
||||
|
||||
static ArrayStoreEnum
|
||||
TypedArrayStoreType(ArrayBufferView::ViewType viewType)
|
||||
{
|
||||
switch (viewType) {
|
||||
case ArrayBufferView::TYPE_INT8:
|
||||
case ArrayBufferView::TYPE_INT16:
|
||||
case ArrayBufferView::TYPE_INT32:
|
||||
case ArrayBufferView::TYPE_UINT8:
|
||||
case ArrayBufferView::TYPE_UINT16:
|
||||
case ArrayBufferView::TYPE_UINT32:
|
||||
return ArrayStore_Intish;
|
||||
case ArrayBufferView::TYPE_FLOAT32:
|
||||
case ArrayBufferView::TYPE_FLOAT64:
|
||||
return ArrayStore_Doublish;
|
||||
return Type::MaybeDouble;
|
||||
default:;
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected array type");
|
||||
@ -1305,7 +1358,8 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
!addStandardLibraryMathName("sqrt", AsmJSMathBuiltin_sqrt) ||
|
||||
!addStandardLibraryMathName("abs", AsmJSMathBuiltin_abs) ||
|
||||
!addStandardLibraryMathName("atan2", AsmJSMathBuiltin_atan2) ||
|
||||
!addStandardLibraryMathName("imul", AsmJSMathBuiltin_imul))
|
||||
!addStandardLibraryMathName("imul", AsmJSMathBuiltin_imul) ||
|
||||
!addStandardLibraryMathName("fround", AsmJSMathBuiltin_fround))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1441,7 +1495,7 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
bool addGlobalVarInitConstant(PropertyName *varName, VarType type, const Value &v,
|
||||
bool isConst) {
|
||||
uint32_t index;
|
||||
if (!module_->addGlobalVarInitConstant(v, &index))
|
||||
if (!module_->addGlobalVarInitConstant(v, type.toCoercion(), &index))
|
||||
return false;
|
||||
Global *global = moduleLifo_.new_<Global>(Global::Variable);
|
||||
if (!global)
|
||||
@ -1808,9 +1862,16 @@ class FunctionCompiler
|
||||
Local(VarType t, unsigned slot) : type(t), slot(slot) {}
|
||||
};
|
||||
|
||||
struct TypedValue
|
||||
{
|
||||
VarType type;
|
||||
Value value;
|
||||
TypedValue(VarType t, const Value &v) : type(t), value(v) {}
|
||||
};
|
||||
|
||||
private:
|
||||
typedef HashMap<PropertyName*, Local> LocalMap;
|
||||
typedef js::Vector<Value> VarInitializerVector;
|
||||
typedef js::Vector<TypedValue> VarInitializerVector;
|
||||
typedef HashMap<PropertyName*, BlockVector> LabeledBlockMap;
|
||||
typedef HashMap<ParseNode*, BlockVector> UnlabeledBlockMap;
|
||||
typedef js::Vector<ParseNode*, 4> NodeStack;
|
||||
@ -1924,7 +1985,7 @@ class FunctionCompiler
|
||||
return failName(pn, "duplicate local name '%s' not allowed", name);
|
||||
if (!locals_.add(p, name, Local(type, locals_.count())))
|
||||
return false;
|
||||
return varInitializers_.append(init);
|
||||
return varInitializers_.append(TypedValue(type, init));
|
||||
}
|
||||
|
||||
bool prepareToEmitMIR(const VarTypeVector &argTypes)
|
||||
@ -1950,7 +2011,8 @@ class FunctionCompiler
|
||||
}
|
||||
unsigned firstLocalSlot = argTypes.length();
|
||||
for (unsigned i = 0; i < varInitializers_.length(); i++) {
|
||||
MConstant *ins = MConstant::New(alloc(), varInitializers_[i]);
|
||||
MConstant *ins = MConstant::NewAsmJS(alloc(), varInitializers_[i].value,
|
||||
varInitializers_[i].type.toMIRType());
|
||||
curBlock_->add(ins);
|
||||
curBlock_->initSlot(info().localSlot(firstLocalSlot + i), ins);
|
||||
}
|
||||
@ -2010,6 +2072,16 @@ class FunctionCompiler
|
||||
return constant;
|
||||
}
|
||||
|
||||
MDefinition *constantFloat(float f)
|
||||
{
|
||||
if (!curBlock_)
|
||||
return NULL;
|
||||
|
||||
MConstant *constant = MConstant::NewAsmJS(alloc(), DoubleValue(double(f)), MIRType_Float32);
|
||||
curBlock_->add(constant);
|
||||
return constant;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
MDefinition *unary(MDefinition *op)
|
||||
{
|
||||
@ -2869,10 +2941,39 @@ CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseN
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
@ -2895,21 +2996,20 @@ CheckTypeAnnotation(ModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *c
|
||||
*coercedExpr = UnaryKid(coercionNode);
|
||||
return true;
|
||||
}
|
||||
case PNK_CALL: {
|
||||
*coercion = AsmJS_FRound;
|
||||
return CheckFloat32Coercion(m, coercionNode, coercedExpr, errorMessage);
|
||||
}
|
||||
default:;
|
||||
}
|
||||
|
||||
return m.fail(coercionNode, "in coercion expression, the expression must be of the form +x or x|0");
|
||||
return m.fail(coercionNode, errorMessage);
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
|
||||
bool isConst)
|
||||
CheckGlobalVariableImportExpr(ModuleCompiler &m, PropertyName *varName, AsmJSCoercion coercion,
|
||||
ParseNode *coercedExpr, bool isConst)
|
||||
{
|
||||
AsmJSCoercion coercion;
|
||||
ParseNode *coercedExpr;
|
||||
if (!CheckTypeAnnotation(m, initNode, &coercion, &coercedExpr))
|
||||
return false;
|
||||
|
||||
if (!coercedExpr->isKind(PNK_DOT))
|
||||
return m.failName(coercedExpr, "invalid import expression for global '%s'", varName);
|
||||
|
||||
@ -2925,6 +3025,35 @@ CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNod
|
||||
return m.addGlobalVarImport(varName, field, coercion, isConst);
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
|
||||
bool isConst)
|
||||
{
|
||||
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 = NULL;
|
||||
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)
|
||||
{
|
||||
@ -3027,6 +3156,9 @@ CheckModuleGlobal(ModuleCompiler &m, ParseNode *var, bool isConst)
|
||||
if (initNode->isKind(PNK_BITOR) || initNode->isKind(PNK_POS))
|
||||
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);
|
||||
|
||||
@ -3058,7 +3190,7 @@ static bool
|
||||
ArgFail(FunctionCompiler &f, PropertyName *argName, ParseNode *stmt)
|
||||
{
|
||||
return f.failName(stmt, "expecting argument type declaration for '%s' of the "
|
||||
"form 'arg = arg|0' or 'arg = +arg'", argName);
|
||||
"form 'arg = arg|0' or 'arg = +arg' or 'arg = fround(arg)'", argName);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -3170,6 +3302,18 @@ CheckVariable(FunctionCompiler &f, ParseNode *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 = NULL;
|
||||
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))
|
||||
return f.failName(initNode, "initializer for '%s' needs to be a numeric literal", name);
|
||||
|
||||
@ -3416,7 +3560,7 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, ArrayBufferView::ViewType
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckArrayLoad(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *type)
|
||||
CheckLoadArray(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *type)
|
||||
{
|
||||
ArrayBufferView::ViewType viewType;
|
||||
MDefinition *pointerDef;
|
||||
@ -3443,15 +3587,30 @@ CheckStoreArray(FunctionCompiler &f, ParseNode *lhs, ParseNode *rhs, MDefinition
|
||||
if (!CheckExpr(f, rhs, &rhsDef, &rhsType))
|
||||
return false;
|
||||
|
||||
switch (TypedArrayStoreType(viewType)) {
|
||||
case ArrayStore_Intish:
|
||||
switch (viewType) {
|
||||
case ArrayBufferView::TYPE_INT8:
|
||||
case ArrayBufferView::TYPE_INT16:
|
||||
case ArrayBufferView::TYPE_INT32:
|
||||
case ArrayBufferView::TYPE_UINT8:
|
||||
case ArrayBufferView::TYPE_UINT16:
|
||||
case ArrayBufferView::TYPE_UINT32:
|
||||
if (!rhsType.isIntish())
|
||||
return f.failf(lhs, "%s is not a subtype of intish", rhsType.toChars());
|
||||
break;
|
||||
case ArrayStore_Doublish:
|
||||
if (!rhsType.isDoublish())
|
||||
return f.failf(lhs, "%s is not a subtype of doublish", rhsType.toChars());
|
||||
case ArrayBufferView::TYPE_FLOAT32:
|
||||
if (rhsType.isMaybeDouble())
|
||||
rhsDef = f.unary<MToFloat32>(rhsDef);
|
||||
else if (!rhsType.isFloatish())
|
||||
return f.failf(lhs, "%s is not a subtype of double? or floatish", rhsType.toChars());
|
||||
break;
|
||||
case ArrayBufferView::TYPE_FLOAT64:
|
||||
if (rhsType.isFloat())
|
||||
rhsDef = f.unary<MToDouble>(rhsDef);
|
||||
else if (!rhsType.isMaybeDouble())
|
||||
return f.failf(lhs, "%s is not a subtype of float or double?", rhsType.toChars());
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected view type");
|
||||
}
|
||||
|
||||
f.storeHeap(viewType, pointerDef, rhsDef, needsBoundsCheck);
|
||||
@ -3564,7 +3723,7 @@ CheckMathAbs(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argType.isDoublish()) {
|
||||
if (argType.isMaybeDouble()) {
|
||||
if (retType != RetType::Double)
|
||||
return f.failf(call, "return type is double, used as %s", retType.toType().toChars());
|
||||
*def = f.unary<MAbs>(argDef, MIRType_Double);
|
||||
@ -3572,7 +3731,15 @@ CheckMathAbs(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(call, "%s is not a subtype of signed or doublish", argType.toChars());
|
||||
if (argType.isMaybeFloat()) {
|
||||
if (retType != RetType::Float)
|
||||
return f.failf(call, "return type is float, used as %s", retType.toType().toChars());
|
||||
*def = f.unary<MAbs>(argDef, MIRType_Float32);
|
||||
*type = Type::Float;
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(call, "%s is not a subtype of signed, float? or double?", argType.toChars());
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -3588,7 +3755,7 @@ CheckMathSqrt(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition
|
||||
if (!CheckExpr(f, arg, &argDef, &argType))
|
||||
return false;
|
||||
|
||||
if (argType.isDoublish()) {
|
||||
if (argType.isMaybeDouble()) {
|
||||
if (retType != RetType::Double)
|
||||
return f.failf(call, "return type is double, used as %s", retType.toType().toChars());
|
||||
*def = f.unary<MSqrt>(argDef, MIRType_Double);
|
||||
@ -3596,7 +3763,15 @@ CheckMathSqrt(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(call, "%s is not a subtype of doublish", argType.toChars());
|
||||
if (argType.isMaybeFloat()) {
|
||||
if (retType != RetType::Float)
|
||||
return f.failf(call, "return type is float, used as %s", retType.toType().toChars());
|
||||
*def = f.unary<MSqrt>(argDef, MIRType_Float32);
|
||||
*type = Type::Float;
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(call, "%s is neither a subtype of double? nor float?", argType.toChars());
|
||||
}
|
||||
|
||||
typedef bool (*CheckArgType)(FunctionCompiler &f, ParseNode *argNode, Type type);
|
||||
@ -3672,7 +3847,7 @@ static bool
|
||||
CheckIsVarType(FunctionCompiler &f, ParseNode *argNode, Type type)
|
||||
{
|
||||
if (!type.isVarType())
|
||||
return f.failf(argNode, "%s is not a subtype of int or double", type.toChars());
|
||||
return f.failf(argNode, "%s is not a subtype of int, float or double", type.toChars());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3786,6 +3961,9 @@ CheckFFICall(FunctionCompiler &f, ParseNode *callNode, unsigned ffiIndex, RetTyp
|
||||
{
|
||||
PropertyName *calleeName = CallCallee(callNode)->name();
|
||||
|
||||
if (retType == RetType::Float)
|
||||
return f.fail(callNode, "FFI calls can't return float");
|
||||
|
||||
FunctionCompiler::Call call(f, retType);
|
||||
if (!CheckCallArgs(f, callNode, CheckIsExternType, &call))
|
||||
return false;
|
||||
@ -3801,11 +3979,88 @@ CheckFFICall(FunctionCompiler &f, ParseNode *callNode, unsigned ffiIndex, RetTyp
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CheckCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **def, Type *type);
|
||||
|
||||
static bool
|
||||
CheckIsDoublish(FunctionCompiler &f, ParseNode *argNode, Type type)
|
||||
CheckFRoundArg(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type, const char* error)
|
||||
{
|
||||
if (!type.isDoublish())
|
||||
return f.failf(argNode, "%s is not a subtype of doublish", type.toChars());
|
||||
ParseNode *arg = NULL;
|
||||
if (!CheckFloat32Coercion(f.m(), expr, &arg, error))
|
||||
return false;
|
||||
|
||||
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())
|
||||
*def = f.unary<MAsmJSUnsignedToFloat32>(inputDef);
|
||||
else if (inputType.isFloatish())
|
||||
*def = inputDef;
|
||||
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)
|
||||
{
|
||||
MDefinition *operand;
|
||||
Type operandType;
|
||||
if (!CheckFRoundArg(f, callNode, &operand, &operandType, "coercion to float should use fround"))
|
||||
return false;
|
||||
|
||||
switch (retType.which()) {
|
||||
case RetType::Double:
|
||||
*def = f.unary<MToDouble>(operand);
|
||||
*type = Type::Double;
|
||||
return true;
|
||||
case RetType::Signed:
|
||||
*def = f.unary<MTruncateToInt32>(operand);
|
||||
*type = Type::Signed;
|
||||
return true;
|
||||
case RetType::Float:
|
||||
*def = operand;
|
||||
*type = Type::Float;
|
||||
return true;
|
||||
case RetType::Void:
|
||||
// definition and return types should be ignored by the caller
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("return value of fround is ignored");
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckIsMaybeDouble(FunctionCompiler &f, ParseNode *argNode, Type type)
|
||||
{
|
||||
if (!type.isMaybeDouble())
|
||||
return f.failf(argNode, "%s is not a subtype of double?", type.toChars());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckIsMaybeFloat(FunctionCompiler &f, ParseNode *argNode, Type type)
|
||||
{
|
||||
if (!type.isMaybeFloat())
|
||||
return f.failf(argNode, "%s is not a subtype of float?", type.toChars());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3814,39 +4069,46 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltin
|
||||
RetType retType, MDefinition **def, Type *type)
|
||||
{
|
||||
unsigned arity = 0;
|
||||
AsmJSImmKind callee;
|
||||
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_sin: arity = 1; callee = AsmJSImm_SinD; break;
|
||||
case AsmJSMathBuiltin_cos: arity = 1; callee = AsmJSImm_CosD; break;
|
||||
case AsmJSMathBuiltin_tan: arity = 1; callee = AsmJSImm_TanD; break;
|
||||
case AsmJSMathBuiltin_asin: arity = 1; callee = AsmJSImm_ASinD; break;
|
||||
case AsmJSMathBuiltin_acos: arity = 1; callee = AsmJSImm_ACosD; break;
|
||||
case AsmJSMathBuiltin_atan: arity = 1; callee = AsmJSImm_ATanD; break;
|
||||
case AsmJSMathBuiltin_ceil: arity = 1; callee = AsmJSImm_CeilD; break;
|
||||
case AsmJSMathBuiltin_floor: arity = 1; callee = AsmJSImm_FloorD; break;
|
||||
case AsmJSMathBuiltin_exp: arity = 1; callee = AsmJSImm_ExpD; break;
|
||||
case AsmJSMathBuiltin_log: arity = 1; callee = AsmJSImm_LogD; break;
|
||||
case AsmJSMathBuiltin_pow: arity = 2; callee = AsmJSImm_PowD; break;
|
||||
case AsmJSMathBuiltin_atan2: arity = 2; callee = AsmJSImm_ATan2D; break;
|
||||
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_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;
|
||||
case AsmJSMathBuiltin_exp: arity = 1; doubleCallee = AsmJSImm_ExpD; floatCallee = AsmJSImm_ExpF; break;
|
||||
case AsmJSMathBuiltin_log: arity = 1; doubleCallee = AsmJSImm_LogD; floatCallee = AsmJSImm_LogF; break;
|
||||
case AsmJSMathBuiltin_pow: arity = 2; doubleCallee = AsmJSImm_PowD; floatCallee = AsmJSImm_Invalid; break;
|
||||
case AsmJSMathBuiltin_atan2: arity = 2; doubleCallee = AsmJSImm_ATan2D; floatCallee = AsmJSImm_Invalid; break;
|
||||
}
|
||||
|
||||
if (retType == RetType::Float && floatCallee == AsmJSImm_Invalid)
|
||||
return f.fail(callNode, "math builtin cannot be used as float");
|
||||
if (retType != RetType::Double && retType != RetType::Float)
|
||||
return f.failf(callNode, "return type of math function is double or float, used as %s", retType.toType().toChars());
|
||||
|
||||
FunctionCompiler::Call call(f, retType);
|
||||
if (!CheckCallArgs(f, callNode, CheckIsDoublish, &call))
|
||||
if (retType == RetType::Float && !CheckCallArgs(f, callNode, CheckIsMaybeFloat, &call))
|
||||
return false;
|
||||
if (retType == RetType::Double && !CheckCallArgs(f, callNode, CheckIsMaybeDouble, &call))
|
||||
return false;
|
||||
|
||||
if (call.sig().args().length() != arity)
|
||||
return f.failf(callNode, "call passed %u arguments, expected %u", call.sig().args().length(), arity);
|
||||
|
||||
if (!f.builtinCall(callee, call, MIRType_Double, def))
|
||||
if (retType == RetType::Float && !f.builtinCall(floatCallee, call, retType.toMIRType(), def))
|
||||
return false;
|
||||
if (retType == RetType::Double && !f.builtinCall(doubleCallee, call, retType.toMIRType(), def))
|
||||
return false;
|
||||
|
||||
if (retType != RetType::Double)
|
||||
return f.failf(callNode, "return type is double, used as %s", retType.toType().toChars());
|
||||
|
||||
*type = Type::Double;
|
||||
*type = retType.toType();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3898,14 +4160,14 @@ CheckPos(FunctionCompiler &f, ParseNode *pos, MDefinition **def, Type *type)
|
||||
if (!CheckExpr(f, operand, &operandDef, &operandType))
|
||||
return false;
|
||||
|
||||
if (operandType.isSigned())
|
||||
if (operandType.isMaybeFloat() || operandType.isSigned())
|
||||
*def = f.unary<MToDouble>(operandDef);
|
||||
else if (operandType.isUnsigned())
|
||||
*def = f.unary<MAsmJSUnsignedToDouble>(operandDef);
|
||||
else if (operandType.isDoublish())
|
||||
else if (operandType.isMaybeDouble())
|
||||
*def = operandDef;
|
||||
else
|
||||
return f.failf(operand, "%s is not a subtype of signed, unsigned or doublish", operandType.toChars());
|
||||
return f.failf(operand, "%s is not a subtype of signed, unsigned, float or double?", operandType.toChars());
|
||||
|
||||
*type = Type::Double;
|
||||
return true;
|
||||
@ -3947,13 +4209,19 @@ CheckNeg(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (operandType.isDoublish()) {
|
||||
if (operandType.isMaybeDouble()) {
|
||||
*def = f.unary<MAsmJSNeg>(operandDef, MIRType_Double);
|
||||
*type = Type::Double;
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(operand, "%s is not a subtype of int or doublish", operandType.toChars());
|
||||
if (operandType.isMaybeFloat()) {
|
||||
*def = f.unary<MAsmJSNeg>(operandDef, MIRType_Float32);
|
||||
*type = Type::Floatish;
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(operand, "%s is not a subtype of int, float? or double?", operandType.toChars());
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -3967,14 +4235,14 @@ CheckCoerceToInt(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *
|
||||
if (!CheckExpr(f, operand, &operandDef, &operandType))
|
||||
return false;
|
||||
|
||||
if (operandType.isDoublish()) {
|
||||
if (operandType.isMaybeDouble() || operandType.isMaybeFloat()) {
|
||||
*def = f.unary<MTruncateToInt32>(operandDef);
|
||||
*type = Type::Signed;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!operandType.isIntish())
|
||||
return f.failf(operand, "%s is not a subtype of doublish or intish", operandType.toChars());
|
||||
return f.failf(operand, "%s is not a subtype of double?, float? or intish", operandType.toChars());
|
||||
|
||||
*def = operandDef;
|
||||
*type = Type::Signed;
|
||||
@ -4071,6 +4339,8 @@ CheckConditional(FunctionCompiler &f, ParseNode *ternary, MDefinition **def, Typ
|
||||
*type = Type::Int;
|
||||
} else if (thenType.isDouble() && elseType.isDouble()) {
|
||||
*type = Type::Double;
|
||||
} else if (thenType.isFloat() && elseType.isFloat()) {
|
||||
*type = Type::Float;
|
||||
} else {
|
||||
return f.failf(ternary, "then/else branches of conditional must both produce int or double, "
|
||||
"current types are %s and %s", thenType.toChars(), elseType.toChars());
|
||||
@ -4130,14 +4400,19 @@ CheckMultiply(FunctionCompiler &f, ParseNode *star, MDefinition **def, Type *typ
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!lhsType.isDoublish())
|
||||
return f.failf(lhs, "%s is not a subtype of doublish", lhsType.toChars());
|
||||
if (!rhsType.isDoublish())
|
||||
return f.failf(rhs, "%s is not a subtype of doublish", rhsType.toChars());
|
||||
if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
|
||||
*def = f.mul(lhsDef, rhsDef, MIRType_Double, MMul::Normal);
|
||||
*type = Type::Double;
|
||||
return true;
|
||||
}
|
||||
|
||||
*def = f.mul(lhsDef, rhsDef, MIRType_Double, MMul::Normal);
|
||||
*type = Type::Double;
|
||||
return true;
|
||||
if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
|
||||
*def = f.mul(lhsDef, rhsDef, MIRType_Float32, MMul::Normal);
|
||||
*type = Type::Floatish;
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.fail(star, "multiply operands must be both int, both double? or both float?");
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -4185,13 +4460,18 @@ CheckAddOrSub(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *typ
|
||||
? f.binary<MAdd>(lhsDef, rhsDef, MIRType_Int32)
|
||||
: f.binary<MSub>(lhsDef, rhsDef, MIRType_Int32);
|
||||
*type = Type::Intish;
|
||||
} else if (lhsType.isDoublish() && rhsType.isDoublish()) {
|
||||
} else if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
|
||||
*def = expr->isKind(PNK_ADD)
|
||||
? f.binary<MAdd>(lhsDef, rhsDef, MIRType_Double)
|
||||
: f.binary<MSub>(lhsDef, rhsDef, MIRType_Double);
|
||||
*type = Type::Double;
|
||||
} else if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
|
||||
*def = expr->isKind(PNK_ADD)
|
||||
? f.binary<MAdd>(lhsDef, rhsDef, MIRType_Float32)
|
||||
: f.binary<MSub>(lhsDef, rhsDef, MIRType_Float32);
|
||||
*type = Type::Floatish;
|
||||
} else {
|
||||
return f.failf(expr, "operands to +/- must both be int or doublish, got %s and %s",
|
||||
return f.failf(expr, "operands to + or - must both be int, float? or double?, got %s and %s",
|
||||
lhsType.toChars(), rhsType.toChars());
|
||||
}
|
||||
|
||||
@ -4214,7 +4494,7 @@ CheckDivOrMod(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *typ
|
||||
if (!CheckExpr(f, rhs, &rhsDef, &rhsType))
|
||||
return false;
|
||||
|
||||
if (lhsType.isDoublish() && rhsType.isDoublish()) {
|
||||
if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
|
||||
*def = expr->isKind(PNK_DIV)
|
||||
? f.div(lhsDef, rhsDef, MIRType_Double, /* unsignd = */ false)
|
||||
: f.mod(lhsDef, rhsDef, MIRType_Double, /* unsignd = */ false);
|
||||
@ -4222,6 +4502,15 @@ CheckDivOrMod(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *typ
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
|
||||
if (expr->isKind(PNK_DIV))
|
||||
*def = f.div(lhsDef, rhsDef, MIRType_Float32, /* unsignd = */ false);
|
||||
else
|
||||
return f.fail(expr, "modulo cannot receive float arguments");
|
||||
*type = Type::Floatish;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lhsType.isSigned() && rhsType.isSigned()) {
|
||||
if (expr->isKind(PNK_DIV))
|
||||
*def = f.div(lhsDef, rhsDef, MIRType_Int32, /* unsignd = */ false);
|
||||
@ -4240,7 +4529,7 @@ CheckDivOrMod(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *typ
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(expr, "arguments to / or %% must both be double, signed, or unsigned; "
|
||||
return f.failf(expr, "arguments to / or %% must both be double?, float?, signed, or unsigned; "
|
||||
"%s and %s are given", lhsType.toChars(), rhsType.toChars());
|
||||
}
|
||||
|
||||
@ -4274,7 +4563,13 @@ CheckComparison(FunctionCompiler &f, ParseNode *comp, MDefinition **def, Type *t
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(comp, "arguments to a comparison must both be signed, unsigned or doubles; "
|
||||
if (lhsType.isFloat() && rhsType.isFloat()) {
|
||||
*def = f.compare(lhsDef, rhsDef, comp->getOp(), MCompare::Compare_Float32);
|
||||
*type = Type::Int;
|
||||
return true;
|
||||
}
|
||||
|
||||
return f.failf(comp, "arguments to a comparison must both be signed, unsigned, floats or doubles; "
|
||||
"%s and %s are given", lhsType.toChars(), rhsType.toChars());
|
||||
}
|
||||
|
||||
@ -4345,6 +4640,18 @@ CheckBitwise(FunctionCompiler &f, ParseNode *bitwise, MDefinition **def, Type *t
|
||||
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);
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type)
|
||||
{
|
||||
@ -4358,7 +4665,7 @@ CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type)
|
||||
|
||||
switch (expr->getKind()) {
|
||||
case PNK_NAME: return CheckVarRef(f, expr, def, type);
|
||||
case PNK_ELEM: return CheckArrayLoad(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);
|
||||
@ -4367,10 +4674,7 @@ CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type)
|
||||
case PNK_COMMA: return CheckComma(f, expr, def, type);
|
||||
case PNK_CONDITIONAL: return CheckConditional(f, expr, def, type);
|
||||
case PNK_STAR: return CheckMultiply(f, expr, def, type);
|
||||
|
||||
case PNK_CALL: return f.fail(expr, "all function calls must either be ignored (via "
|
||||
"f(); or comma-expression), coerced to signed "
|
||||
"(via f()|0) or coerced to double (via +f())");
|
||||
case PNK_CALL: return CheckUncoercedCall(f, expr, def, type);
|
||||
|
||||
case PNK_ADD:
|
||||
case PNK_SUB: return CheckAddOrSub(f, expr, def, type);
|
||||
@ -4792,6 +5096,8 @@ CheckReturn(FunctionCompiler &f, ParseNode *returnStmt)
|
||||
retType = RetType::Signed;
|
||||
else if (type.isDouble())
|
||||
retType = RetType::Double;
|
||||
else if (type.isFloat())
|
||||
retType = RetType::Float;
|
||||
else if (type.isVoid())
|
||||
retType = RetType::Void;
|
||||
else
|
||||
@ -5605,7 +5911,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
||||
masm.load32(src, scratch);
|
||||
masm.storePtr(scratch, Address(StackPointer, iter->offsetFromArgBase()));
|
||||
} else {
|
||||
JS_ASSERT(iter.mirType() == MIRType_Double);
|
||||
JS_ASSERT(iter.mirType() == MIRType_Double || iter.mirType() == MIRType_Float32);
|
||||
masm.loadDouble(src, ScratchFloatReg);
|
||||
masm.storeDouble(ScratchFloatReg, Address(StackPointer, iter->offsetFromArgBase()));
|
||||
}
|
||||
@ -5629,6 +5935,9 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
||||
case RetType::Signed:
|
||||
masm.storeValue(JSVAL_TYPE_INT32, ReturnReg, Address(argv, 0));
|
||||
break;
|
||||
case RetType::Float:
|
||||
masm.convertFloatToDouble(ReturnFloatReg, ReturnFloatReg);
|
||||
// Fall through as ReturnFloatReg now contains a Double
|
||||
case RetType::Double:
|
||||
masm.canonicalizeDouble(ReturnFloatReg);
|
||||
masm.storeDouble(ReturnFloatReg, Address(argv, 0));
|
||||
@ -5873,6 +6182,9 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.loadDouble(argv, ReturnFloatReg);
|
||||
break;
|
||||
case RetType::Float:
|
||||
MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI");
|
||||
break;
|
||||
}
|
||||
|
||||
// Note: the caller is IonMonkey code which means there are no non-volatile
|
||||
@ -5924,6 +6236,9 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.loadDouble(argv, ReturnFloatReg);
|
||||
break;
|
||||
case RetType::Float:
|
||||
MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI");
|
||||
break;
|
||||
}
|
||||
|
||||
masm.freeStack(reserveSize + sizeof(int32_t));
|
||||
@ -6128,6 +6443,9 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
||||
case RetType::Double:
|
||||
masm.convertValueToDouble(JSReturnOperand, ReturnFloatReg, &oolConvert);
|
||||
break;
|
||||
case RetType::Float:
|
||||
MOZ_ASSUME_UNREACHABLE("Float shouldn't be returned from a FFI");
|
||||
break;
|
||||
}
|
||||
|
||||
masm.bind(&done);
|
||||
|
@ -70,10 +70,17 @@ ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Gl
|
||||
switch (global.varInitKind()) {
|
||||
case AsmJSModule::Global::InitConstant: {
|
||||
const Value &v = global.varInitConstant();
|
||||
if (v.isInt32())
|
||||
switch (global.varInitCoercion()) {
|
||||
case AsmJS_ToInt32:
|
||||
*(int32_t *)datum = v.toInt32();
|
||||
else
|
||||
break;
|
||||
case AsmJS_ToNumber:
|
||||
*(double *)datum = v.toDouble();
|
||||
break;
|
||||
case AsmJS_FRound:
|
||||
*(float *)datum = static_cast<float>(v.toDouble());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AsmJSModule::Global::InitImport: {
|
||||
@ -82,7 +89,7 @@ ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Gl
|
||||
if (!GetDataProperty(cx, importVal, field, &v))
|
||||
return false;
|
||||
|
||||
switch (global.varImportCoercion()) {
|
||||
switch (global.varInitCoercion()) {
|
||||
case AsmJS_ToInt32:
|
||||
if (!ToInt32(cx, v, (int32_t *)datum))
|
||||
return false;
|
||||
@ -91,6 +98,10 @@ ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Gl
|
||||
if (!ToNumber(cx, v, (double *)datum))
|
||||
return false;
|
||||
break;
|
||||
case AsmJS_FRound:
|
||||
if (!RoundFloat32(cx, v, (float *)datum))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -157,6 +168,7 @@ ValidateMathBuiltin(JSContext *cx, AsmJSModule::Global &global, HandleValue glob
|
||||
case AsmJSMathBuiltin_abs: native = js_math_abs; break;
|
||||
case AsmJSMathBuiltin_atan2: native = math_atan2; break;
|
||||
case AsmJSMathBuiltin_imul: native = math_imul; break;
|
||||
case AsmJSMathBuiltin_fround: native = math_fround; break;
|
||||
}
|
||||
|
||||
if (!IsNativeFunction(v, native))
|
||||
@ -364,6 +376,10 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!ToNumber(cx, v, (double*)&coercedArgs[i]))
|
||||
return false;
|
||||
break;
|
||||
case AsmJS_FRound:
|
||||
if (!RoundFloat32(cx, v, (float *)&coercedArgs[i]))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,28 +235,50 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
|
||||
return FuncCast(NumberMod);
|
||||
case AsmJSImm_SinD:
|
||||
return FuncCast<double (double)>(sin);
|
||||
case AsmJSImm_SinF:
|
||||
return FuncCast<float (float)>(sinf);
|
||||
case AsmJSImm_CosD:
|
||||
return FuncCast<double (double)>(cos);
|
||||
case AsmJSImm_CosF:
|
||||
return FuncCast<float (float)>(cosf);
|
||||
case AsmJSImm_TanD:
|
||||
return FuncCast<double (double)>(tan);
|
||||
case AsmJSImm_TanF:
|
||||
return FuncCast<float (float)>(tanf);
|
||||
case AsmJSImm_ASinD:
|
||||
return FuncCast<double (double)>(asin);
|
||||
case AsmJSImm_ASinF:
|
||||
return FuncCast<float (float)>(asinf);
|
||||
case AsmJSImm_ACosD:
|
||||
return FuncCast<double (double)>(acos);
|
||||
case AsmJSImm_ACosF:
|
||||
return FuncCast<float (float)>(acosf);
|
||||
case AsmJSImm_ATanD:
|
||||
return FuncCast<double (double)>(atan);
|
||||
case AsmJSImm_ATanF:
|
||||
return FuncCast<float (float)>(atanf);
|
||||
case AsmJSImm_CeilD:
|
||||
return FuncCast<double (double)>(ceil);
|
||||
case AsmJSImm_CeilF:
|
||||
return FuncCast<float (float)>(ceilf);
|
||||
case AsmJSImm_FloorD:
|
||||
return FuncCast<double (double)>(floor);
|
||||
case AsmJSImm_FloorF:
|
||||
return FuncCast<float (float)>(floorf);
|
||||
case AsmJSImm_ExpD:
|
||||
return FuncCast<double (double)>(exp);
|
||||
case AsmJSImm_ExpF:
|
||||
return FuncCast<float (float)>(expf);
|
||||
case AsmJSImm_LogD:
|
||||
return FuncCast<double (double)>(log);
|
||||
case AsmJSImm_LogF:
|
||||
return FuncCast<float (float)>(logf);
|
||||
case AsmJSImm_PowD:
|
||||
return FuncCast(ecmaPow);
|
||||
case AsmJSImm_ATan2D:
|
||||
return FuncCast(ecmaAtan2);
|
||||
case AsmJSImm_Invalid:
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Bad AsmJSImmKind");
|
||||
|
@ -29,7 +29,8 @@ namespace js {
|
||||
enum AsmJSCoercion
|
||||
{
|
||||
AsmJS_ToInt32,
|
||||
AsmJS_ToNumber
|
||||
AsmJS_ToNumber,
|
||||
AsmJS_FRound
|
||||
};
|
||||
|
||||
// The asm.js spec recognizes this set of builtin Math functions.
|
||||
@ -39,7 +40,8 @@ enum AsmJSMathBuiltin
|
||||
AsmJSMathBuiltin_asin, AsmJSMathBuiltin_acos, AsmJSMathBuiltin_atan,
|
||||
AsmJSMathBuiltin_ceil, AsmJSMathBuiltin_floor, AsmJSMathBuiltin_exp,
|
||||
AsmJSMathBuiltin_log, AsmJSMathBuiltin_pow, AsmJSMathBuiltin_sqrt,
|
||||
AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul
|
||||
AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul,
|
||||
AsmJSMathBuiltin_fround
|
||||
};
|
||||
|
||||
// Static-link data is used to patch a module either after it has been
|
||||
@ -105,9 +107,9 @@ class AsmJSModule
|
||||
struct {
|
||||
uint32_t index_;
|
||||
VarInitKind initKind_;
|
||||
AsmJSCoercion coercion_;
|
||||
union {
|
||||
Value constant_; // will only contain int32/double
|
||||
AsmJSCoercion coercion_;
|
||||
} init;
|
||||
} var;
|
||||
uint32_t ffiIndex_;
|
||||
@ -151,10 +153,9 @@ class AsmJSModule
|
||||
JS_ASSERT(pod.u.var.initKind_ == InitConstant);
|
||||
return pod.u.var.init.constant_;
|
||||
}
|
||||
AsmJSCoercion varImportCoercion() const {
|
||||
AsmJSCoercion varInitCoercion() const {
|
||||
JS_ASSERT(pod.which_ == Variable);
|
||||
JS_ASSERT(pod.u.var.initKind_ == InitImport);
|
||||
return pod.u.var.init.coercion_;
|
||||
return pod.u.var.coercion_;
|
||||
}
|
||||
PropertyName *varImportField() const {
|
||||
JS_ASSERT(pod.which_ == Variable);
|
||||
@ -455,13 +456,14 @@ class AsmJSModule
|
||||
return charsBegin_ + pod.charsLength_;
|
||||
}
|
||||
|
||||
bool addGlobalVarInitConstant(const Value &v, uint32_t *globalIndex) {
|
||||
bool addGlobalVarInitConstant(const Value &v, AsmJSCoercion coercion, uint32_t *globalIndex) {
|
||||
JS_ASSERT(pod.funcPtrTableAndExitBytes_ == 0);
|
||||
if (pod.numGlobalVars_ == UINT32_MAX)
|
||||
return false;
|
||||
Global g(Global::Variable, nullptr);
|
||||
g.pod.u.var.initKind_ = Global::InitConstant;
|
||||
g.pod.u.var.init.constant_ = v;
|
||||
g.pod.u.var.coercion_ = coercion;
|
||||
g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++;
|
||||
return globals_.append(g);
|
||||
}
|
||||
@ -469,7 +471,7 @@ class AsmJSModule
|
||||
JS_ASSERT(pod.funcPtrTableAndExitBytes_ == 0);
|
||||
Global g(Global::Variable, name);
|
||||
g.pod.u.var.initKind_ = Global::InitImport;
|
||||
g.pod.u.var.init.coercion_ = coercion;
|
||||
g.pod.u.var.coercion_ = coercion;
|
||||
g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++;
|
||||
return globals_.append(g);
|
||||
}
|
||||
|
@ -3300,7 +3300,7 @@ LIRGenerator::visitAsmJSParameter(MAsmJSParameter *ins)
|
||||
if (abi.argInRegister())
|
||||
return defineFixed(new(alloc()) LAsmJSParameter, ins, LAllocation(abi.reg()));
|
||||
|
||||
JS_ASSERT(ins->type() == MIRType_Int32 || ins->type() == MIRType_Double);
|
||||
JS_ASSERT(IsNumberType(ins->type()));
|
||||
LAllocation::Kind argKind = ins->type() == MIRType_Int32
|
||||
? LAllocation::INT_ARGUMENT
|
||||
: LAllocation::DOUBLE_ARGUMENT;
|
||||
@ -3312,7 +3312,7 @@ LIRGenerator::visitAsmJSReturn(MAsmJSReturn *ins)
|
||||
{
|
||||
MDefinition *rval = ins->getOperand(0);
|
||||
LAsmJSReturn *lir = new(alloc()) LAsmJSReturn;
|
||||
if (rval->type() == MIRType_Double)
|
||||
if (IsFloatingPointType(rval->type()))
|
||||
lir->setOperand(0, useFixed(rval, ReturnFloatReg));
|
||||
else if (rval->type() == MIRType_Int32)
|
||||
lir->setOperand(0, useFixed(rval, ReturnReg));
|
||||
@ -3330,7 +3330,7 @@ LIRGenerator::visitAsmJSVoidReturn(MAsmJSVoidReturn *ins)
|
||||
bool
|
||||
LIRGenerator::visitAsmJSPassStackArg(MAsmJSPassStackArg *ins)
|
||||
{
|
||||
if (ins->arg()->type() == MIRType_Double) {
|
||||
if (IsFloatingPointType(ins->arg()->type())) {
|
||||
JS_ASSERT(!ins->arg()->isEmittedAtUses());
|
||||
return add(new(alloc()) LAsmJSPassStackArg(useRegisterAtStart(ins->arg())), ins);
|
||||
}
|
||||
|
@ -9241,7 +9241,9 @@ class MAsmJSLoadHeap : public MUnaryInstruction, public MAsmJSHeapAccess
|
||||
: MUnaryInstruction(ptr), MAsmJSHeapAccess(vt, false)
|
||||
{
|
||||
setMovable();
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32 || vt == ArrayBufferView::TYPE_FLOAT64)
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32)
|
||||
setResultType(MIRType_Float32);
|
||||
else if (vt == ArrayBufferView::TYPE_FLOAT64)
|
||||
setResultType(MIRType_Double);
|
||||
else
|
||||
setResultType(MIRType_Int32);
|
||||
@ -9291,7 +9293,7 @@ class MAsmJSLoadGlobalVar : public MNullaryInstruction
|
||||
MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant)
|
||||
: globalDataOffset_(globalDataOffset), isConstant_(isConstant)
|
||||
{
|
||||
JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double);
|
||||
JS_ASSERT(IsNumberType(type));
|
||||
setResultType(type);
|
||||
setMovable();
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ ABIArgGenerator::next(MIRType type)
|
||||
current_ = ABIArg(Register::FromCode(intRegIndex_));
|
||||
intRegIndex_++;
|
||||
break;
|
||||
case MIRType_Float32:
|
||||
case MIRType_Double:
|
||||
if (floatRegIndex_ == NumFloatArgRegs) {
|
||||
static const int align = sizeof(double) - 1;
|
||||
|
@ -1969,12 +1969,10 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
|
||||
JS_ASSERT(ptrImm >= 0);
|
||||
if (isFloat) {
|
||||
VFPRegister vd(ToFloatRegister(ins->output()));
|
||||
if (size == 32) {
|
||||
if (size == 32)
|
||||
masm.ma_vldr(Operand(HeapReg, ptrImm), vd.singleOverlay(), Assembler::Always);
|
||||
masm.as_vcvt(vd, vd.singleOverlay(), false, Assembler::Always);
|
||||
} else {
|
||||
else
|
||||
masm.ma_vldr(Operand(HeapReg, ptrImm), vd, Assembler::Always);
|
||||
}
|
||||
} else {
|
||||
masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, Imm32(ptrImm),
|
||||
ToRegister(ins->output()), Offset, Assembler::Always);
|
||||
@ -1987,12 +1985,10 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
|
||||
if (mir->skipBoundsCheck()) {
|
||||
if (isFloat) {
|
||||
VFPRegister vd(ToFloatRegister(ins->output()));
|
||||
if (size == 32) {
|
||||
if (size == 32)
|
||||
masm.ma_vldr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Always);
|
||||
masm.as_vcvt(vd, vd.singleOverlay(), false, Assembler::Always);
|
||||
} else {
|
||||
else
|
||||
masm.ma_vldr(vd, HeapReg, ptrReg, 0, Assembler::Always);
|
||||
}
|
||||
} else {
|
||||
masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, ptrReg,
|
||||
ToRegister(ins->output()), Offset, Assembler::Always);
|
||||
@ -2003,12 +1999,12 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
|
||||
BufferOffset bo = masm.ma_BoundsCheck(ptrReg);
|
||||
if (isFloat) {
|
||||
FloatRegister dst = ToFloatRegister(ins->output());
|
||||
masm.ma_vmov(NANReg, dst, Assembler::AboveOrEqual);
|
||||
VFPRegister vd(dst);
|
||||
if (size == 32) {
|
||||
masm.convertDoubleToFloat(NANReg, dst, Assembler::AboveOrEqual);
|
||||
masm.ma_vldr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Below);
|
||||
masm.as_vcvt(vd, vd.singleOverlay(), false, Assembler::Below);
|
||||
} else {
|
||||
masm.ma_vmov(NANReg, dst, Assembler::AboveOrEqual);
|
||||
masm.ma_vldr(vd, HeapReg, ptrReg, 0, Assembler::Below);
|
||||
}
|
||||
} else {
|
||||
@ -2044,12 +2040,10 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
|
||||
JS_ASSERT(ptrImm >= 0);
|
||||
if (isFloat) {
|
||||
VFPRegister vd(ToFloatRegister(ins->value()));
|
||||
if (size == 32) {
|
||||
masm.as_vcvt(VFPRegister(ScratchFloatReg).singleOverlay(), vd, false, Assembler::Always);
|
||||
masm.ma_vstr(VFPRegister(ScratchFloatReg).singleOverlay(), Operand(HeapReg, ptrImm), Assembler::Always);
|
||||
} else {
|
||||
if (size == 32)
|
||||
masm.ma_vstr(vd.singleOverlay(), Operand(HeapReg, ptrImm), Assembler::Always);
|
||||
else
|
||||
masm.ma_vstr(vd, Operand(HeapReg, ptrImm), Assembler::Always);
|
||||
}
|
||||
} else {
|
||||
masm.ma_dataTransferN(IsStore, size, isSigned, HeapReg, Imm32(ptrImm),
|
||||
ToRegister(ins->value()), Offset, Assembler::Always);
|
||||
@ -2064,7 +2058,7 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
|
||||
if (isFloat) {
|
||||
VFPRegister vd(ToFloatRegister(ins->value()));
|
||||
if (size == 32)
|
||||
masm.storeFloat(vd, HeapReg, ptrReg, Assembler::Always);
|
||||
masm.ma_vstr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Always);
|
||||
else
|
||||
masm.ma_vstr(vd, HeapReg, ptrReg, 0, Assembler::Always);
|
||||
} else {
|
||||
@ -2078,7 +2072,7 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
|
||||
if (isFloat) {
|
||||
VFPRegister vd(ToFloatRegister(ins->value()));
|
||||
if (size == 32)
|
||||
masm.storeFloat(vd, HeapReg, ptrReg, Assembler::Below);
|
||||
masm.ma_vstr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Below);
|
||||
else
|
||||
masm.ma_vstr(vd, HeapReg, ptrReg, 0, Assembler::Below);
|
||||
} else {
|
||||
@ -2229,10 +2223,14 @@ CodeGeneratorARM::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins)
|
||||
{
|
||||
const MAsmJSLoadGlobalVar *mir = ins->mir();
|
||||
unsigned addr = mir->globalDataOffset();
|
||||
if (mir->type() == MIRType_Int32)
|
||||
if (mir->type() == MIRType_Int32) {
|
||||
masm.ma_dtr(IsLoad, GlobalReg, Imm32(addr), ToRegister(ins->output()));
|
||||
else
|
||||
} else if (mir->type() == MIRType_Float32) {
|
||||
VFPRegister vd(ToFloatRegister(ins->output()));
|
||||
masm.ma_vldr(Operand(GlobalReg, addr), vd.singleOverlay());
|
||||
} else {
|
||||
masm.ma_vldr(Operand(GlobalReg, addr), ToFloatRegister(ins->output()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2242,12 +2240,16 @@ CodeGeneratorARM::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins)
|
||||
const MAsmJSStoreGlobalVar *mir = ins->mir();
|
||||
|
||||
MIRType type = mir->value()->type();
|
||||
JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double);
|
||||
JS_ASSERT(IsNumberType(type));
|
||||
unsigned addr = mir->globalDataOffset();
|
||||
if (mir->value()->type() == MIRType_Int32)
|
||||
if (mir->value()->type() == MIRType_Int32) {
|
||||
masm.ma_dtr(IsStore, GlobalReg, Imm32(addr), ToRegister(ins->value()));
|
||||
else
|
||||
} else if (mir->value()->type() == MIRType_Float32) {
|
||||
VFPRegister vd(ToFloatRegister(ins->value()));
|
||||
masm.ma_vstr(vd.singleOverlay(), Operand(GlobalReg, addr));
|
||||
} else {
|
||||
masm.ma_vstr(ToFloatRegister(ins->value()), Operand(GlobalReg, addr));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -176,10 +176,19 @@ class CodeGeneratorARM : public CodeGeneratorShared
|
||||
bool generateInvalidateEpilogue();
|
||||
protected:
|
||||
void postAsmJSCall(LAsmJSCall *lir) {
|
||||
#if !defined(JS_CPU_ARM_HARDFP)
|
||||
#ifndef JS_CPU_ARM_HARDFP
|
||||
if (lir->mir()->callee().which() == MAsmJSCall::Callee::Builtin) {
|
||||
if (lir->mir()->type() == MIRType_Double)
|
||||
switch (lir->mir()->type()) {
|
||||
case MIRType_Double:
|
||||
masm.ma_vxfer(r0, r1, d0);
|
||||
break;
|
||||
case MIRType_Float32:
|
||||
masm.as_vxfer(r0, InvalidReg, VFPRegister(d0).singleOverlay(),
|
||||
Assembler::CoreToFloat);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -412,6 +412,9 @@ LIRGeneratorARM::visitAsmJSNeg(MAsmJSNeg *ins)
|
||||
if (ins->type() == MIRType_Int32)
|
||||
return define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
|
||||
|
||||
if(ins->type() == MIRType_Float32)
|
||||
return define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
|
||||
|
||||
JS_ASSERT(ins->type() == MIRType_Double);
|
||||
return define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
|
||||
}
|
||||
|
@ -74,9 +74,10 @@ MacroAssemblerARM::convertUInt32ToFloat32(const Register &src, const FloatRegist
|
||||
as_vcvt(VFPRegister(dest).singleOverlay(), dest.uintOverlay());
|
||||
}
|
||||
|
||||
void MacroAssemblerARM::convertDoubleToFloat(const FloatRegister &src, const FloatRegister &dest)
|
||||
void MacroAssemblerARM::convertDoubleToFloat(const FloatRegister &src, const FloatRegister &dest,
|
||||
Condition c)
|
||||
{
|
||||
as_vcvt(VFPRegister(dest).singleOverlay(), VFPRegister(src));
|
||||
as_vcvt(VFPRegister(dest).singleOverlay(), VFPRegister(src), false, c);
|
||||
}
|
||||
|
||||
// there are two options for implementing emitTruncateDouble.
|
||||
|
@ -50,7 +50,8 @@ class MacroAssemblerARM : public Assembler
|
||||
void convertInt32ToDouble(const Address &src, FloatRegister dest);
|
||||
void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest);
|
||||
void convertUInt32ToDouble(const Register &src, const FloatRegister &dest);
|
||||
void convertDoubleToFloat(const FloatRegister &src, const FloatRegister &dest);
|
||||
void convertDoubleToFloat(const FloatRegister &src, const FloatRegister &dest,
|
||||
Condition c = Always);
|
||||
void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail);
|
||||
void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail,
|
||||
bool negativeZeroCheck = true);
|
||||
@ -1494,11 +1495,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
return as_cmp(bounded, Imm8(0));
|
||||
}
|
||||
|
||||
void storeFloat(VFPRegister src, Register base, Register index, Condition cond) {
|
||||
as_vcvt(VFPRegister(ScratchFloatReg).singleOverlay(), src, false, cond);
|
||||
ma_vstr(VFPRegister(ScratchFloatReg).singleOverlay(), base, index, 0, cond);
|
||||
|
||||
}
|
||||
void moveFloat(FloatRegister src, FloatRegister dest) {
|
||||
as_vmov(VFPRegister(src).singleOverlay(), VFPRegister(dest).singleOverlay());
|
||||
}
|
||||
|
@ -691,17 +691,28 @@ enum AsmJSImmKind
|
||||
#endif
|
||||
AsmJSImm_ModD,
|
||||
AsmJSImm_SinD,
|
||||
AsmJSImm_SinF,
|
||||
AsmJSImm_CosD,
|
||||
AsmJSImm_CosF,
|
||||
AsmJSImm_TanD,
|
||||
AsmJSImm_TanF,
|
||||
AsmJSImm_ASinD,
|
||||
AsmJSImm_ASinF,
|
||||
AsmJSImm_ACosD,
|
||||
AsmJSImm_ACosF,
|
||||
AsmJSImm_ATanD,
|
||||
AsmJSImm_ATanF,
|
||||
AsmJSImm_CeilD,
|
||||
AsmJSImm_CeilF,
|
||||
AsmJSImm_FloorD,
|
||||
AsmJSImm_FloorF,
|
||||
AsmJSImm_ExpD,
|
||||
AsmJSImm_ExpF,
|
||||
AsmJSImm_LogD,
|
||||
AsmJSImm_LogF,
|
||||
AsmJSImm_PowD,
|
||||
AsmJSImm_ATan2D
|
||||
AsmJSImm_ATan2D,
|
||||
AsmJSImm_Invalid
|
||||
};
|
||||
|
||||
// Pointer to be embedded as an immediate in asm.js code.
|
||||
|
@ -227,6 +227,9 @@ LIRGeneratorX86Shared::visitAsmJSNeg(MAsmJSNeg *ins)
|
||||
if (ins->type() == MIRType_Int32)
|
||||
return defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins, 0);
|
||||
|
||||
if (ins->type() == MIRType_Float32)
|
||||
return defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins, 0);
|
||||
|
||||
JS_ASSERT(ins->type() == MIRType_Double);
|
||||
return defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins, 0);
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ ABIArgGenerator::next(MIRType type)
|
||||
case MIRType_Pointer:
|
||||
current_ = ABIArg(IntArgRegs[regIndex_++]);
|
||||
break;
|
||||
case MIRType_Float32:
|
||||
case MIRType_Double:
|
||||
current_ = ABIArg(FloatArgRegs[regIndex_++]);
|
||||
break;
|
||||
@ -58,6 +59,7 @@ ABIArgGenerator::next(MIRType type)
|
||||
current_ = ABIArg(IntArgRegs[intRegIndex_++]);
|
||||
break;
|
||||
case MIRType_Double:
|
||||
case MIRType_Float32:
|
||||
if (floatRegIndex_ == NumFloatArgRegs) {
|
||||
current_ = ABIArg(stackOffset_);
|
||||
stackOffset_ += sizeof(uint64_t);
|
||||
|
@ -409,15 +409,6 @@ CodeGeneratorX64::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
|
||||
srcAddr = Operand(HeapReg, ToRegister(ptr), TimesOne);
|
||||
}
|
||||
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32) {
|
||||
FloatRegister dest = ToFloatRegister(ins->output());
|
||||
uint32_t before = masm.size();
|
||||
masm.loadFloat(srcAddr, dest);
|
||||
uint32_t after = masm.size();
|
||||
masm.cvtss2sd(dest, dest);
|
||||
return skipNote || gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, ToAnyRegister(ins->output())));
|
||||
}
|
||||
|
||||
uint32_t before = masm.size();
|
||||
switch (vt) {
|
||||
case ArrayBufferView::TYPE_INT8: masm.movsbl(srcAddr, ToRegister(ins->output())); break;
|
||||
@ -426,6 +417,7 @@ CodeGeneratorX64::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
|
||||
case ArrayBufferView::TYPE_UINT16: masm.movzwl(srcAddr, ToRegister(ins->output())); break;
|
||||
case ArrayBufferView::TYPE_INT32:
|
||||
case ArrayBufferView::TYPE_UINT32: masm.movl(srcAddr, ToRegister(ins->output())); break;
|
||||
case ArrayBufferView::TYPE_FLOAT32: masm.loadFloat(srcAddr, ToFloatRegister(ins->output())); break;
|
||||
case ArrayBufferView::TYPE_FLOAT64: masm.loadDouble(srcAddr, ToFloatRegister(ins->output())); break;
|
||||
default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
|
||||
}
|
||||
@ -453,14 +445,6 @@ CodeGeneratorX64::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
|
||||
dstAddr = Operand(HeapReg, ToRegister(ins->ptr()), TimesOne);
|
||||
}
|
||||
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32) {
|
||||
masm.convertDoubleToFloat(ToFloatRegister(ins->value()), ScratchFloatReg);
|
||||
uint32_t before = masm.size();
|
||||
masm.storeFloat(ScratchFloatReg, dstAddr);
|
||||
uint32_t after = masm.size();
|
||||
return skipNote || gen->noteHeapAccess(AsmJSHeapAccess(before, after));
|
||||
}
|
||||
|
||||
uint32_t before = masm.size();
|
||||
if (ins->value()->isConstant()) {
|
||||
switch (vt) {
|
||||
@ -480,6 +464,7 @@ CodeGeneratorX64::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
|
||||
case ArrayBufferView::TYPE_UINT16: masm.movw(ToRegister(ins->value()), dstAddr); break;
|
||||
case ArrayBufferView::TYPE_INT32:
|
||||
case ArrayBufferView::TYPE_UINT32: masm.movl(ToRegister(ins->value()), dstAddr); break;
|
||||
case ArrayBufferView::TYPE_FLOAT32: masm.storeFloat(ToFloatRegister(ins->value()), dstAddr); break;
|
||||
case ArrayBufferView::TYPE_FLOAT64: masm.storeDouble(ToFloatRegister(ins->value()), dstAddr); break;
|
||||
default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
|
||||
}
|
||||
@ -508,7 +493,7 @@ CodeGeneratorX64::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins)
|
||||
MAsmJSStoreGlobalVar *mir = ins->mir();
|
||||
|
||||
MIRType type = mir->value()->type();
|
||||
JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double);
|
||||
JS_ASSERT(IsNumberType(type));
|
||||
|
||||
CodeOffsetLabel label;
|
||||
if (type == MIRType_Int32)
|
||||
|
@ -278,6 +278,16 @@ class Assembler : public AssemblerX86Shared
|
||||
}
|
||||
}
|
||||
|
||||
void fstp32(const Operand &src) {
|
||||
switch (src.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.fstp32_m(src.disp(), src.base());
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
|
||||
void cmpl(const Register src, ImmWord ptr) {
|
||||
masm.cmpl_ir(ptr.value, src.code());
|
||||
}
|
||||
|
@ -410,16 +410,21 @@ CodeGeneratorX86::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32 *lir)
|
||||
class jit::OutOfLineLoadTypedArrayOutOfBounds : public OutOfLineCodeBase<CodeGeneratorX86>
|
||||
{
|
||||
AnyRegister dest_;
|
||||
bool isFloat32Load_;
|
||||
public:
|
||||
OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest) : dest_(dest) {}
|
||||
OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest, bool isFloat32Load)
|
||||
: dest_(dest), isFloat32Load_(isFloat32Load)
|
||||
{}
|
||||
|
||||
const AnyRegister &dest() const { return dest_; }
|
||||
bool isFloat32Load() const { return isFloat32Load_; }
|
||||
bool accept(CodeGeneratorX86 *codegen) { return codegen->visitOutOfLineLoadTypedArrayOutOfBounds(this); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
CodeGeneratorX86::loadNonFloat32ViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
|
||||
const LDefinition *out)
|
||||
CodeGeneratorX86::loadViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
|
||||
const LDefinition *out)
|
||||
{
|
||||
switch (vt) {
|
||||
case ArrayBufferView::TYPE_INT8: masm.movsblWithPatch(srcAddr, ToRegister(out)); break;
|
||||
@ -429,6 +434,7 @@ CodeGeneratorX86::loadNonFloat32ViewTypeElement(ArrayBufferView::ViewType vt, co
|
||||
case ArrayBufferView::TYPE_UINT16: masm.movzwlWithPatch(srcAddr, ToRegister(out)); break;
|
||||
case ArrayBufferView::TYPE_INT32:
|
||||
case ArrayBufferView::TYPE_UINT32: masm.movlWithPatch(srcAddr, ToRegister(out)); break;
|
||||
case ArrayBufferView::TYPE_FLOAT32: masm.movssWithPatch(srcAddr, ToFloatRegister(out)); break;
|
||||
case ArrayBufferView::TYPE_FLOAT64: masm.movsdWithPatch(srcAddr, ToFloatRegister(out)); break;
|
||||
default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
|
||||
}
|
||||
@ -436,19 +442,11 @@ CodeGeneratorX86::loadNonFloat32ViewTypeElement(ArrayBufferView::ViewType vt, co
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
CodeGeneratorX86::loadViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
|
||||
const LDefinition *out)
|
||||
CodeGeneratorX86::loadAndNoteViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
|
||||
const LDefinition *out)
|
||||
{
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32) {
|
||||
FloatRegister dest = ToFloatRegister(out);
|
||||
uint32_t before = masm.size();
|
||||
masm.movssWithPatch(srcAddr, dest);
|
||||
uint32_t after = masm.size();
|
||||
masm.cvtss2sd(dest, dest);
|
||||
return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, AnyRegister(dest)));
|
||||
}
|
||||
uint32_t before = masm.size();
|
||||
loadNonFloat32ViewTypeElement(vt, srcAddr, out);
|
||||
loadViewTypeElement(vt, srcAddr, out);
|
||||
uint32_t after = masm.size();
|
||||
return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out)));
|
||||
}
|
||||
@ -458,13 +456,15 @@ CodeGeneratorX86::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic
|
||||
{
|
||||
const MLoadTypedArrayElementStatic *mir = ins->mir();
|
||||
ArrayBufferView::ViewType vt = mir->viewType();
|
||||
JS_ASSERT_IF(vt == ArrayBufferView::TYPE_FLOAT32, mir->type() == MIRType_Float32);
|
||||
|
||||
Register ptr = ToRegister(ins->ptr());
|
||||
const LDefinition *out = ins->output();
|
||||
|
||||
OutOfLineLoadTypedArrayOutOfBounds *ool = nullptr;
|
||||
bool isFloat32Load = (vt == ArrayBufferView::TYPE_FLOAT32);
|
||||
if (!mir->fallible()) {
|
||||
ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out));
|
||||
ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out), isFloat32Load);
|
||||
if (!addOutOfLineCode(ool))
|
||||
return false;
|
||||
}
|
||||
@ -476,18 +476,11 @@ CodeGeneratorX86::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic
|
||||
return false;
|
||||
|
||||
Address srcAddr(ptr, (int32_t) mir->base());
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32) {
|
||||
JS_ASSERT(mir->type() == MIRType_Float32);
|
||||
FloatRegister dest = ToFloatRegister(out);
|
||||
masm.movssWithPatch(srcAddr, dest);
|
||||
masm.canonicalizeFloat(dest);
|
||||
if (ool)
|
||||
masm.bind(ool->rejoin());
|
||||
return true;
|
||||
}
|
||||
loadNonFloat32ViewTypeElement(vt, srcAddr, out);
|
||||
loadViewTypeElement(vt, srcAddr, out);
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT64)
|
||||
masm.canonicalizeDouble(ToFloatRegister(out));
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32)
|
||||
masm.canonicalizeFloat(ToFloatRegister(out));
|
||||
if (ool)
|
||||
masm.bind(ool->rejoin());
|
||||
return true;
|
||||
@ -507,33 +500,25 @@ CodeGeneratorX86::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
|
||||
// immediate in the instruction. This displacement will fixed up when the
|
||||
// base address is known during dynamic linking (AsmJSModule::initHeap).
|
||||
PatchedAbsoluteAddress srcAddr((void *) ptr->toConstant()->toInt32());
|
||||
return loadViewTypeElement(vt, srcAddr, out);
|
||||
return loadAndNoteViewTypeElement(vt, srcAddr, out);
|
||||
}
|
||||
|
||||
Register ptrReg = ToRegister(ptr);
|
||||
Address srcAddr(ptrReg, 0);
|
||||
|
||||
if (mir->skipBoundsCheck())
|
||||
return loadViewTypeElement(vt, srcAddr, out);
|
||||
return loadAndNoteViewTypeElement(vt, srcAddr, out);
|
||||
|
||||
OutOfLineLoadTypedArrayOutOfBounds *ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out));
|
||||
bool isFloat32Load = vt == ArrayBufferView::TYPE_FLOAT32;
|
||||
OutOfLineLoadTypedArrayOutOfBounds *ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out), isFloat32Load);
|
||||
if (!addOutOfLineCode(ool))
|
||||
return false;
|
||||
|
||||
CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
|
||||
masm.j(Assembler::AboveOrEqual, ool->entry());
|
||||
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32) {
|
||||
FloatRegister dest = ToFloatRegister(out);
|
||||
uint32_t before = masm.size();
|
||||
masm.movssWithPatch(srcAddr, dest);
|
||||
uint32_t after = masm.size();
|
||||
masm.cvtss2sd(dest, dest);
|
||||
masm.bind(ool->rejoin());
|
||||
return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, AnyRegister(dest), cmp.offset()));
|
||||
}
|
||||
uint32_t before = masm.size();
|
||||
loadNonFloat32ViewTypeElement(vt, srcAddr, out);
|
||||
loadViewTypeElement(vt, srcAddr, out);
|
||||
uint32_t after = masm.size();
|
||||
masm.bind(ool->rejoin());
|
||||
return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out), cmp.offset()));
|
||||
@ -543,7 +528,10 @@ bool
|
||||
CodeGeneratorX86::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds *ool)
|
||||
{
|
||||
if (ool->dest().isFloat()) {
|
||||
masm.loadConstantDouble(GenericNaN(), ool->dest().fpu());
|
||||
if (ool->isFloat32Load())
|
||||
masm.loadConstantFloat32(float(GenericNaN()), ool->dest().fpu());
|
||||
else
|
||||
masm.loadConstantDouble(GenericNaN(), ool->dest().fpu());
|
||||
} else {
|
||||
Register destReg = ool->dest().gpr();
|
||||
masm.mov(ImmWord(0), destReg);
|
||||
@ -554,8 +542,8 @@ CodeGeneratorX86::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArra
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
CodeGeneratorX86::storeNonFloat32ViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
|
||||
const T &dstAddr)
|
||||
CodeGeneratorX86::storeViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
|
||||
const T &dstAddr)
|
||||
{
|
||||
switch (vt) {
|
||||
case ArrayBufferView::TYPE_INT8:
|
||||
@ -565,6 +553,7 @@ CodeGeneratorX86::storeNonFloat32ViewTypeElement(ArrayBufferView::ViewType vt, c
|
||||
case ArrayBufferView::TYPE_UINT16: masm.movwWithPatch(ToRegister(value), dstAddr); break;
|
||||
case ArrayBufferView::TYPE_INT32:
|
||||
case ArrayBufferView::TYPE_UINT32: masm.movlWithPatch(ToRegister(value), dstAddr); break;
|
||||
case ArrayBufferView::TYPE_FLOAT32: masm.movssWithPatch(ToFloatRegister(value), dstAddr); break;
|
||||
case ArrayBufferView::TYPE_FLOAT64: masm.movsdWithPatch(ToFloatRegister(value), dstAddr); break;
|
||||
default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
|
||||
}
|
||||
@ -572,18 +561,11 @@ CodeGeneratorX86::storeNonFloat32ViewTypeElement(ArrayBufferView::ViewType vt, c
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
CodeGeneratorX86::storeViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
|
||||
const T &dstAddr)
|
||||
CodeGeneratorX86::storeAndNoteViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
|
||||
const T &dstAddr)
|
||||
{
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32) {
|
||||
uint32_t before = masm.size();
|
||||
masm.convertDoubleToFloat(ToFloatRegister(value), ScratchFloatReg);
|
||||
masm.movssWithPatch(ScratchFloatReg, dstAddr);
|
||||
uint32_t after = masm.size();
|
||||
return gen->noteHeapAccess(AsmJSHeapAccess(before, after));
|
||||
}
|
||||
uint32_t before = masm.size();
|
||||
storeNonFloat32ViewTypeElement(vt, value, dstAddr);
|
||||
storeViewTypeElement(vt, value, dstAddr);
|
||||
uint32_t after = masm.size();
|
||||
return gen->noteHeapAccess(AsmJSHeapAccess(before, after));
|
||||
}
|
||||
@ -602,13 +584,7 @@ CodeGeneratorX86::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStati
|
||||
masm.j(Assembler::AboveOrEqual, &rejoin);
|
||||
|
||||
Address dstAddr(ptr, (int32_t) mir->base());
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32) {
|
||||
JS_ASSERT(mir->value()->type() == MIRType_Float32);
|
||||
masm.movssWithPatch(ToFloatRegister(value), dstAddr);
|
||||
masm.bind(&rejoin);
|
||||
return true;
|
||||
}
|
||||
storeNonFloat32ViewTypeElement(vt, value, dstAddr);
|
||||
storeViewTypeElement(vt, value, dstAddr);
|
||||
masm.bind(&rejoin);
|
||||
return true;
|
||||
}
|
||||
@ -627,29 +603,21 @@ CodeGeneratorX86::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
|
||||
// immediate in the instruction. This displacement will fixed up when the
|
||||
// base address is known during dynamic linking (AsmJSModule::initHeap).
|
||||
PatchedAbsoluteAddress dstAddr((void *) ptr->toConstant()->toInt32());
|
||||
return storeViewTypeElement(vt, value, dstAddr);
|
||||
return storeAndNoteViewTypeElement(vt, value, dstAddr);
|
||||
}
|
||||
|
||||
Register ptrReg = ToRegister(ptr);
|
||||
Address dstAddr(ptrReg, 0);
|
||||
|
||||
if (mir->skipBoundsCheck())
|
||||
return storeViewTypeElement(vt, value, dstAddr);
|
||||
return storeAndNoteViewTypeElement(vt, value, dstAddr);
|
||||
|
||||
CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
|
||||
Label rejoin;
|
||||
masm.j(Assembler::AboveOrEqual, &rejoin);
|
||||
|
||||
if (vt == ArrayBufferView::TYPE_FLOAT32) {
|
||||
masm.convertDoubleToFloat(ToFloatRegister(value), ScratchFloatReg);
|
||||
uint32_t before = masm.size();
|
||||
masm.movssWithPatch(ScratchFloatReg, dstAddr);
|
||||
uint32_t after = masm.size();
|
||||
masm.bind(&rejoin);
|
||||
return gen->noteHeapAccess(AsmJSHeapAccess(before, after, cmp.offset()));
|
||||
}
|
||||
uint32_t before = masm.size();
|
||||
storeNonFloat32ViewTypeElement(vt, value, dstAddr);
|
||||
storeViewTypeElement(vt, value, dstAddr);
|
||||
uint32_t after = masm.size();
|
||||
masm.bind(&rejoin);
|
||||
return gen->noteHeapAccess(AsmJSHeapAccess(before, after, cmp.offset()));
|
||||
@ -659,10 +627,14 @@ bool
|
||||
CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins)
|
||||
{
|
||||
MAsmJSLoadGlobalVar *mir = ins->mir();
|
||||
MIRType type = mir->type();
|
||||
JS_ASSERT(IsNumberType(type));
|
||||
|
||||
CodeOffsetLabel label;
|
||||
if (mir->type() == MIRType_Int32)
|
||||
if (type == MIRType_Int32)
|
||||
label = masm.movlWithPatch(PatchedAbsoluteAddress(), ToRegister(ins->output()));
|
||||
else if (type == MIRType_Float32)
|
||||
label = masm.movssWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
|
||||
else
|
||||
label = masm.movsdWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
|
||||
|
||||
@ -675,11 +647,13 @@ CodeGeneratorX86::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins)
|
||||
MAsmJSStoreGlobalVar *mir = ins->mir();
|
||||
|
||||
MIRType type = mir->value()->type();
|
||||
JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double);
|
||||
JS_ASSERT(IsNumberType(type));
|
||||
|
||||
CodeOffsetLabel label;
|
||||
if (type == MIRType_Int32)
|
||||
label = masm.movlWithPatch(ToRegister(ins->value()), PatchedAbsoluteAddress());
|
||||
else if (type == MIRType_Float32)
|
||||
label = masm.movssWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
|
||||
else
|
||||
label = masm.movsdWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
|
||||
|
||||
@ -713,13 +687,18 @@ void
|
||||
CodeGeneratorX86::postAsmJSCall(LAsmJSCall *lir)
|
||||
{
|
||||
MAsmJSCall *mir = lir->mir();
|
||||
if (mir->type() != MIRType_Double || mir->callee().which() != MAsmJSCall::Callee::Builtin)
|
||||
if (!IsFloatingPointType(mir->type()) || mir->callee().which() != MAsmJSCall::Callee::Builtin)
|
||||
return;
|
||||
|
||||
masm.reserveStack(sizeof(double));
|
||||
masm.fstp(Operand(esp, 0));
|
||||
masm.loadDouble(Operand(esp, 0), ReturnFloatReg);
|
||||
masm.freeStack(sizeof(double));
|
||||
if (mir->type() == MIRType_Float32) {
|
||||
Operand op(esp, -sizeof(float));
|
||||
masm.fstp32(op);
|
||||
masm.loadFloat(op, ReturnFloatReg);
|
||||
} else {
|
||||
Operand op(esp, -sizeof(double));
|
||||
masm.fstp(op);
|
||||
masm.loadDouble(op, ReturnFloatReg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1013,7 +992,12 @@ CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32 *ool)
|
||||
masm.setupUnalignedABICall(1, output);
|
||||
masm.cvtss2sd(input, input);
|
||||
masm.passABIArg(input);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
|
||||
|
||||
if (gen->compilingAsmJS())
|
||||
masm.callWithABI(AsmJSImm_ToInt32);
|
||||
else
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
|
||||
|
||||
masm.storeCallResult(output);
|
||||
masm.pop(input);
|
||||
|
||||
|
@ -30,16 +30,16 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared
|
||||
ValueOperand ToTempValue(LInstruction *ins, size_t pos);
|
||||
|
||||
template<typename T>
|
||||
bool loadViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
|
||||
bool loadAndNoteViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
|
||||
const LDefinition *out);
|
||||
template<typename T>
|
||||
void loadNonFloat32ViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
|
||||
void loadViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
|
||||
const LDefinition *out);
|
||||
template<typename T>
|
||||
bool storeViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
|
||||
bool storeAndNoteViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
|
||||
const T &dstAddr);
|
||||
template<typename T>
|
||||
void storeNonFloat32ViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
|
||||
void storeViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
|
||||
const T &dstAddr);
|
||||
void storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType,
|
||||
const Register &elements, const LAllocation *index);
|
||||
|
@ -460,6 +460,16 @@ js::math_imul(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Implements Math.fround (20.2.2.16) up to step 3
|
||||
bool
|
||||
js::RoundFloat32(JSContext *cx, Handle<Value> v, float *out)
|
||||
{
|
||||
double d;
|
||||
bool success = ToNumber(cx, v, &d);
|
||||
*out = static_cast<float>(d);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
js::math_fround(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -470,11 +480,10 @@ js::math_fround(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
double x;
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
float f;
|
||||
if (!RoundFloat32(cx, args[0], &f))
|
||||
return false;
|
||||
|
||||
float f = x;
|
||||
args.rval().setDouble(static_cast<double>(f));
|
||||
return true;
|
||||
}
|
||||
|
@ -84,6 +84,9 @@ namespace js {
|
||||
extern bool
|
||||
math_imul(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
|
||||
extern bool
|
||||
RoundFloat32(JSContext *cx, Handle<Value> v, float *out);
|
||||
|
||||
extern bool
|
||||
math_fround(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user