Bug 1391248 - Add ll,sc,sync instruction support to mips32 simulator. r=lth
author"dragan.mladjenovic" <dragan.mladjenovic@rt-rk.com>
Thu, 24 Aug 2017 10:47:00 -0400
changeset 376603 ee2061564115
parent 376602 d7502c932452
child 376604 e452433ec516
push id94132
push userryanvm@gmail.com
push dateThu, 24 Aug 2017 19:14:09 +0000
treeherdermozilla-inbound@3c6a4705b511 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1391248
milestone57.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 1391248 - Add ll,sc,sync instruction support to mips32 simulator. r=lth
js/src/jit/mips32/Simulator-mips32.cpp
js/src/jit/mips32/Simulator-mips32.h
--- a/js/src/jit/mips32/Simulator-mips32.cpp
+++ b/js/src/jit/mips32/Simulator-mips32.cpp
@@ -30,16 +30,17 @@
 
 #include "mozilla/Casting.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include <float.h>
 
+#include "jit/AtomicOperations.h"
 #include "jit/mips32/Assembler-mips32.h"
 #include "vm/Runtime.h"
 #include "wasm/WasmInstance.h"
 #include "wasm/WasmSignalHandlers.h"
 
 #define I8(v)   static_cast<int8_t>(v)
 #define I16(v)  static_cast<int16_t>(v)
 #define U16(v)  static_cast<uint16_t>(v)
@@ -375,16 +376,17 @@ SimInstruction::instructionType() const
           case ff_tgeu:
           case ff_tlt:
           case ff_tltu:
           case ff_teq:
           case ff_tne:
           case ff_movz:
           case ff_movn:
           case ff_movci:
+          case ff_sync:
             return kRegisterType;
           default:
             return kUnsupported;
         };
         break;
       case op_special2:
         switch (functionFieldRaw()) {
           case ff_mul:
@@ -443,16 +445,18 @@ SimInstruction::instructionType() const
       case op_sh:
       case op_swl:
       case op_sw:
       case op_swr:
       case op_lwc1:
       case op_ldc1:
       case op_swc1:
       case op_sdc1:
+      case op_ll:
+      case op_sc:
         return kImmediateType;
         // 26 bits immediate type instructions. e.g.: j imm26.
       case op_j:
       case op_jal:
         return kJumpType;
       default:
         return kUnsupported;
     }
@@ -1270,16 +1274,19 @@ Simulator::Simulator()
     // All registers are initialized to zero to start with.
     for (int i = 0; i < Register::kNumSimuRegisters; i++) {
         registers_[i] = 0;
     }
     for (int i = 0; i < Simulator::FPURegister::kNumFPURegisters; i++) {
         FPUregisters_[i] = 0;
     }
     FCSR_ = 0;
+    LLBit_ = false;
+    LLAddr_ = 0;
+    lastLLValue_ = 0;
 
     // The ra and pc are initialized to a known bad value that will cause an
     // access violation if the simulator ever tries to execute it.
     registers_[pc] = bad_ra;
     registers_[ra] = bad_ra;
 
     for (int i = 0; i < kNumExceptions; i++)
         exceptions[i] = 0;
@@ -1671,16 +1678,17 @@ Simulator::writeW(uint32_t addr, int val
     if (addr < 0x400) {
         // This has to be a NULL-dereference, drop into debugger.
         printf("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n",
                addr, reinterpret_cast<intptr_t>(instr));
         MOZ_CRASH();
     }
     if ((addr & kPointerAlignmentMask) == 0) {
         intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
+        LLBit_ = false;
         *ptr = value;
         return;
     }
     printf("Unaligned write at 0x%08x, pc=0x%08" PRIxPTR "\n",
            addr,
            reinterpret_cast<intptr_t>(instr));
     MOZ_CRASH();
 }
@@ -1699,16 +1707,17 @@ Simulator::readD(uint32_t addr, SimInstr
     return 0;
 }
 
 void
 Simulator::writeD(uint32_t addr, double value, SimInstruction* instr)
 {
     if ((addr & kDoubleAlignmentMask) == 0) {
         double* ptr = reinterpret_cast<double*>(addr);
+        LLBit_ = false;
         *ptr = value;
         return;
     }
     printf("Unaligned (double) write at 0x%08x, pc=0x%08" PRIxPTR "\n",
            addr,
            reinterpret_cast<intptr_t>(instr));
     MOZ_CRASH();
 }
