--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -473,24 +473,24 @@ DecodeExpr(FunctionDecoder& f, ExprType
return DecodeBinaryOperator(f, expected, ExprType::I32);
case Expr::I64Add:
case Expr::I64Sub:
case Expr::I64Mul:
case Expr::I64DivS:
case Expr::I64DivU:
case Expr::I64RemS:
case Expr::I64RemU:
+ return f.fail("NYI: i64");
case Expr::I64And:
case Expr::I64Or:
case Expr::I64Xor:
case Expr::I64Shl:
case Expr::I64ShrS:
case Expr::I64ShrU:
- return f.fail("NYI: i64") &&
- DecodeBinaryOperator(f, expected, ExprType::I64);
+ return DecodeBinaryOperator(f, expected, ExprType::I64);
case Expr::F32Add:
case Expr::F32Sub:
case Expr::F32Mul:
case Expr::F32Div:
case Expr::F32Min:
case Expr::F32Max:
return DecodeBinaryOperator(f, expected, ExprType::F32);
case Expr::F32CopySign:
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -440,21 +440,21 @@ class FunctionCompiler
if (inDeadCode())
return nullptr;
MMod* ins = MMod::NewAsmJS(alloc(), lhs, rhs, type, unsignd);
curBlock_->add(ins);
return ins;
}
template <class T>
- MDefinition* bitwise(MDefinition* lhs, MDefinition* rhs)
+ MDefinition* bitwise(MDefinition* lhs, MDefinition* rhs, MIRType type)
{
if (inDeadCode())
return nullptr;
- T* ins = T::NewAsmJS(alloc(), lhs, rhs);
+ T* ins = T::NewAsmJS(alloc(), lhs, rhs, type);
curBlock_->add(ins);
return ins;
}
template <class T>
MDefinition* bitwise(MDefinition* op)
{
if (inDeadCode())
@@ -781,17 +781,17 @@ class FunctionCompiler
return true;
}
MAsmJSLoadFuncPtr* ptrFun;
if (mg().isAsmJS()) {
MOZ_ASSERT(IsPowerOfTwo(length));
MConstant* mask = MConstant::New(alloc(), Int32Value(length - 1));
curBlock_->add(mask);
- MBitAnd* maskedIndex = MBitAnd::NewAsmJS(alloc(), index, mask);
+ MBitAnd* maskedIndex = MBitAnd::NewAsmJS(alloc(), index, mask, MIRType_Int32);
curBlock_->add(maskedIndex);
ptrFun = MAsmJSLoadFuncPtr::New(alloc(), maskedIndex, globalDataOffset);
curBlock_->add(ptrFun);
} else {
// For wasm code, as a space optimization, the ModuleGenerator does not allocate a
// table for signatures which do not contain any indirectly-callable functions.
// However, these signatures may still be called (it is not a validation error)
// so we instead have a flag alwaysThrow which throws an exception instead of loading
@@ -2323,31 +2323,31 @@ EmitComparison(FunctionCompiler& f, Expr
}
*def = f.compare(lhs, rhs, compareOp, compareType);
return true;
}
template<class T>
static bool
-EmitBitwise(FunctionCompiler& f, MDefinition** def)
+EmitBitwise(FunctionCompiler& f, ExprType type, MDefinition** def)
{
MDefinition* lhs;
- if (!EmitExpr(f, ExprType::I32, &lhs))
+ if (!EmitExpr(f, type, &lhs))
return false;
MDefinition* rhs;
- if (!EmitExpr(f, ExprType::I32, &rhs))
+ if (!EmitExpr(f, type, &rhs))
return false;
- *def = f.bitwise<T>(lhs, rhs);
+ MIRType mirType = ToMIRType(type);
+ *def = f.bitwise<T>(lhs, rhs, mirType);
return true;
}
-template<>
-bool
-EmitBitwise<MBitNot>(FunctionCompiler& f, MDefinition** def)
+static bool
+EmitBitwiseNot(FunctionCompiler& f, MDefinition** def)
{
MDefinition* in;
if (!EmitExpr(f, ExprType::I32, &in))
return false;
*def = f.bitwise<MBitNot>(in);
return true;
}
@@ -2815,29 +2815,29 @@ EmitExpr(FunctionCompiler& f, ExprType t
return EmitUnary<MTruncateToInt32>(f, ExprType::F64, def);
case Expr::I32Clz:
return EmitUnary<MClz>(f, ExprType::I32, def);
case Expr::I32Abs:
return EmitUnaryMir<MAbs>(f, ExprType::I32, def);
case Expr::I32Neg:
return EmitUnaryMir<MAsmJSNeg>(f, ExprType::I32, def);
case Expr::I32Or:
- return EmitBitwise<MBitOr>(f, def);
+ return EmitBitwise<MBitOr>(f, ExprType::I32, def);
case Expr::I32And:
- return EmitBitwise<MBitAnd>(f, def);
+ return EmitBitwise<MBitAnd>(f, ExprType::I32, def);
case Expr::I32Xor:
- return EmitBitwise<MBitXor>(f, def);
+ return EmitBitwise<MBitXor>(f, ExprType::I32, def);
case Expr::I32Shl:
- return EmitBitwise<MLsh>(f, def);
+ return EmitBitwise<MLsh>(f, ExprType::I32, def);
case Expr::I32ShrS:
- return EmitBitwise<MRsh>(f, def);
+ return EmitBitwise<MRsh>(f, ExprType::I32, def);
case Expr::I32ShrU:
- return EmitBitwise<MUrsh>(f, def);
+ return EmitBitwise<MUrsh>(f, ExprType::I32, def);
case Expr::I32BitNot:
- return EmitBitwise<MBitNot>(f, def);
+ return EmitBitwiseNot(f, def);
case Expr::I32LoadMem8S:
return EmitLoad(f, Scalar::Int8, def);
case Expr::I32LoadMem8U:
return EmitLoad(f, Scalar::Uint8, def);
case Expr::I32LoadMem16S:
return EmitLoad(f, Scalar::Int16, def);
case Expr::I32LoadMem16U:
return EmitLoad(f, Scalar::Uint16, def);
@@ -2890,16 +2890,28 @@ EmitExpr(FunctionCompiler& f, ExprType t
return EmitAtomicsLoad(f, def);
case Expr::I32AtomicsStore:
return EmitAtomicsStore(f, def);
case Expr::I32AtomicsBinOp:
return EmitAtomicsBinOp(f, def);
// I64
case Expr::I64Const:
return EmitLiteral(f, ExprType::I64, def);
+ case Expr::I64Or:
+ return EmitBitwise<MBitOr>(f, ExprType::I64, def);
+ case Expr::I64And:
+ return EmitBitwise<MBitAnd>(f, ExprType::I64, def);
+ case Expr::I64Xor:
+ return EmitBitwise<MBitXor>(f, ExprType::I64, def);
+ case Expr::I64Shl:
+ return EmitBitwise<MLsh>(f, ExprType::I64, def);
+ case Expr::I64ShrS:
+ return EmitBitwise<MRsh>(f, ExprType::I64, def);
+ case Expr::I64ShrU:
+ return EmitBitwise<MUrsh>(f, ExprType::I64, def);
// F32
case Expr::F32Const:
return EmitLiteral(f, ExprType::F32, def);
case Expr::F32Add:
return EmitAddOrSub(f, ExprType::F32, IsAdd(true), def);
case Expr::F32Sub:
return EmitAddOrSub(f, ExprType::F32, IsAdd(false), def);
case Expr::F32Mul:
@@ -3066,22 +3078,16 @@ EmitExpr(FunctionCompiler& f, ExprType t
case Expr::I64Popcnt:
case Expr::I64Add:
case Expr::I64Sub:
case Expr::I64Mul:
case Expr::I64DivS:
case Expr::I64DivU:
case Expr::I64RemS:
case Expr::I64RemU:
- case Expr::I64Or:
- case Expr::I64And:
- case Expr::I64Xor:
- case Expr::I64Shl:
- case Expr::I64ShrU:
- case Expr::I64ShrS:
MOZ_CRASH("NYI");
case Expr::Unreachable:
break;
case Expr::Limit:
MOZ_CRASH("Limit");
}
MOZ_CRASH("unexpected wasm opcode");
--- a/js/src/jit-test/tests/wasm/basic-integer.js
+++ b/js/src/jit-test/tests/wasm/basic-integer.js
@@ -4,21 +4,29 @@ assertEq(wasmEvalText('(module (func (re
assertEq(wasmEvalText('(module (func (result i32) (i32.const -2147483648)) (export "" 0))')(), -2147483648);
assertEq(wasmEvalText('(module (func (result i32) (i32.const 4294967295)) (export "" 0))')(), -1);
function testUnary(type, opcode, op, expect) {
assertEq(wasmEvalText('(module (func (param ' + type + ') (result ' + type + ') (' + type + '.' + opcode + ' (get_local 0))) (export "" 0))')(op), expect);
}
function testBinary(type, opcode, lhs, rhs, expect) {
- assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result ' + type + ') (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
+ if (type === 'i64') {
+ // i64 cannot be imported/exported, so we use a wrapper function.
+ assertEq(wasmEvalText(`(module
+ (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (get_local 1)))
+ (func (result i32) (i64.eq (call 0 (i64.const ${lhs}) (i64.const ${rhs})) (i64.const ${expect})))
+ (export "" 1))`)(), 1);
+ } else {
+ assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result ' + type + ') (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
+ }
}
function testComparison(type, opcode, lhs, rhs, expect) {
- if (type == 'i64') {
+ if (type === 'i64') {
// i64 cannot be imported/exported, so we use a wrapper function.
assertEq(wasmEvalText(`(module
(func (param i64) (param i64) (result i32) (i64.${opcode} (get_local 0) (get_local 1)))
(func (result i32) (call 0 (i64.const ${lhs}) (i64.const ${rhs})))
(export "" 1))`)(), expect);
// Also test if_else, for the compare-and-branch path.
assertEq(wasmEvalText(`(module
(func (param i64) (param i64) (result i32)
@@ -67,24 +75,33 @@ testComparison('i32', 'ge_u', 40, 40, 1)
//testBinary('i64', 'add', 40, 2, 42); // TODO: NYI
//testBinary('i64', 'sub', 40, 2, 38); // TODO: NYI
//testBinary('i64', 'mul', 40, 2, 80); // TODO: NYI
//testBinary('i64', 'div_s', -40, 2, -20); // TODO: NYI
//testBinary('i64', 'div_u', -40, 2, 2147483628); // TODO: NYI
//testBinary('i64', 'rem_s', 40, -3, 1); // TODO: NYI
//testBinary('i64', 'rem_u', 40, -3, 40); // TODO: NYI
-//testBinary('i64', 'and', 42, 6, 2); // TODO: NYI
-//testBinary('i64', 'or', 42, 6, 46); // TODO: NYI
-//testBinary('i64', 'xor', 42, 2, 40); // TODO: NYI
-//testBinary('i64', 'shl', 40, 2, 160); // TODO: NYI
-//testBinary('i64', 'shr_s', -40, 2, -10); // TODO: NYI
-//testBinary('i64', 'shr_u', -40, 2, 1073741814); // TODO: NYI
if (getBuildConfiguration().x64) {
+ testBinary('i64', 'and', 42, 6, 2);
+ testBinary('i64', 'or', 42, 6, 46);
+ testBinary('i64', 'xor', 42, 2, 40);
+ testBinary('i64', 'and', "0x8765432112345678", "0xffff0000ffff0000", "0x8765000012340000");
+ testBinary('i64', 'or', "0x8765432112345678", "0xffff0000ffff0000", "0xffff4321ffff5678");
+ testBinary('i64', 'xor', "0x8765432112345678", "0xffff0000ffff0000", "0x789a4321edcb5678");
+ testBinary('i64', 'shl', 40, 2, 160);
+ testBinary('i64', 'shr_s', -40, 2, -10);
+ testBinary('i64', 'shr_u', -40, 2, "0x3ffffffffffffff6");
+ testBinary('i64', 'shl', 0xff00ff, 28, "0xff00ff0000000");
+ testBinary('i64', 'shl', 1, 63, "0x8000000000000000");
+ testBinary('i64', 'shl', 1, 64, 1);
+ testBinary('i64', 'shr_s', "0xff00ff0000000", 28, 0xff00ff);
+ testBinary('i64', 'shr_u', "0x8ffff00ff0000000", 56, 0x8f);
+
testComparison('i64', 'eq', 40, 40, 1);
testComparison('i64', 'ne', 40, 40, 0);
testComparison('i64', 'lt_s', 40, 40, 0);
testComparison('i64', 'lt_u', 40, 40, 0);
testComparison('i64', 'le_s', 40, 40, 1);
testComparison('i64', 'le_u', 40, 40, 1);
testComparison('i64', 'gt_s', 40, 40, 0);
testComparison('i64', 'gt_u', 40, 40, 0);
--- a/js/src/jit/AlignmentMaskAnalysis.cpp
+++ b/js/src/jit/AlignmentMaskAnalysis.cpp
@@ -60,17 +60,17 @@ AnalyzeAsmHeapAddress(MDefinition* ptr,
return;
uint32_t i = op1->toConstant()->toInt32();
uint32_t m = rhs->toConstant()->toInt32();
if (!IsAlignmentMask(m) || (i & m) != i)
return;
// The pattern was matched! Produce the replacement expression.
- MInstruction* and_ = MBitAnd::NewAsmJS(graph.alloc(), op0, rhs);
+ MInstruction* and_ = MBitAnd::NewAsmJS(graph.alloc(), op0, rhs, MIRType_Int32);
ptr->block()->insertBefore(ptr->toBitAnd(), and_);
MInstruction* add = MAdd::NewAsmJS(graph.alloc(), and_, op1, MIRType_Int32);
ptr->block()->insertBefore(ptr->toBitAnd(), add);
ptr->replaceAllUsesWith(add);
ptr->block()->discard(ptr->toBitAnd());
}
bool
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1116,22 +1116,30 @@ LIRGenerator::visitCompare(MCompare* com
}
void
LIRGenerator::lowerBitOp(JSOp op, MInstruction* ins)
{
MDefinition* lhs = ins->getOperand(0);
MDefinition* rhs = ins->getOperand(1);
- if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
+ if (lhs->type() == MIRType_Int32) {
+ MOZ_ASSERT(rhs->type() == MIRType_Int32);
ReorderCommutative(&lhs, &rhs, ins);
lowerForALU(new(alloc()) LBitOpI(op), ins, lhs, rhs);
return;
}
+ if (lhs->type() == MIRType_Int64) {
+ MOZ_ASSERT(rhs->type() == MIRType_Int64);
+ ReorderCommutative(&lhs, &rhs, ins);
+ lowerForALUInt64(new(alloc()) LBitOpI64(op), ins, lhs, rhs);
+ return;
+ }
+
LBitOpV* lir = new(alloc()) LBitOpV(op, useBoxAtStart(lhs), useBoxAtStart(rhs));
defineReturn(lir, ins);
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitTypeOf(MTypeOf* ins)
{
@@ -1215,32 +1223,40 @@ LIRGenerator::visitBitXor(MBitXor* ins)
}
void
LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins)
{
MDefinition* lhs = ins->getOperand(0);
MDefinition* rhs = ins->getOperand(1);
- if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
+ if (lhs->type() == MIRType_Int32) {
+ MOZ_ASSERT(rhs->type() == MIRType_Int32);
+
if (ins->type() == MIRType_Double) {
MOZ_ASSERT(op == JSOP_URSH);
lowerUrshD(ins->toUrsh());
return;
}
LShiftI* lir = new(alloc()) LShiftI(op);
if (op == JSOP_URSH) {
if (ins->toUrsh()->fallible())
assignSnapshot(lir, Bailout_OverflowInvalidate);
}
lowerForShift(lir, ins, lhs, rhs);
return;
}
+ if (lhs->type() == MIRType_Int64) {
+ MOZ_ASSERT(rhs->type() == MIRType_Int64);
+ lowerForShiftInt64(new(alloc()) LShiftI64(op), ins, lhs, rhs);
+ return;
+ }
+
MOZ_ASSERT(ins->specialization() == MIRType_None);
if (op == JSOP_URSH) {
// Result is either int32 or double so we have to use BinaryV.
lowerBinaryV(JSOP_URSH, ins);
return;
}
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2469,25 +2469,27 @@ MBinaryBitwiseInstruction::foldUnnecessa
void
MBinaryBitwiseInstruction::infer(BaselineInspector*, jsbytecode*)
{
if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(0)->mightBeType(MIRType_Symbol) ||
getOperand(1)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Symbol))
{
specialization_ = MIRType_None;
} else {
- specializeAsInt32();
+ specializeAs(MIRType_Int32);
}
}
void
-MBinaryBitwiseInstruction::specializeAsInt32()
-{
- specialization_ = MIRType_Int32;
- MOZ_ASSERT(type() == MIRType_Int32);
+MBinaryBitwiseInstruction::specializeAs(MIRType type)
+{
+ MOZ_ASSERT(type == MIRType_Int32 || type == MIRType_Int64);
+ MOZ_ASSERT(this->type() == type);
+
+ specialization_ = type;
if (isBitOr() || isBitAnd() || isBitXor())
setCommutative();
}
void
MShiftInstruction::infer(BaselineInspector*, jsbytecode*)
{
@@ -3403,94 +3405,94 @@ MTypeOf::cacheInputMaybeCallableOrEmulat
if (!input()->maybeEmulatesUndefined(constraints) && !MaybeCallable(constraints, input()))
markInputNotCallableOrEmulatesUndefined();
}
MBitAnd*
MBitAnd::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
{
- return new(alloc) MBitAnd(left, right);
+ return new(alloc) MBitAnd(left, right, MIRType_Int32);
}
MBitAnd*
-MBitAnd::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right)
-{
- MBitAnd* ins = new(alloc) MBitAnd(left, right);
- ins->specializeAsInt32();
+MBitAnd::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
+{
+ MBitAnd* ins = new(alloc) MBitAnd(left, right, type);
+ ins->specializeAs(type);
return ins;
}
MBitOr*
MBitOr::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
{
- return new(alloc) MBitOr(left, right);
+ return new(alloc) MBitOr(left, right, MIRType_Int32);
}
MBitOr*
-MBitOr::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right)
-{
- MBitOr* ins = new(alloc) MBitOr(left, right);
- ins->specializeAsInt32();
+MBitOr::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
+{
+ MBitOr* ins = new(alloc) MBitOr(left, right, type);
+ ins->specializeAs(type);
return ins;
}
MBitXor*
MBitXor::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
{
- return new(alloc) MBitXor(left, right);
+ return new(alloc) MBitXor(left, right, MIRType_Int32);
}
MBitXor*
-MBitXor::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right)
-{
- MBitXor* ins = new(alloc) MBitXor(left, right);
- ins->specializeAsInt32();
+MBitXor::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
+{
+ MBitXor* ins = new(alloc) MBitXor(left, right, type);
+ ins->specializeAs(type);
return ins;
}
MLsh*
MLsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
{
- return new(alloc) MLsh(left, right);
+ return new(alloc) MLsh(left, right, MIRType_Int32);
}
MLsh*
-MLsh::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right)
-{
- MLsh* ins = new(alloc) MLsh(left, right);
- ins->specializeAsInt32();
+MLsh::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
+{
+ MLsh* ins = new(alloc) MLsh(left, right, type);
+ ins->specializeAs(type);
return ins;
}
MRsh*
MRsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
{
- return new(alloc) MRsh(left, right);
+ return new(alloc) MRsh(left, right, MIRType_Int32);
}
MRsh*
-MRsh::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right)
-{
- MRsh* ins = new(alloc) MRsh(left, right);
- ins->specializeAsInt32();
+MRsh::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
+{
+ MRsh* ins = new(alloc) MRsh(left, right, type);
+ ins->specializeAs(type);
return ins;
}
MUrsh*
MUrsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
{
- return new(alloc) MUrsh(left, right);
+ return new(alloc) MUrsh(left, right, MIRType_Int32);
}
MUrsh*
-MUrsh::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right)
-{
- MUrsh* ins = new(alloc) MUrsh(left, right);
- ins->specializeAsInt32();
+MUrsh::NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
+{
+ MUrsh* ins = new(alloc) MUrsh(left, right, type);
+ ins->specializeAs(type);
// Since Ion has no UInt32 type, we use Int32 and we have a special
// exception to the type rules: we can return values in
// (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
// without bailing out. This is necessary because Ion has no UInt32
// type and we can't have bailouts in asm.js code.
ins->bailoutsDisabled_ = true;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5570,25 +5570,26 @@ class MToId
}
};
class MBinaryBitwiseInstruction
: public MBinaryInstruction,
public BitwisePolicy::Data
{
protected:
- MBinaryBitwiseInstruction(MDefinition* left, MDefinition* right)
+ MBinaryBitwiseInstruction(MDefinition* left, MDefinition* right, MIRType type)
: MBinaryInstruction(left, right), maskMatchesLeftRange(false),
maskMatchesRightRange(false)
{
- setResultType(MIRType_Int32);
- setMovable();
- }
-
- void specializeAsInt32();
+ MOZ_ASSERT(type == MIRType_Int32 || type == MIRType_Int64);
+ setResultType(type);
+ setMovable();
+ }
+
+ void specializeAs(MIRType type);
bool maskMatchesLeftRange;
bool maskMatchesRightRange;
public:
MDefinition* foldsTo(TempAllocator& alloc) override;
MDefinition* foldUnnecessaryBitop();
virtual MDefinition* foldIfZero(size_t operand) = 0;
virtual MDefinition* foldIfNegOne(size_t operand) = 0;
@@ -5611,24 +5612,25 @@ class MBinaryBitwiseInstruction
return AliasSet::None();
}
TruncateKind operandTruncateKind(size_t index) const override;
};
class MBitAnd : public MBinaryBitwiseInstruction
{
- MBitAnd(MDefinition* left, MDefinition* right)
- : MBinaryBitwiseInstruction(left, right)
+ MBitAnd(MDefinition* left, MDefinition* right, MIRType type)
+ : MBinaryBitwiseInstruction(left, right, type)
{ }
public:
INSTRUCTION_HEADER(BitAnd)
static MBitAnd* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
- static MBitAnd* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
+ static MBitAnd* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+ MIRType type);
MDefinition* foldIfZero(size_t operand) override {
return getOperand(operand); // 0 & x => 0;
}
MDefinition* foldIfNegOne(size_t operand) override {
return getOperand(1 - operand); // x & -1 => x
}
MDefinition* foldIfEqual() override {
@@ -5645,24 +5647,25 @@ class MBitAnd : public MBinaryBitwiseIns
return specialization_ != MIRType_None;
}
ALLOW_CLONE(MBitAnd)
};
class MBitOr : public MBinaryBitwiseInstruction
{
- MBitOr(MDefinition* left, MDefinition* right)
- : MBinaryBitwiseInstruction(left, right)
+ MBitOr(MDefinition* left, MDefinition* right, MIRType type)
+ : MBinaryBitwiseInstruction(left, right, type)
{ }
public:
INSTRUCTION_HEADER(BitOr)
static MBitOr* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
- static MBitOr* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
+ static MBitOr* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+ MIRType type);
MDefinition* foldIfZero(size_t operand) override {
return getOperand(1 - operand); // 0 | x => x, so if ith is 0, return (1-i)th
}
MDefinition* foldIfNegOne(size_t operand) override {
return getOperand(operand); // x | -1 => -1
}
MDefinition* foldIfEqual() override {
@@ -5677,24 +5680,25 @@ class MBitOr : public MBinaryBitwiseInst
return specialization_ != MIRType_None;
}
ALLOW_CLONE(MBitOr)
};
class MBitXor : public MBinaryBitwiseInstruction
{
- MBitXor(MDefinition* left, MDefinition* right)
- : MBinaryBitwiseInstruction(left, right)
+ MBitXor(MDefinition* left, MDefinition* right, MIRType type)
+ : MBinaryBitwiseInstruction(left, right, type)
{ }
public:
INSTRUCTION_HEADER(BitXor)
static MBitXor* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
- static MBitXor* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
+ static MBitXor* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+ MIRType type);
MDefinition* foldIfZero(size_t operand) override {
return getOperand(1 - operand); // 0 ^ x => x
}
MDefinition* foldIfNegOne(size_t operand) override {
return this;
}
MDefinition* foldIfEqual() override {
@@ -5712,18 +5716,18 @@ class MBitXor : public MBinaryBitwiseIns
ALLOW_CLONE(MBitXor)
};
class MShiftInstruction
: public MBinaryBitwiseInstruction
{
protected:
- MShiftInstruction(MDefinition* left, MDefinition* right)
- : MBinaryBitwiseInstruction(left, right)
+ MShiftInstruction(MDefinition* left, MDefinition* right, MIRType type)
+ : MBinaryBitwiseInstruction(left, right, type)
{ }
public:
MDefinition* foldIfNegOne(size_t operand) override {
return this;
}
MDefinition* foldIfEqual() override {
return this;
@@ -5731,24 +5735,25 @@ class MShiftInstruction
MDefinition* foldIfAllBitsSet(size_t operand) override {
return this;
}
virtual void infer(BaselineInspector* inspector, jsbytecode* pc) override;
};
class MLsh : public MShiftInstruction
{
- MLsh(MDefinition* left, MDefinition* right)
- : MShiftInstruction(left, right)
+ MLsh(MDefinition* left, MDefinition* right, MIRType type)
+ : MShiftInstruction(left, right, type)
{ }
public:
INSTRUCTION_HEADER(Lsh)
static MLsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
- static MLsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
+ static MLsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+ MIRType type);
MDefinition* foldIfZero(size_t operand) override {
// 0 << x => 0
// x << 0 => x
return getOperand(0);
}
void computeRange(TempAllocator& alloc) override;
@@ -5757,24 +5762,25 @@ class MLsh : public MShiftInstruction
return specialization_ != MIRType_None;
}
ALLOW_CLONE(MLsh)
};
class MRsh : public MShiftInstruction
{
- MRsh(MDefinition* left, MDefinition* right)
- : MShiftInstruction(left, right)
+ MRsh(MDefinition* left, MDefinition* right, MIRType type)
+ : MShiftInstruction(left, right, type)
{ }
public:
INSTRUCTION_HEADER(Rsh)
static MRsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
- static MRsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
+ static MRsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+ MIRType type);
MDefinition* foldIfZero(size_t operand) override {
// 0 >> x => 0
// x >> 0 => x
return getOperand(0);
}
void computeRange(TempAllocator& alloc) override;
@@ -5785,25 +5791,26 @@ class MRsh : public MShiftInstruction
ALLOW_CLONE(MRsh)
};
class MUrsh : public MShiftInstruction
{
bool bailoutsDisabled_;
- MUrsh(MDefinition* left, MDefinition* right)
- : MShiftInstruction(left, right),
+ MUrsh(MDefinition* left, MDefinition* right, MIRType type)
+ : MShiftInstruction(left, right, type),
bailoutsDisabled_(false)
{ }
public:
INSTRUCTION_HEADER(Ursh)
static MUrsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
- static MUrsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
+ static MUrsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+ MIRType type);
MDefinition* foldIfZero(size_t operand) override {
// 0 >>> x => 0
if (operand == 0)
return getOperand(0);
return this;
}
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -688,16 +688,18 @@ class MacroAssembler : public MacroAssem
inline void and32(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64);
inline void and32(Imm32 imm, const Address& dest) PER_SHARED_ARCH;
inline void and32(const Address& src, Register dest) PER_SHARED_ARCH;
inline void andPtr(Register src, Register dest) PER_ARCH;
inline void andPtr(Imm32 imm, Register dest) PER_ARCH;
inline void and64(Imm64 imm, Register64 dest) PER_ARCH;
+ inline void or64(Imm64 imm, Register64 dest) PER_ARCH;
+ inline void xor64(Imm64 imm, Register64 dest) PER_ARCH;
inline void or32(Register src, Register dest) PER_SHARED_ARCH;
inline void or32(Imm32 imm, Register dest) PER_SHARED_ARCH;
inline void or32(Imm32 imm, const Address& dest) PER_SHARED_ARCH;
inline void orPtr(Register src, Register dest) PER_ARCH;
inline void orPtr(Imm32 imm, Register dest) PER_ARCH;
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -628,18 +628,23 @@ Range::Range(const MDefinition* def)
}
}
// As a special case, MUrsh is permitted to claim a result type of
// MIRType_Int32 while actually returning values in [0,UINT32_MAX] without
// bailouts. If range analysis hasn't ruled out values in
// (INT32_MAX,UINT32_MAX], set the range to be conservatively correct for
// use as either a uint32 or an int32.
- if (!hasInt32UpperBound() && def->isUrsh() && def->toUrsh()->bailoutsDisabled())
+ if (!hasInt32UpperBound() &&
+ def->isUrsh() &&
+ def->toUrsh()->bailoutsDisabled() &&
+ def->type() != MIRType_Int64)
+ {
lower_ = INT32_MIN;
+ }
assertInvariants();
}
static uint16_t
ExponentImpliedByDouble(double d)
{
// Handle the special values.
@@ -1311,38 +1316,47 @@ void
MClampToUint8::computeRange(TempAllocator& alloc)
{
setRange(Range::NewUInt32Range(alloc, 0, 255));
}
void
MBitAnd::computeRange(TempAllocator& alloc)
{
+ if (specialization_ == MIRType_Int64)
+ return;
+
Range left(getOperand(0));
Range right(getOperand(1));
left.wrapAroundToInt32();
right.wrapAroundToInt32();
setRange(Range::and_(alloc, &left, &right));
}
void
MBitOr::computeRange(TempAllocator& alloc)
{
+ if (specialization_ == MIRType_Int64)
+ return;
+
Range left(getOperand(0));
Range right(getOperand(1));
left.wrapAroundToInt32();
right.wrapAroundToInt32();
setRange(Range::or_(alloc, &left, &right));
}
void
MBitXor::computeRange(TempAllocator& alloc)
{
+ if (specialization_ == MIRType_Int64)
+ return;
+
Range left(getOperand(0));
Range right(getOperand(1));
left.wrapAroundToInt32();
right.wrapAroundToInt32();
setRange(Range::xor_(alloc, &left, &right));
}
@@ -1353,16 +1367,19 @@ MBitNot::computeRange(TempAllocator& all
op.wrapAroundToInt32();
setRange(Range::not_(alloc, &op));
}
void
MLsh::computeRange(TempAllocator& alloc)
{
+ if (specialization_ == MIRType_Int64)
+ return;
+
Range left(getOperand(0));
Range right(getOperand(1));
left.wrapAroundToInt32();
MConstant* rhsConst = getOperand(1)->maybeConstantValue();
if (rhsConst && rhsConst->type() == MIRType_Int32) {
int32_t c = rhsConst->toInt32();
setRange(Range::lsh(alloc, &left, c));
@@ -1371,16 +1388,19 @@ MLsh::computeRange(TempAllocator& alloc)
right.wrapAroundToShiftCount();
setRange(Range::lsh(alloc, &left, &right));
}
void
MRsh::computeRange(TempAllocator& alloc)
{
+ if (specialization_ == MIRType_Int64)
+ return;
+
Range left(getOperand(0));
Range right(getOperand(1));
left.wrapAroundToInt32();
MConstant* rhsConst = getOperand(1)->maybeConstantValue();
if (rhsConst && rhsConst->type() == MIRType_Int32) {
int32_t c = rhsConst->toInt32();
setRange(Range::rsh(alloc, &left, c));
@@ -1389,16 +1409,19 @@ MRsh::computeRange(TempAllocator& alloc)
right.wrapAroundToShiftCount();
setRange(Range::rsh(alloc, &left, &right));
}
void
MUrsh::computeRange(TempAllocator& alloc)
{
+ if (specialization_ == MIRType_Int64)
+ return;
+
Range left(getOperand(0));
Range right(getOperand(1));
// ursh can be thought of as converting its left operand to uint32, or it
// can be thought of as converting its left operand to int32, and then
// reinterpreting the int32 bits as a uint32 value. Both approaches yield
// the same result. Since we lack support for full uint32 ranges, we use
// the second interpretation, though it does cause us to be conservative.
@@ -3318,16 +3341,19 @@ MPowHalf::collectRangeInfoPreTrunc()
operandIsNeverNegativeZero_ = true;
if (!inputRange.canBeNaN())
operandIsNeverNaN_ = true;
}
void
MUrsh::collectRangeInfoPreTrunc()
{
+ if (specialization_ == MIRType_Int64)
+ return;
+
Range lhsRange(lhs()), rhsRange(rhs());
// As in MUrsh::computeRange(), convert the inputs.
lhsRange.wrapAroundToInt32();
rhsRange.wrapAroundToShiftCount();
// If the most significant bit of our result is always going to be zero,
// we can optimize by disabling bailout checks for enforcing an int32 range.
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -159,16 +159,23 @@ LIRGeneratorARM::lowerForALU(LInstructio
// MulI, but only for bail out paths so useAtStart when no bailouts.
ins->setOperand(0, ins->snapshot() ? useRegister(lhs) : useRegisterAtStart(lhs));
ins->setOperand(1, ins->snapshot() ? useRegisterOrConstant(rhs) :
useRegisterOrConstantAtStart(rhs));
define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
}
void
+LIRGeneratorARM::lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
+{
+ MOZ_CRASH("NYI");
+}
+
+void
LIRGeneratorARM::lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir, MDefinition* input)
{
ins->setOperand(0, useRegisterAtStart(input));
define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
}
template<size_t Temps>
void
@@ -226,16 +233,23 @@ void
LIRGeneratorARM::lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
{
ins->setOperand(0, useRegister(lhs));
ins->setOperand(1, useRegisterOrConstant(rhs));
define(ins, mir);
}
void
+LIRGeneratorARM::lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
+{
+ MOZ_CRASH("NYI");
+}
+
+void
LIRGeneratorARM::lowerDivI(MDiv* div)
{
if (div->isUnsigned()) {
lowerUDiv(div);
return;
}
// Division instructions are slow. Division by constant denominators can be
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -42,16 +42,21 @@ class LIRGeneratorARM : public LIRGenera
MDefinition* rhs);
void lowerUrshD(MUrsh* mir);
void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
MDefinition* input);
void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs);
+ void lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins, MDefinition* mir,
+ MDefinition* lhs, MDefinition* rhs);
+ void lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
+
void lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
MDefinition* src);
template<size_t Temps>
void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs);
void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir,
MDefinition* lhs, MDefinition* rhs)
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -81,16 +81,30 @@ MacroAssembler::andPtr(Imm32 imm, Regist
void
MacroAssembler::and64(Imm64 imm, Register64 dest)
{
and32(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
and32(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
}
void
+MacroAssembler::or64(Imm64 imm, Register64 dest)
+{
+ or32(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
+ or32(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
+}
+
+void
+MacroAssembler::xor64(Imm64 imm, Register64 dest)
+{
+ xor32(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
+ xor32(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
+}
+
+void
MacroAssembler::or32(Register src, Register dest)
{
ma_orr(src, dest);
}
void
MacroAssembler::or32(Imm32 imm, Register dest)
{
--- a/js/src/jit/arm64/Lowering-arm64.cpp
+++ b/js/src/jit/arm64/Lowering-arm64.cpp
@@ -83,16 +83,30 @@ LIRGeneratorARM64::lowerForFPU(LInstruct
}
template void LIRGeneratorARM64::lowerForFPU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs);
template void LIRGeneratorARM64::lowerForFPU(LInstructionHelper<1, 2, 1>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs);
void
+LIRGeneratorARM64::lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
+{
+ MOZ_CRASH("NYI");
+}
+
+void
+LIRGeneratorARM64::lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
+{
+ MOZ_CRASH("NYI");
+}
+
+void
LIRGeneratorARM64::lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
MDefinition* lhs, MDefinition* rhs)
{
MOZ_CRASH("lowerForBitAndAndBranch");
}
void
LIRGeneratorARM64::defineUntypedPhi(MPhi* phi, size_t lirIndex)
--- a/js/src/jit/arm64/Lowering-arm64.h
+++ b/js/src/jit/arm64/Lowering-arm64.h
@@ -43,16 +43,21 @@ class LIRGeneratorARM64 : public LIRGene
void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
MDefinition* rhs);
void lowerUrshD(MUrsh* mir);
void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir, MDefinition* input);
void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs);
+ void lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins, MDefinition* mir,
+ MDefinition* lhs, MDefinition* rhs);
+ void lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
+
void lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir, MDefinition* input);
template <size_t Temps>
void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs);
void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir,
MDefinition* lhs, MDefinition* rhs)
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -91,16 +91,34 @@ MacroAssembler::and64(Imm64 imm, Registe
{
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
mov(ImmWord(imm.value), scratch);
andPtr(scratch, dest.reg);
}
void
+MacroAssembler::or64(Imm64 imm, Register64 dest)
+{
+ vixl::UseScratchRegisterScope temps(this);
+ const Register scratch = temps.AcquireX().asUnsized();
+ mov(ImmWord(imm.value), scratch);
+ orPtr(scratch, dest.reg);
+}
+
+void
+MacroAssembler::xor64(Imm64 imm, Register64 dest)
+{
+ vixl::UseScratchRegisterScope temps(this);
+ const Register scratch = temps.AcquireX().asUnsized();
+ mov(ImmWord(imm.value), scratch);
+ xorPtr(scratch, dest.reg);
+}
+
+void
MacroAssembler::or32(Imm32 imm, Register dest)
{
Orr(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value));
}
void
MacroAssembler::or32(Register src, Register dest)
{
--- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -50,16 +50,30 @@ LIRGeneratorMIPSShared::lowerForALU(LIns
MDefinition* lhs, MDefinition* rhs)
{
ins->setOperand(0, useRegister(lhs));
ins->setOperand(1, useRegisterOrConstant(rhs));
define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
}
void
+LIRGeneratorMIPSShared::lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
+{
+ MOZ_CRASH("NYI");
+}
+
+void
+LIRGeneratorMIPSShared::lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
+{
+ MOZ_CRASH("NYI");
+}
+
+void
LIRGeneratorMIPSShared::lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
MDefinition* input)
{
ins->setOperand(0, useRegister(input));
define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
}
template<size_t Temps>
--- a/js/src/jit/mips-shared/Lowering-mips-shared.h
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.h
@@ -32,16 +32,21 @@ class LIRGeneratorMIPSShared : public LI
MDefinition* rhs);
void lowerUrshD(MUrsh* mir);
void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
MDefinition* input);
void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs);
+ void lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins, MDefinition* mir,
+ MDefinition* lhs, MDefinition* rhs);
+ void lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
+
void lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
MDefinition* src);
template<size_t Temps>
void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs);
void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir,
MDefinition* lhs, MDefinition* rhs)
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -48,16 +48,30 @@ MacroAssembler::andPtr(Imm32 imm, Regist
void
MacroAssembler::and64(Imm64 imm, Register64 dest)
{
and32(Imm32(imm.value & LOW_32_MASK), dest.low);
and32(Imm32((imm.value >> 32) & LOW_32_MASK), dest.high);
}
void
+MacroAssembler::or64(Imm64 imm, Register64 dest)
+{
+ or32(Imm32(imm.value & LOW_32_MASK), dest.low);
+ or32(Imm32((imm.value >> 32) & LOW_32_MASK), dest.high);
+}
+
+void
+MacroAssembler::xor64(Imm64 imm, Register64 dest)
+{
+ xor32(Imm32(imm.value & LOW_32_MASK), dest.low);
+ xor32(Imm32((imm.value >> 32) & LOW_32_MASK), dest.high);
+}
+
+void
MacroAssembler::orPtr(Register src, Register dest)
{
ma_or(dest, src);
}
void
MacroAssembler::orPtr(Imm32 imm, Register dest)
{
--- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h
@@ -46,16 +46,30 @@ MacroAssembler::andPtr(Imm32 imm, Regist
void
MacroAssembler::and64(Imm64 imm, Register64 dest)
{
ma_li(ScratchRegister, ImmWord(imm.value));
ma_and(dest.reg, ScratchRegister);
}
void
+MacroAssembler::or64(Imm64 imm, Register64 dest)
+{
+ ma_li(ScratchRegister, ImmWord(imm.value));
+ ma_or(dest.reg, ScratchRegister);
+}
+
+void
+MacroAssembler::xor64(Imm64 imm, Register64 dest)
+{
+ ma_li(ScratchRegister, ImmWord(imm.value));
+ ma_xor(dest.reg, ScratchRegister);
+}
+
+void
MacroAssembler::orPtr(Register src, Register dest)
{
ma_or(dest, src);
}
void
MacroAssembler::orPtr(Imm32 imm, Register dest)
{
--- a/js/src/jit/none/Lowering-none.h
+++ b/js/src/jit/none/Lowering-none.h
@@ -33,16 +33,20 @@ class LIRGeneratorNone : public LIRGener
void lowerForShift(LInstructionHelper<1, 2, 0>*, MDefinition*, MDefinition*, MDefinition*) {
MOZ_CRASH();
}
void lowerUrshD(MUrsh*) { MOZ_CRASH(); }
template <typename T>
void lowerForALU(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) { MOZ_CRASH(); }
template <typename T>
void lowerForFPU(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) { MOZ_CRASH(); }
+ template <typename T>
+ void lowerForALUInt64(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) { MOZ_CRASH(); }
+ template <typename T>
+ void lowerForShiftInt64(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) { MOZ_CRASH(); }
void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir,
MDefinition* lhs, MDefinition* rhs) {
MOZ_CRASH();
}
void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir,
MDefinition* lhs, MDefinition* rhs) {
MOZ_CRASH();
}
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -2943,16 +2943,39 @@ class LBitOpI : public LInstructionHelpe
return CodeName[op_];
}
JSOp bitop() const {
return op_;
}
};
+class LBitOpI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>
+{
+ JSOp op_;
+
+ public:
+ LIR_HEADER(BitOpI64)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ explicit LBitOpI64(JSOp op)
+ : op_(op)
+ { }
+
+ const char* extraName() const {
+ return CodeName[op_];
+ }
+
+ JSOp bitop() const {
+ return op_;
+ }
+};
+
// Call a VM function to perform a bitwise operation.
class LBitOpV : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0>
{
JSOp jsop_;
public:
LIR_HEADER(BitOpV)
@@ -2996,16 +3019,40 @@ class LShiftI : public LBinaryMath<0>
return mir_->toInstruction();
}
const char* extraName() const {
return CodeName[op_];
}
};
+class LShiftI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>
+{
+ JSOp op_;
+
+ public:
+ LIR_HEADER(ShiftI64)
+
+ explicit LShiftI64(JSOp op)
+ : op_(op)
+ { }
+
+ JSOp bitop() {
+ return op_;
+ }
+
+ MInstruction* mir() {
+ return mir_->toInstruction();
+ }
+
+ const char* extraName() const {
+ return CodeName[op_];
+ }
+};
+
class LUrshD : public LBinaryMath<1>
{
public:
LIR_HEADER(UrshD)
LUrshD(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& temp) {
setOperand(0, lhs);
setOperand(1, rhs);
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -92,18 +92,20 @@
_(CreateArgumentsObject) \
_(GetArgumentsObjectArg) \
_(SetArgumentsObjectArg) \
_(ReturnFromCtor) \
_(ComputeThis) \
_(BitNotI) \
_(BitNotV) \
_(BitOpI) \
+ _(BitOpI64) \
_(BitOpV) \
_(ShiftI) \
+ _(ShiftI64) \
_(UrshD) \
_(Return) \
_(Throw) \
_(Phi) \
_(TestIAndBranch) \
_(TestDAndBranch) \
_(TestFAndBranch) \
_(TestVAndBranch) \
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -24,16 +24,17 @@ LIRGeneratorShared::emitAtUses(MInstruct
}
LUse
LIRGeneratorShared::use(MDefinition* mir, LUse policy)
{
// It is illegal to call use() on an instruction with two defs.
#if BOX_PIECES > 1
MOZ_ASSERT(mir->type() != MIRType_Value);
+ MOZ_ASSERT(mir->type() != MIRType_Int64);
#endif
ensureDefined(mir);
policy.setVirtualRegister(mir->virtualRegister());
return policy;
}
template <size_t X> void
LIRGeneratorShared::define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir,
@@ -82,21 +83,51 @@ LIRGeneratorShared::defineReuseInput(LIn
LDefinition def(type, LDefinition::MUST_REUSE_INPUT);
def.setReusedInput(operand);
define(lir, mir, def);
}
template <size_t Ops, size_t Temps> void
+LIRGeneratorShared::defineInt64ReuseInput(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir,
+ MDefinition* mir, uint32_t operand)
+{
+ // The input should be used at the start of the instruction, to avoid moves.
+ MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart());
+ MOZ_ASSERT(!lir->isCall());
+
+ uint32_t vreg = getVirtualRegister();
+
+ LDefinition def1(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT);
+ def1.setReusedInput(operand);
+ lir->setDef(0, def1);
+ lir->getDef(0)->setVirtualRegister(vreg);
+
+#if JS_BITS_PER_WORD == 32
+ getVirtualRegister();
+ LDefinition def2(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT);
+ def2.setReusedInput(operand + 1);
+ lir->setDef(1, def2);
+ lir->getDef(1)->setVirtualRegister(vreg + 1);
+#endif
+
+ lir->setMir(mir);
+ mir->setVirtualRegister(vreg);
+ add(lir);
+
+}
+
+template <size_t Ops, size_t Temps> void
LIRGeneratorShared::defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps>* lir, MDefinition* mir,
LDefinition::Policy policy)
{
// Call instructions should use defineReturn.
MOZ_ASSERT(!lir->isCall());
+ MOZ_ASSERT(mir->type() == MIRType_Value);
uint32_t vreg = getVirtualRegister();
#if defined(JS_NUNBOX32)
lir->setDef(0, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy));
lir->setDef(1, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy));
getVirtualRegister();
#elif defined(JS_PUNBOX64)
@@ -109,16 +140,17 @@ LIRGeneratorShared::defineBox(LInstructi
}
template <size_t Ops, size_t Temps> void
LIRGeneratorShared::defineInt64(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir,
LDefinition::Policy policy)
{
// Call instructions should use defineReturn.
MOZ_ASSERT(!lir->isCall());
+ MOZ_ASSERT(mir->type() == MIRType_Int64);
uint32_t vreg = getVirtualRegister();
#if JS_BITS_PER_WORD == 32
lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, policy));
lir->setDef(1, LDefinition(vreg + 1, LDefinition::GENERAL, policy));
getVirtualRegister();
#else
@@ -676,41 +708,41 @@ LIRGeneratorShared::useInt64(MDefinition
return LInt64Allocation(LUse(vreg + 1, policy, useAtStart),
LUse(vreg, policy, useAtStart));
#else
return LInt64Allocation(LUse(vreg, policy, useAtStart));
#endif
}
LInt64Allocation
-LIRGeneratorShared::useInt64(MDefinition* mir)
+LIRGeneratorShared::useInt64(MDefinition* mir, bool useAtStart)
{
// On 32-bit platforms, always load the value in registers.
#if JS_BITS_PER_WORD == 32
- return useInt64(mir, LUse::REGISTER, /* useAtStart = */ false);
+ return useInt64(mir, LUse::REGISTER, useAtStart);
#else
- return useInt64(mir, LUse::ANY, /* useAtStart = */ false);
+ return useInt64(mir, LUse::ANY, useAtStart);
#endif
}
LInt64Allocation
LIRGeneratorShared::useInt64Register(MDefinition* mir, bool useAtStart)
{
return useInt64(mir, LUse::REGISTER, useAtStart);
}
LInt64Allocation
-LIRGeneratorShared::useInt64OrConstant(MDefinition* mir)
+LIRGeneratorShared::useInt64OrConstant(MDefinition* mir, bool useAtStart)
{
if (mir->isConstant()) {
#if defined(JS_NUNBOX32)
return LInt64Allocation(LAllocation(mir->toConstant()), LAllocation());
#else
return LInt64Allocation(LAllocation(mir->toConstant()));
#endif
}
- return useInt64(mir);
+ return useInt64(mir, useAtStart);
}
} // namespace jit
} // namespace js
#endif /* jit_shared_Lowering_shared_inl_h */
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -158,30 +158,41 @@ class LIRGeneratorShared : public MDefin
LDefinition::Policy policy = LDefinition::REGISTER);
template <size_t X>
inline void define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir,
const LDefinition& def);
template <size_t Ops, size_t Temps>
inline void defineReuseInput(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir, uint32_t operand);
+ template <size_t Ops, size_t Temps>
+ inline void defineInt64ReuseInput(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir,
+ MDefinition* mir, uint32_t operand);
+
// Returns a box allocation for a Value-typed instruction.
inline LBoxAllocation useBox(MDefinition* mir, LUse::Policy policy = LUse::REGISTER,
bool useAtStart = false);
// Returns a box allocation. The use is either typed, a Value, or
// a constant (if useConstant is true).
inline LBoxAllocation useBoxOrTypedOrConstant(MDefinition* mir, bool useConstant);
// Returns an int64 allocation for an Int64-typed instruction.
inline LInt64Allocation useInt64(MDefinition* mir, LUse::Policy policy, bool useAtStart);
- inline LInt64Allocation useInt64(MDefinition* mir);
- inline LInt64Allocation useInt64OrConstant(MDefinition* mir);
+ inline LInt64Allocation useInt64(MDefinition* mir, bool useAtStart = false);
+ inline LInt64Allocation useInt64OrConstant(MDefinition* mir, bool useAtStart = false);
inline LInt64Allocation useInt64Register(MDefinition* mir, bool useAtStart = false);
+ LInt64Allocation useInt64RegisterAtStart(MDefinition* mir) {
+ return useInt64Register(mir, /* useAtStart = */ true);
+ }
+ LInt64Allocation useInt64OrConstantAtStart(MDefinition* mir) {
+ return useInt64OrConstant(mir, /* useAtStart = */ true);
+ }
+
// Rather than defining a new virtual register, sets |ins| to have the same
// virtual register as |as|.
inline void redefine(MDefinition* ins, MDefinition* as);
// Redefine a sin/cos call to sincos.
inline void redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func);
TempAllocator& alloc() const {
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -557,16 +557,25 @@ class Assembler : public AssemblerX86Sha
masm.shlq_ir(imm.value, dest.encoding());
}
void shrq(Imm32 imm, Register dest) {
masm.shrq_ir(imm.value, dest.encoding());
}
void sarq(Imm32 imm, Register dest) {
masm.sarq_ir(imm.value, dest.encoding());
}
+ void shlq_cl(Register dest) {
+ masm.shlq_CLr(dest.encoding());
+ }
+ void shrq_cl(Register dest) {
+ masm.shrq_CLr(dest.encoding());
+ }
+ void sarq_cl(Register dest) {
+ masm.sarq_CLr(dest.encoding());
+ }
void orq(Imm32 imm, Register dest) {
masm.orq_ir(imm.value, dest.encoding());
}
void orq(Register src, Register dest) {
masm.orq_rr(src.encoding(), dest.encoding());
}
void orq(const Operand& src, Register dest) {
switch (src.kind()) {
@@ -584,16 +593,31 @@ class Assembler : public AssemblerX86Sha
}
}
void xorq(Register src, Register dest) {
masm.xorq_rr(src.encoding(), dest.encoding());
}
void xorq(Imm32 imm, Register dest) {
masm.xorq_ir(imm.value, dest.encoding());
}
+ void xorq(const Operand& src, Register dest) {
+ switch (src.kind()) {
+ case Operand::REG:
+ masm.xorq_rr(src.reg(), dest.encoding());
+ break;
+ case Operand::MEM_REG_DISP:
+ masm.xorq_mr(src.disp(), src.base(), dest.encoding());
+ break;
+ case Operand::MEM_ADDRESS32:
+ masm.xorq_mr(src.address(), dest.encoding());
+ break;
+ default:
+ MOZ_CRASH("unexpected operand kind");
+ }
+ }
void imulq(Register src, Register dest) {
masm.imulq_rr(src.encoding(), dest.encoding());
}
void vcvtsi2sdq(Register src, FloatRegister dest) {
masm.vcvtsi2sdq_rr(src.encoding(), dest.encoding());
}
--- a/js/src/jit/x64/BaseAssembler-x64.h
+++ b/js/src/jit/x64/BaseAssembler-x64.h
@@ -108,16 +108,28 @@ class BaseAssemblerX64 : public BaseAsse
}
void orq_mr(const void* addr, RegisterID dst)
{
spew("orq %p, %s", addr, GPReg64Name(dst));
m_formatter.oneByteOp64(OP_OR_GvEv, addr, dst);
}
+ void xorq_mr(int32_t offset, RegisterID base, RegisterID dst)
+ {
+ spew("xorq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst));
+ m_formatter.oneByteOp64(OP_XOR_GvEv, offset, base, dst);
+ }
+
+ void xorq_mr(const void* addr, RegisterID dst)
+ {
+ spew("xorq %p, %s", addr, GPReg64Name(dst));
+ m_formatter.oneByteOp64(OP_XOR_GvEv, addr, dst);
+ }
+
void andq_ir(int32_t imm, RegisterID dst)
{
spew("andq $0x%" PRIx64 ", %s", int64_t(imm), GPReg64Name(dst));
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_AND);
m_formatter.immediate8s(imm);
} else {
if (dst == rax)
@@ -222,16 +234,28 @@ class BaseAssemblerX64 : public BaseAsse
}
void sarq_CLr(RegisterID dst)
{
spew("sarq %%cl, %s", GPReg64Name(dst));
m_formatter.oneByteOp64(OP_GROUP2_EvCL, dst, GROUP2_OP_SAR);
}
+ void shlq_CLr(RegisterID dst)
+ {
+ spew("shlq %%cl, %s", GPReg64Name(dst));
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, dst, GROUP2_OP_SHL);
+ }
+
+ void shrq_CLr(RegisterID dst)
+ {
+ spew("shrq %%cl, %s", GPReg64Name(dst));
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, dst, GROUP2_OP_SHR);
+ }
+
void sarq_ir(int32_t imm, RegisterID dst)
{
MOZ_ASSERT(imm < 64);
spew("sarq $%d, %s", imm, GPReg64Name(dst));
if (imm == 1)
m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_SAR);
else {
m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_SAR);
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -245,16 +245,88 @@ CodeGeneratorX64::visitCompare64AndBranc
else
masm.cmpPtr(lhs, ToOperand(rhs));
bool isSigned = mir->compareType() == MCompare::Compare_Int64;
emitBranch(JSOpToCondition(lir->jsop(), isSigned), lir->ifTrue(), lir->ifFalse());
}
void
+CodeGeneratorX64::visitBitOpI64(LBitOpI64* lir)
+{
+ Register lhs = ToRegister(lir->getOperand(0));
+ const LAllocation* rhs = lir->getOperand(1);
+
+ switch (lir->bitop()) {
+ case JSOP_BITOR:
+ if (rhs->isConstant())
+ masm.or64(Imm64(ToInt64(rhs)), Register64(lhs));
+ else
+ masm.orq(ToOperand(rhs), lhs);
+ break;
+ case JSOP_BITXOR:
+ if (rhs->isConstant())
+ masm.xor64(Imm64(ToInt64(rhs)), Register64(lhs));
+ else
+ masm.xorq(ToOperand(rhs), lhs);
+ break;
+ case JSOP_BITAND:
+ if (rhs->isConstant())
+ masm.and64(Imm64(ToInt64(rhs)), Register64(lhs));
+ else
+ masm.andq(ToOperand(rhs), lhs);
+ break;
+ default:
+ MOZ_CRASH("unexpected binary opcode");
+ }
+}
+
+void
+CodeGeneratorX64::visitShiftI64(LShiftI64* lir)
+{
+ Register lhs = ToRegister(lir->getOperand(0));
+ const LAllocation* rhs = lir->getOperand(1);
+
+ if (rhs->isConstant()) {
+ int32_t shift = ToInt32(rhs) & 0x3F;
+ switch (lir->bitop()) {
+ case JSOP_LSH:
+ if (shift)
+ masm.shlq(Imm32(shift), lhs);
+ break;
+ case JSOP_RSH:
+ if (shift)
+ masm.sarq(Imm32(shift), lhs);
+ break;
+ case JSOP_URSH:
+ if (shift)
+ masm.shrq(Imm32(shift), lhs);
+ break;
+ default:
+ MOZ_CRASH("Unexpected shift op");
+ }
+ } else {
+ MOZ_ASSERT(ToRegister(rhs) == ecx);
+ switch (lir->bitop()) {
+ case JSOP_LSH:
+ masm.shlq_cl(lhs);
+ break;
+ case JSOP_RSH:
+ masm.sarq_cl(lhs);
+ break;
+ case JSOP_URSH:
+ masm.shrq_cl(lhs);
+ break;
+ default:
+ MOZ_CRASH("Unexpected shift op");
+ }
+ }
+}
+
+void
CodeGeneratorX64::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir)
{
masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
}
void
CodeGeneratorX64::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir)
{
--- a/js/src/jit/x64/CodeGenerator-x64.h
+++ b/js/src/jit/x64/CodeGenerator-x64.h
@@ -39,16 +39,18 @@ class CodeGeneratorX64 : public CodeGene
void visitBox(LBox* box);
void visitUnbox(LUnbox* unbox);
void visitCompareB(LCompareB* lir);
void visitCompareBAndBranch(LCompareBAndBranch* lir);
void visitCompareBitwise(LCompareBitwise* lir);
void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir);
void visitCompare64(LCompare64* lir);
void visitCompare64AndBranch(LCompare64AndBranch* lir);
+ void visitBitOpI64(LBitOpI64* lir);
+ void visitShiftI64(LShiftI64* lir);
void visitTruncateDToInt32(LTruncateDToInt32* ins);
void visitTruncateFToInt32(LTruncateFToInt32* ins);
void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins);
void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins);
void visitAsmJSCall(LAsmJSCall* ins);
void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);
void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins);
--- a/js/src/jit/x64/MacroAssembler-x64-inl.h
+++ b/js/src/jit/x64/MacroAssembler-x64-inl.h
@@ -39,18 +39,47 @@ void
MacroAssembler::andPtr(Imm32 imm, Register dest)
{
andq(imm, dest);
}
void
MacroAssembler::and64(Imm64 imm, Register64 dest)
{
- movq(ImmWord(uintptr_t(imm.value)), ScratchReg);
- andq(ScratchReg, dest.reg);
+ if (INT32_MIN <= int64_t(imm.value) && int64_t(imm.value) <= INT32_MAX) {
+ andq(Imm32(imm.value), dest.reg);
+ } else {
+ ScratchRegisterScope scratch(*this);
+ movq(ImmWord(uintptr_t(imm.value)), scratch);
+ andq(scratch, dest.reg);
+ }
+}
+
+void
+MacroAssembler::or64(Imm64 imm, Register64 dest)
+{
+ if (INT32_MIN <= int64_t(imm.value) && int64_t(imm.value) <= INT32_MAX) {
+ orq(Imm32(imm.value), dest.reg);
+ } else {
+ ScratchRegisterScope scratch(*this);
+ movq(ImmWord(uintptr_t(imm.value)), scratch);
+ orq(scratch, dest.reg);
+ }
+}
+
+void
+MacroAssembler::xor64(Imm64 imm, Register64 dest)
+{
+ if (INT32_MIN <= int64_t(imm.value) && int64_t(imm.value) <= INT32_MAX) {
+ xorq(Imm32(imm.value), dest.reg);
+ } else {
+ ScratchRegisterScope scratch(*this);
+ movq(ImmWord(uintptr_t(imm.value)), scratch);
+ xorq(scratch, dest.reg);
+ }
}
void
MacroAssembler::orPtr(Register src, Register dest)
{
orq(src, dest);
}
--- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp
@@ -76,32 +76,66 @@ LIRGeneratorX86Shared::lowerForShift(LIn
ins->setOperand(1, useOrConstantAtStart(rhs));
else
ins->setOperand(1, lhs != rhs ? useFixed(rhs, ecx) : useFixedAtStart(rhs, ecx));
defineReuseInput(ins, mir, 0);
}
void
+LIRGeneratorX86Shared::lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
+{
+ ins->setInt64Operand(0, useInt64RegisterAtStart(lhs));
+
+ // shift operator should be constant or in register ecx
+ // x86 can't shift a non-ecx register
+ if (rhs->isConstant()) {
+ ins->setOperand(INT64_PIECES, useOrConstantAtStart(rhs));
+ } else {
+ // The operands are int64, but we only care about the lower 32 bits of
+ // the RHS. On 32-bit, the code below will load that part in ecx and
+ // will discard the upper half.
+ ensureDefined(rhs);
+ bool useAtStart = (lhs == rhs);
+ LUse use(ecx, useAtStart);
+ use.setVirtualRegister(rhs->virtualRegister());
+ ins->setOperand(INT64_PIECES, use);
+ }
+
+ defineInt64ReuseInput(ins, mir, 0);
+}
+
+void
LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
MDefinition* input)
{
ins->setOperand(0, useRegisterAtStart(input));
defineReuseInput(ins, mir, 0);
}
void
LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
MDefinition* lhs, MDefinition* rhs)
{
ins->setOperand(0, useRegisterAtStart(lhs));
ins->setOperand(1, lhs != rhs ? useOrConstant(rhs) : useOrConstantAtStart(rhs));
defineReuseInput(ins, mir, 0);
}
+void
+LIRGeneratorX86Shared::lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
+{
+ ins->setInt64Operand(0, useInt64RegisterAtStart(lhs));
+ ins->setInt64Operand(INT64_PIECES,
+ lhs != rhs ? useInt64OrConstant(rhs) : useInt64OrConstantAtStart(rhs));
+ defineInt64ReuseInput(ins, mir, 0);
+}
+
template<size_t Temps>
void
LIRGeneratorX86Shared::lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
{
// Without AVX, we'll need to use the x86 encodings where one of the
// inputs must be the same location as the output.
//
// :TODO: (Bug 1132894) Note, we might have to allocate a different
--- a/js/src/jit/x86-shared/Lowering-x86-shared.h
+++ b/js/src/jit/x86-shared/Lowering-x86-shared.h
@@ -26,16 +26,22 @@ class LIRGeneratorX86Shared : public LIR
void visitGuardShape(MGuardShape* ins);
void visitGuardObjectGroup(MGuardObjectGroup* ins);
void visitPowHalf(MPowHalf* ins);
void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
MDefinition* rhs);
void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir, MDefinition* input);
void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
MDefinition* rhs);
+
+ void lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins, MDefinition* mir,
+ MDefinition* lhs, MDefinition* rhs);
+ void lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>* ins,
+ MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
+
template<size_t Temps>
void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir, MDefinition* lhs,
MDefinition* rhs);
void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir,
MDefinition* lhs, MDefinition* rhs);
void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir,
MDefinition* lhs, MDefinition* rhs);
void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -48,16 +48,30 @@ MacroAssembler::andPtr(Imm32 imm, Regist
void
MacroAssembler::and64(Imm64 imm, Register64 dest)
{
andl(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
andl(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
}
void
+MacroAssembler::or64(Imm64 imm, Register64 dest)
+{
+ orl(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
+ orl(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
+}
+
+void
+MacroAssembler::xor64(Imm64 imm, Register64 dest)
+{
+ xorl(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
+ xorl(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
+}
+
+void
MacroAssembler::orPtr(Register src, Register dest)
{
orl(src, dest);
}
void
MacroAssembler::orPtr(Imm32 imm, Register dest)
{