Bug 1423857 - MIPS: Add big endian support. r=lth
authorMiran.Karic <Miran.Karic@imgtec.com>
Thu, 11 Jan 2018 04:35:00 +0200
changeset 450956 3b640564e1bd83c32a91b0ad719b0fe8cba02098
parent 450955 3d7ad9a9c2fee4a21d716882580e77ff5b06ea89
child 450957 809a14e1c12b4ccca6c328f80719c0f0787128e6
push id8543
push userryanvm@gmail.com
push dateTue, 16 Jan 2018 14:33:22 +0000
treeherdermozilla-beta@a6525ed16a32 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1423857
milestone59.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 1423857 - MIPS: Add big endian support. r=lth This fixes JIT for MIPS big endian. These are MIPS only changes.
js/src/jit/MIR.cpp
js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
js/src/jit/mips32/Architecture-mips32.h
js/src/jit/mips32/MacroAssembler-mips32.cpp
js/src/jit/mips32/MacroAssembler-mips32.h
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1033,28 +1033,40 @@ void
 MConstant::assertInitializedPayload() const
 {
     // valueHash() and equals() expect the unused payload bits to be
     // initialized to zero. Assert this in debug builds.
 
     switch (type()) {
       case MIRType::Int32:
       case MIRType::Float32:
+#if MOZ_LITTLE_ENDIAN
         MOZ_ASSERT((payload_.asBits >> 32) == 0);
+#else
+        MOZ_ASSERT((payload_.asBits << 32) == 0);
+#endif
         break;
       case MIRType::Boolean:
+#if MOZ_LITTLE_ENDIAN
         MOZ_ASSERT((payload_.asBits >> 1) == 0);
+#else
+        MOZ_ASSERT((payload_.asBits & ~(1ULL << 56)) == 0);
+#endif
         break;
       case MIRType::Double:
       case MIRType::Int64:
         break;
       case MIRType::String:
       case MIRType::Object:
       case MIRType::Symbol:
+#if MOZ_LITTLE_ENDIAN
         MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits >> 32) == 0);