@@ -1741,30 +1750,32 @@ Simulator::readH(uint32_t addr, SimInstr
     return 0;
 }
 
 void
 Simulator::writeH(uint32_t addr, uint16_t value, SimInstruction* instr)
 {
     if ((addr & 1) == 0) {
         uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
+        LLBit_ = false;
         *ptr = value;
         return;
     }
     printf("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" PRIxPTR "\n",
            addr,
            reinterpret_cast<intptr_t>(instr));
     MOZ_CRASH();
 }
 
 void
 Simulator::writeH(uint32_t addr, int16_t value, SimInstruction* instr)
 {
     if ((addr & 1) == 0) {
         int16_t* ptr = reinterpret_cast<int16_t*>(addr);
+        LLBit_ = false;
         *ptr = value;
         return;
     }
     printf("Unaligned halfword write at 0x%08x, pc=0x%08" PRIxPTR "\n",
            addr,
            reinterpret_cast<intptr_t>(instr));
     MOZ_CRASH();
 }
@@ -1782,26 +1793,78 @@ Simulator::readB(uint32_t addr)
     int8_t* ptr = reinterpret_cast<int8_t*>(addr);
     return *ptr;
 }
 
 void
 Simulator::writeB(uint32_t addr, uint8_t value)
 {
     uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
+    LLBit_ = false;
     *ptr = value;
 }
 
 void
 Simulator::writeB(uint32_t addr, int8_t value)
 {
     int8_t* ptr = reinterpret_cast<int8_t*>(addr);
+    LLBit_ = false;
     *ptr = value;
 }
 
