Bug 1289054 - Part 24: Make WebAssembly ready to run 64bit instructions on arm, r=luke
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:53:50 +0200
changeset 349443 0f0fe678a40ae291bf1ee4baec03da61e63635cf
parent 349442 1449099f1906015dd12a8b488a7f426f5b6b4c52
child 349444 5b6fd86e965ec386e93ac060375dd8639bd99944
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1289054
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1289054 - Part 24: Make WebAssembly ready to run 64bit instructions on arm, r=luke
js/src/asmjs/WasmIonCompile.cpp
js/src/asmjs/WasmJS.cpp
js/src/asmjs/WasmStubs.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/RegisterSets.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/shared/LIR-shared.h
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x86/CodeGenerator-x86.cpp
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -812,22 +812,38 @@ class FunctionCompiler
     }
 
     bool passArg(MDefinition* argDef, ValType type, CallArgs* args)
     {
         if (inDeadCode())
             return true;
 
         ABIArg arg = args->abi_.next(ToMIRType(type));
-        if (arg.kind() != ABIArg::Stack)
+        switch (arg.kind()) {
+#ifdef JS_CODEGEN_REGISTER_PAIR
+          case ABIArg::GPR_PAIR: {
+            auto mirLow = MWrapInt64ToInt32::NewAsmJS(alloc(), argDef, /* bottomHalf = */ true);
+            curBlock_->add(mirLow);
+            auto mirHigh = MWrapInt64ToInt32::NewAsmJS(alloc(), argDef, /* bottomHalf = */ false);
+            curBlock_->add(mirHigh);
+            return args->regArgs_.append(MAsmJSCall::Arg(AnyRegister(arg.gpr64().low), mirLow)) &&
+                   args->regArgs_.append(MAsmJSCall::Arg(AnyRegister(arg.gpr64().high), mirHigh));
+          }
+#endif
+          case ABIArg::GPR:
+          case ABIArg::FPU:
             return args->regArgs_.append(MAsmJSCall::Arg(arg.reg(), argDef));
-
-        auto* mir = MAsmJSPassStackArg::New(alloc(), arg.offsetFromArgBase(), argDef);
-        curBlock_->add(mir);
-        return args->stackArgs_.append(mir);
+          case ABIArg::Stack: {
+            auto* mir = MAsmJSPassStackArg::New(alloc(), arg.offsetFromArgBase(), argDef);
+            curBlock_->add(mir);
+            return args->stackArgs_.append(mir);
+          }
+          default:
+            MOZ_CRASH("Unknown ABIArg kind.");
+        }
     }
 
     // Add the hidden TLS pointer argument to CallArgs, and assume that it will
     // be preserved by the call.
     bool passTlsPointer(CallArgs* args)
     {
         if (inDeadCode())
             return true;
--- a/js/src/asmjs/WasmJS.cpp
+++ b/js/src/asmjs/WasmJS.cpp
@@ -60,17 +60,17 @@ CheckCompilerSupport(JSContext* cx)
     }
 
     return true;
 }
 
 bool
 wasm::IsI64Implemented()
 {
-#if defined(JS_CPU_X64) || defined(JS_CODEGEN_X86)
+#if defined(JS_CPU_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
     return true;
 #else
     return false;
 #endif
 }
 
 // ============================================================================
 // (Temporary) Wasm class and static methods
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -186,17 +186,20 @@ wasm::GenerateEntry(MacroAssembler& masm
           case ABIArg::GPR:
             if (type == MIRType::Int32)
                 masm.load32(src, iter->gpr());
             else if (type == MIRType::Int64)
                 masm.load64(src, iter->gpr64());
             break;
 #ifdef JS_CODEGEN_REGISTER_PAIR
           case ABIArg::GPR_PAIR:
-            MOZ_CRASH("wasm uses hardfp for function calls.");
+            if (type == MIRType::Int64)
+                masm.load64(src, iter->gpr64());
+            else
+                MOZ_CRASH("wasm uses hardfp for function calls.");
             break;
 #endif
           case ABIArg::FPU: {
             static_assert(sizeof(ExportArg) >= jit::Simd128DataSize,
                           "ExportArg must be big enough to store SIMD values");
             switch (type) {
               case MIRType::Int8x16:
               case MIRType::Int16x8:
@@ -357,17 +360,20 @@ FillArgumentArray(MacroAssembler& masm, 
                 else
                     masm.store64(i->gpr64(), dstAddr);
             } else {
                 MOZ_CRASH("unexpected input type?");
             }
             break;
 #ifdef JS_CODEGEN_REGISTER_PAIR
           case ABIArg::GPR_PAIR:
-            MOZ_CRASH("AsmJS uses hardfp for function calls.");
+            if (type == MIRType::Int64)
+                masm.store64(i->gpr64(), dstAddr);
+            else
+                MOZ_CRASH("AsmJS uses hardfp for function calls.");
             break;
 #endif
           case ABIArg::FPU: {
             MOZ_ASSERT(IsFloatingPointType(type));
             FloatRegister srcReg = i->fpu();
             if (type == MIRType::Double) {
                 if (toValue) {
                     // Preserve the NaN pattern in the input.
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -4065,18 +4065,19 @@ MWasmTruncateToInt32::foldsTo(TempAlloca
     return this;
 }
 
 MDefinition*
 MWrapInt64ToInt32::foldsTo(TempAllocator& alloc)
 {
     MDefinition* input = this->input();
     if (input->isConstant()) {
-        int64_t c = input->toConstant()->toInt64();
-        return MConstant::New(alloc, Int32Value(int32_t(c)));
+        uint64_t c = input->toConstant()->toInt64();
+        int32_t output = bottomHalf() ? int32_t(c) : int32_t(c >> 32);
+        return MConstant::New(alloc, Int32Value(output));
     }
 
     return this;
 }
 
 MDefinition*
 MExtendInt32ToInt64::foldsTo(TempAllocator& alloc)
 {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5189,35 +5189,48 @@ class MAsmJSUnsignedToFloat32
 
     bool canProduceFloat32() const override { return true; }
 };
 
 class MWrapInt64ToInt32
   : public MUnaryInstruction,
     public NoTypePolicy::Data
 {
-    explicit MWrapInt64ToInt32(MDefinition* def)
-      : MUnaryInstruction(def)
+    bool bottomHalf_;
+
+    explicit MWrapInt64ToInt32(MDefinition* def, bool bottomHalf)
+      : MUnaryInstruction(def),
+        bottomHalf_(bottomHalf)
     {
         setResultType(MIRType::Int32);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(WrapInt64ToInt32)
-    static MWrapInt64ToInt32* NewAsmJS(TempAllocator& alloc, MDefinition* def) {
-        return new(alloc) MWrapInt64ToInt32(def);
+    static MWrapInt64ToInt32* NewAsmJS(TempAllocator& alloc, MDefinition* def,
+                                       bool bottomHalf = true)
+    {
+        return new(alloc) MWrapInt64ToInt32(def, bottomHalf);
     }
 
     MDefinition* foldsTo(TempAllocator& alloc) override;
     bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
+        if (!ins->isWrapInt64ToInt32())
+            return false;
+        if (ins->toWrapInt64ToInt32()->bottomHalf() != bottomHalf())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool bottomHalf() const {
+        return bottomHalf_;
     }
 };
 
 class MExtendInt32ToInt64
   : public MUnaryInstruction,
     public NoTypePolicy::Data
 {
     bool isUnsigned_;
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -1250,17 +1250,17 @@ class ABIArg
     Register gpr() const {
         MOZ_ASSERT(kind() == GPR);
         return Register::FromCode(u.gpr_);
     }
     Register64 gpr64() const {
 #ifdef JS_PUNBOX64
         return Register64(gpr());
 #else
-        MOZ_CRASH("NYI");
+        return Register64(oddGpr(), evenGpr());
 #endif
     }
     Register evenGpr() const {
         MOZ_ASSERT(isGeneralRegPair());
         return Register::FromCode(u.gpr_);
     }
     Register oddGpr() const {
         MOZ_ASSERT(isGeneralRegPair());
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -3249,17 +3249,20 @@ CodeGeneratorARM::visitCopySignD(LCopySi
 }
 
 void
 CodeGeneratorARM::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir)
 {
     const LInt64Allocation& input = lir->getInt64Operand(0);
     Register output = ToRegister(lir->output());
 
-    masm.move32(ToRegister(input.low()), output);
+    if (lir->mir()->bottomHalf())
+        masm.move32(ToRegister(input.low()), output);
+    else
+        masm.move32(ToRegister(input.high()), output);
 }
 
 void
 CodeGeneratorARM::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir)
 {
     Register64 output = ToOutRegister64(lir);
     MOZ_ASSERT(ToRegister(lir->input()) == output.low);
 
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -4330,16 +4330,20 @@ class LWrapInt64ToInt32 : public LInstru
   public:
     LIR_HEADER(WrapInt64ToInt32)
 
     static const size_t Input = 0;
 
     explicit LWrapInt64ToInt32(const LInt64Allocation& input) {
         setInt64Operand(Input, input);
     }
+
+    const MWrapInt64ToInt32* mir() {
+        return mir_->toWrapInt64ToInt32();
+    }
 };
 
 class LExtendInt32ToInt64 : public LInstructionHelper<INT64_PIECES, 1, 0>
 {
   public:
     LIR_HEADER(ExtendInt32ToInt64)
 
     explicit LExtendInt32ToInt64(const LAllocation& input) {
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -1146,17 +1146,20 @@ CodeGeneratorX64::visitTruncateFToInt32(
 }
 
 void
 CodeGeneratorX64::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir)
 {
     const LAllocation* input = lir->getOperand(0);
     Register output = ToRegister(lir->output());
 
-    masm.movl(ToOperand(input), output);
+    if (lir->mir()->bottomHalf())
+        masm.movl(ToOperand(input), output);
+    else
+        MOZ_CRASH("Not implemented.");
 }
 
 void
 CodeGeneratorX64::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir)
 {
     const LAllocation* input = lir->getOperand(0);
     Register output = ToRegister(lir->output());
 
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -1569,17 +1569,20 @@ CodeGeneratorX86::visitExtendInt32ToInt6
 }
 
 void
 CodeGeneratorX86::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir)
 {
     const LInt64Allocation& input = lir->getInt64Operand(0);
     Register output = ToRegister(lir->output());
 
-    masm.movl(ToRegister(input.low()), output);
+    if (lir->mir()->bottomHalf())
+        masm.movl(ToRegister(input.low()), output);
+    else
+        masm.movl(ToRegister(input.high()), output);
 }
 
 void
 CodeGeneratorX86::visitClzI64(LClzI64* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     Register64 output = ToOutRegister64(lir);