+#else
+        MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits << 32) == 0);
+#endif
         break;
       default:
         MOZ_ASSERT(IsNullOrUndefined(type()) || IsMagicType(type()));
         MOZ_ASSERT(payload_.asBits == 0);
         break;
     }
 }
 #endif
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -547,16 +547,17 @@ MacroAssemblerMIPSShared::ma_load(Regist
     asMasm().computeScaledAddress(src, SecondScratchReg);
     asMasm().ma_load(dest, Address(SecondScratchReg, src.offset), size, extension);
 }
 
 void
 MacroAssemblerMIPSShared::ma_load_unaligned(const wasm::MemoryAccessDesc& access, Register dest, const BaseIndex& src, Register temp,
                                             LoadStoreSize size, LoadStoreExtension extension)
 {
+    MOZ_ASSERT(MOZ_LITTLE_ENDIAN, "Wasm-only; wasm is disabled on big-endian.");
     int16_t lowOffset, hiOffset;
     Register base;
 
     asMasm().computeScaledAddress(src, SecondScratchReg);
 
     if (Imm16::IsInSignedRange(src.offset) && Imm16::IsInSignedRange(src.offset + size / 8 - 1)) {
         base = SecondScratchReg;
         lowOffset = Imm16(src.offset).encode();
@@ -699,16 +700,17 @@ MacroAssemblerMIPSShared::ma_store(Imm32
     // so we can use it as a parameter here
     asMasm().ma_store(ScratchRegister, Address(SecondScratchReg, 0), size, extension);
 }
 
 void
 MacroAssemblerMIPSShared::ma_store_unaligned(const wasm::MemoryAccessDesc& access, Register data, const BaseIndex& dest, Register temp,
                                              LoadStoreSize size, LoadStoreExtension extension)
 {
+    MOZ_ASSERT(MOZ_LITTLE_ENDIAN, "Wasm-only; wasm is disabled on big-endian.");
     int16_t lowOffset, hiOffset;
     Register base;
 
     asMasm().computeEffectiveAddress(dest, SecondScratchReg);
 
     if (Imm16::IsInSignedRange(dest.offset) && Imm16::IsInSignedRange(dest.offset + size / 8 - 1)) {
         base = SecondScratchReg;
         lowOffset = Imm16(dest.offset).encode();
--- a/js/src/jit/mips32/Architecture-mips32.h
+++ b/js/src/jit/mips32/Architecture-mips32.h
@@ -19,18 +19,23 @@
 namespace js {
 namespace jit {
 
 static const uint32_t ShadowStackSpace = 4 * sizeof(uintptr_t);
 
 // These offsets are specific to nunboxing, and capture offsets into the
 // components of a js::Value.
 // Size of MIPS32 general purpose registers is 32 bits.
+#if MOZ_LITTLE_ENDIAN
 static const int32_t NUNBOX32_TYPE_OFFSET = 4;
 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
+#else
+static const int32_t NUNBOX32_TYPE_OFFSET = 0;
+static const int32_t NUNBOX32_PAYLOAD_OFFSET = 4;
+#endif
 
 // Size of each bailout table entry.
 // For MIPS this is 2 instructions relative call.
 static const uint32_t BAILOUT_TABLE_ENTRY_SIZE = 2 * sizeof(void*);
 
 // MIPS32 can have two types of floating-point coprocessors modes:
 // - FR=0 mode/ 32-bit FPRs - Historical default, there are 32 single
 // precision registers and pairs of even and odd float registers are used as
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -642,16 +642,19 @@ MacroAssemblerMIPS::ma_cmp_set(Register 
 void
 MacroAssemblerMIPS::ma_lid(FloatRegister dest, double value)
 {
     struct DoubleStruct {
         uint32_t lo;
         uint32_t hi;
     } ;
     DoubleStruct intStruct = mozilla::BitwiseCast<DoubleStruct>(value);
+#if MOZ_BIG_ENDIAN
+    mozilla::Swap(intStruct.hi, intStruct.lo);
+#endif
 
     // put hi part of 64 bit value into the odd register
     if (intStruct.hi == 0) {
         moveToDoubleHi(zero, dest);
     } else {
         ma_li(ScratchRegister, Imm32(intStruct.hi));
         moveToDoubleHi(ScratchRegister, dest);
     }
@@ -697,39 +700,41 @@ MacroAssemblerMIPS::ma_ls(FloatRegister 
 }
 
 void
 MacroAssemblerMIPS::ma_ld(FloatRegister ft, Address address)
 {
     // Use single precision load instructions so we don't have to worry about
     // alignment.
 
+    int32_t off = address.offset + PAYLOAD_OFFSET;
     int32_t off2 = address.offset + TAG_OFFSET;
-    if (Imm16::IsInSignedRange(address.offset) && Imm16::IsInSignedRange(off2)) {
-        as_ls(ft, address.base, address.offset);
+    if (Imm16::IsInSignedRange(off) && Imm16::IsInSignedRange(off2)) {
+        as_ls(ft, address.base, off);
         as_ls(getOddPair(ft), address.base, off2);
     } else {
         MOZ_ASSERT(address.base != ScratchRegister);
-        ma_li(ScratchRegister, Imm32(address.offset));
+        ma_li(ScratchRegister, Imm32(off));
         as_addu(ScratchRegister, address.base, ScratchRegister);
         as_ls(ft, ScratchRegister, PAYLOAD_OFFSET);
         as_ls(getOddPair(ft), ScratchRegister, TAG_OFFSET);
     }
 }
 
 void
 MacroAssemblerMIPS::ma_sd(FloatRegister ft, Address address)
 {
+    int32_t off = address.offset + PAYLOAD_OFFSET;
     int32_t off2 = address.offset + TAG_OFFSET;
-    if (Imm16::IsInSignedRange(address.offset) && Imm16::IsInSignedRange(off2)) {
-        as_ss(ft, address.base, address.offset);
+    if (Imm16::IsInSignedRange(off) && Imm16::IsInSignedRange(off2)) {
+        as_ss(ft, address.base, off);
         as_ss(getOddPair(ft), address.base, off2);
     } else {
         MOZ_ASSERT(address.base != ScratchRegister);
-        ma_li(ScratchRegister, Imm32(address.offset));
+        ma_li(ScratchRegister, Imm32(off));
         as_addu(ScratchRegister, address.base, ScratchRegister);
         as_ss(ft, ScratchRegister, PAYLOAD_OFFSET);
         as_ss(getOddPair(ft), ScratchRegister, TAG_OFFSET);
     }
 }
 
 void
 MacroAssemblerMIPS::ma_ss(FloatRegister ft, Address address)
@@ -933,16 +938,17 @@ MacroAssemblerMIPSCompat::loadDouble(con
     computeScaledAddress(src, SecondScratchReg);
     ma_ld(dest, Address(SecondScratchReg, src.offset));
 }
 
 void
 MacroAssemblerMIPSCompat::loadUnalignedDouble(const wasm::MemoryAccessDesc& access,
                                               const BaseIndex& src, Register temp, FloatRegister dest)
 {
+    MOZ_ASSERT(MOZ_LITTLE_ENDIAN, "Wasm-only; wasm is disabled on big-endian.");
     computeScaledAddress(src, SecondScratchReg);
 
     uint32_t framePushed = asMasm().framePushed();
     BufferOffset load;
     if (Imm16::IsInSignedRange(src.offset) && Imm16::IsInSignedRange(src.offset + 7)) {
         load = as_lwl(temp, SecondScratchReg, src.offset + INT64LOW_OFFSET + 3);
         as_lwr(temp, SecondScratchReg, src.offset + INT64LOW_OFFSET);
         append(access, load.getOffset(), framePushed);
@@ -991,16 +997,17 @@ MacroAssemblerMIPSCompat::loadFloat32(co
     computeScaledAddress(src, SecondScratchReg);
     ma_ls(dest, Address(SecondScratchReg, src.offset));
 }
 
 void
 MacroAssemblerMIPSCompat::loadUnalignedFloat32(const wasm::MemoryAccessDesc& access,
                                                const BaseIndex& src, Register temp, FloatRegister dest)
 {
+    MOZ_ASSERT(MOZ_LITTLE_ENDIAN, "Wasm-only; wasm is disabled on big-endian.");
     computeScaledAddress(src, SecondScratchReg);
     BufferOffset load;
     if (Imm16::IsInSignedRange(src.offset) && Imm16::IsInSignedRange(src.offset + 3)) {
         load = as_lwl(temp, SecondScratchReg, src.offset + 3);
         as_lwr(temp, SecondScratchReg, src.offset);
     } else {
         ma_li(ScratchRegister, Imm32(src.offset));
         as_daddu(ScratchRegister, SecondScratchReg, ScratchRegister);
@@ -1143,16 +1150,17 @@ MacroAssemblerMIPSCompat::storePtr(Regis
     movePtr(ImmPtr(dest.addr), ScratchRegister);
     storePtr(src, Address(ScratchRegister, 0));
 }
 
 void
 MacroAssemblerMIPSCompat::storeUnalignedFloat32(const wasm::MemoryAccessDesc& access,
                                                 FloatRegister src, Register temp, const BaseIndex& dest)
 {
+    MOZ_ASSERT(MOZ_LITTLE_ENDIAN, "Wasm-only; wasm is disabled on big-endian.");
     computeScaledAddress(dest, SecondScratchReg);
     moveFromFloat32(src, temp);
 
     BufferOffset store;
     if (Imm16::IsInSignedRange(dest.offset) && Imm16::IsInSignedRange(dest.offset + 3)) {
         store = as_swl(temp, SecondScratchReg, dest.offset + 3);
         as_swr(temp, SecondScratchReg, dest.offset);
     } else {
@@ -1163,16 +1171,17 @@ MacroAssemblerMIPSCompat::storeUnaligned
     }
     append(access, store.getOffset(), asMasm().framePushed());
 }
 
 void
 MacroAssemblerMIPSCompat::storeUnalignedDouble(const wasm::MemoryAccessDesc& access,
                                                FloatRegister src, Register temp, const BaseIndex& dest)
 {
+    MOZ_ASSERT(MOZ_LITTLE_ENDIAN, "Wasm-only; wasm is disabled on big-endian.");
     computeScaledAddress(dest, SecondScratchReg);
 
     uint32_t framePushed = asMasm().framePushed();
     BufferOffset store;
     if (Imm16::IsInSignedRange(dest.offset) && Imm16::IsInSignedRange(dest.offset + 7)) {
         moveFromDoubleHi(src, temp);
         store = as_swl(temp, SecondScratchReg, dest.offset + INT64HIGH_OFFSET + 3);
         as_swr(temp, SecondScratchReg, dest.offset + INT64HIGH_OFFSET);
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -32,18 +32,23 @@ struct ImmType : public ImmTag
 
 static constexpr ValueOperand JSReturnOperand{JSReturnReg_Type, JSReturnReg_Data};
 static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0);
 
 static const int defaultShift = 3;
 static_assert(1 << defaultShift == sizeof(JS::Value), "The defaultShift is wrong");
 
 static const uint32_t LOW_32_MASK = (1LL << 32) - 1;
+#if MOZ_LITTLE_ENDIAN
 static const int32_t LOW_32_OFFSET = 0;
 static const int32_t HIGH_32_OFFSET = 4;
+#else
+static const int32_t LOW_32_OFFSET = 4;
+static const int32_t HIGH_32_OFFSET = 0;
+#endif
 
 class MacroAssemblerMIPS : public MacroAssemblerMIPSShared
 {
   public:
     using MacroAssemblerMIPSShared::ma_b;
     using MacroAssemblerMIPSShared::ma_li;
     using MacroAssemblerMIPSShared::ma_ss;
     using MacroAssemblerMIPSShared::ma_sd;
@@ -390,16 +395,20 @@ class MacroAssemblerMIPSCompat : public 
     void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest);
 
     // higher level tag testing code
     Operand ToPayload(Operand base);
     Address ToPayload(Address base) {
         return ToPayload(Operand(base)).toAddress();
     }
 
+    BaseIndex ToPayload(BaseIndex base) {
+        return BaseIndex(base.base, base.index, base.scale, base.offset + NUNBOX32_PAYLOAD_OFFSET);
+    }
+
   protected:
     Operand ToType(Operand base);
     Address ToType(Address base) {
         return ToType(Operand(base)).toAddress();
     }
 
     uint32_t getType(const Value& val);
     void moveData(const Value& val, Register data);
@@ -408,24 +417,24 @@ class MacroAssemblerMIPSCompat : public 
 
     CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr);
     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr);
 
     void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
         if (dest.isFloat())
             loadInt32OrDouble(address, dest.fpu());
         else
-            ma_lw(dest.gpr(), address);
+            ma_lw(dest.gpr(), ToPayload(address));
     }
 
     void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) {
         if (dest.isFloat())
             loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale);
         else
-            load32(address, dest.gpr());
+            load32(ToPayload(address), dest.gpr());
     }
 
     template <typename T>
     void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
                            MIRType slotType);
 
     template <typename T>
     void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
@@ -488,27 +497,41 @@ class MacroAssemblerMIPSCompat : public 
     void loadValue(Operand dest, ValueOperand val) {
         loadValue(dest.toAddress(), val);
     }
     void loadValue(const BaseIndex& addr, ValueOperand val);
     void tagValue(JSValueType type, Register payload, ValueOperand dest);
 
     void pushValue(ValueOperand val);
     void popValue(ValueOperand val);
+#if MOZ_LITTLE_ENDIAN
     void pushValue(const Value& val) {
         push(Imm32(val.toNunboxTag()));
         if (val.isGCThing())
             push(ImmGCPtr(val.toGCThing()));
         else
             push(Imm32(val.toNunboxPayload()));
     }
     void pushValue(JSValueType type, Register reg) {
         push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
         ma_push(reg);
     }
+#else
+    void pushValue(const Value& val) {
+        if (val.isGCThing())
+            push(ImmGCPtr(val.toGCThing()));
+        else
+            push(Imm32(val.toNunboxPayload()));
+        push(Imm32(val.toNunboxTag()));
+    }
+    void pushValue(JSValueType type, Register reg) {
+        ma_push(reg);
+        push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
+    }
+#endif
     void pushValue(const Address& addr);
 
     void storePayload(const Value& val, Address dest);
     void storePayload(Register src, Address dest);
     void storePayload(const Value& val, const BaseIndex& dest);
     void storePayload(Register src, const BaseIndex& dest);
     void storeTypeTag(ImmTag tag, Address dest);
     void storeTypeTag(ImmTag tag, const BaseIndex& dest);