+int
+Simulator::loadLinkedW(uint32_t addr, SimInstruction* instr)
+{
+    if ((addr & kPointerAlignmentMask) == 0) {
+        volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(addr);
+        int32_t value = *ptr;
+        lastLLValue_ = value;
+        LLAddr_ = addr;
+        // Note that any memory write or "external" interrupt should reset this value to false.
+        LLBit_ = true;
+        return value;
+    }
+    printf("Unaligned read at 0x%08x, pc=0x%08" PRIxPTR "\n",
+           addr,
+           reinterpret_cast<intptr_t>(instr));
+    MOZ_CRASH();
+    return 0;
+}
+
+int
+Simulator::storeConditionalW(uint32_t addr, int value, SimInstruction* instr)
+{
+    // Correct behavior in this case, as defined by architecture, is to just return 0,
+    // but there is no point at allowing that. It is certainly an indicator of a bug.
+    if (addr != LLAddr_) {
+        printf("SC to bad address: 0x%08x, pc=0x%08" PRIxPTR ", expected: 0x%08x\n",
+               addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
+        MOZ_CRASH();
+    }
+
+    if ((addr & kPointerAlignmentMask) == 0) {
+        SharedMem<int32_t*> ptr = SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
+
+        if (!LLBit_) {
+            return 0;
+        }
+
+        LLBit_ = false;
+        LLAddr_ = 0;
+        int32_t expected = lastLLValue_;
+        int32_t old = AtomicOperations::compareExchangeSeqCst(ptr, expected, int32_t(value));
+        return (old == expected) ? 1:0;
+    }
+    printf("Unaligned SC at 0x%08x, pc=0x%08" PRIxPTR "\n",
+           addr,
+           reinterpret_cast<intptr_t>(instr));
+    MOZ_CRASH();
+    return 0;
+}
+
 uintptr_t
 Simulator::stackLimit() const
 {
     return stackLimit_;
 }
 
 uintptr_t*
 Simulator::addressOfStackLimit()
@@ -2400,16 +2463,17 @@ Simulator::configureTypeRegister(SimInst
             do_interrupt = rs == rt;
             break;
           case ff_tne:
             do_interrupt = rs != rt;
             break;
           case ff_movn:
           case ff_movz:
           case ff_movci:
+          case ff_sync:
             // No action taken on decode.
             break;
           case ff_div:
           case ff_divu:
             // div and divu never raise exceptions.
             break;
           default:
             MOZ_CRASH();
@@ -2956,16 +3020,30 @@ Simulator::decodeTypeRegister(SimInstruc
           case ff_tlt:
           case ff_tltu:
           case ff_teq:
           case ff_tne:
             if (do_interrupt) {
                 softwareInterrupt(instr);
             }
             break;
+          case ff_sync:
+            switch(instr->bits(10, 6)){
+                case 0x0:
+                case 0x4:
+                case 0x10:
+                case 0x11:
+                case 0x12:
+                case 0x13:
+                  AtomicOperations::fenceSeqCst();
+                  break;
+                default:
+                  MOZ_CRASH();
+            }
+            break;
             // Conditional moves.
           case ff_movn:
             if (rt) setRegister(rd_reg, rs);
             break;
           case ff_movci: {
             uint32_t cc = instr->fbccValue();
             uint32_t fcsr_cc = GetFCSRConditionBit(cc);
             if (instr->bit(16)) {  // Read Tf bit.
@@ -3243,16 +3321,24 @@ Simulator::decodeTypeImmediate(SimInstru
       case op_ldc1:
         addr = rs + se_imm16;
         fp_out = readD(addr, instr);
         break;
       case op_swc1:
       case op_sdc1:
         addr = rs + se_imm16;
         break;
+      case op_ll:
+        addr = rs + se_imm16;
+        alu_out = loadLinkedW(addr, instr);
+        break;
+      case op_sc:
+        addr = rs + se_imm16;
+        alu_out = storeConditionalW(addr,rt,instr);
+        break;
       default:
         MOZ_CRASH();
     }
 
     // ---------- Raise exceptions triggered.
     signalExceptions();
 
     // ---------- Execution.
@@ -3288,16 +3374,18 @@ Simulator::decodeTypeImmediate(SimInstru
         // ------------- Memory instructions.
       case op_lb:
       case op_lh:
       case op_lwl:
       case op_lw:
       case op_lbu:
       case op_lhu:
       case op_lwr:
+      case op_ll:
+      case op_sc:
         setRegister(rt_reg, alu_out);
         break;
       case op_sb:
         writeB(addr, static_cast<int8_t>(rt));
         break;
       case op_sh:
         writeH(addr, static_cast<uint16_t>(rt), instr);
         break;
--- a/js/src/jit/mips32/Simulator-mips32.h
+++ b/js/src/jit/mips32/Simulator-mips32.h
@@ -256,16 +256,19 @@ class Simulator {
     inline void writeH(uint32_t addr, int16_t value, SimInstruction* instr);
 
     inline int readW(uint32_t addr, SimInstruction* instr);
     inline void writeW(uint32_t addr, int value, SimInstruction* instr);
 
     inline double readD(uint32_t addr, SimInstruction* instr);
     inline void writeD(uint32_t addr, double value, SimInstruction* instr);
 
+    inline int32_t loadLinkedW(uint32_t addr, SimInstruction* instr);
+    inline int32_t storeConditionalW(uint32_t addr, int32_t value, SimInstruction* instr);
+
     // Executing is handled based on the instruction type.
     void decodeTypeRegister(SimInstruction* instr);
 
     // Helper function for decodeTypeRegister.
     void configureTypeRegister(SimInstruction* instr,
                                int32_t& alu_out,
                                int64_t& i64hilo,
                                uint64_t& u64hilo,
@@ -331,16 +334,20 @@ class Simulator {
     // Architecture state.
     // Registers.
     int32_t registers_[kNumSimuRegisters];
     // Coprocessor Registers.
     int32_t FPUregisters_[kNumFPURegisters];
     // FPU control register.
     uint32_t FCSR_;
 
+    bool LLBit_;
+    uint32_t LLAddr_;
+    int32_t lastLLValue_;
+
     // Simulator support.
     char* stack_;
     uintptr_t stackLimit_;
     bool pc_modified_;
     int icount_;
     int break_count_;
 
     // wasm async interrupt support