Bug 1316850 - reduce code duplication. r=bbouvier
authorLars T Hansen <lhansen@mozilla.com>
Tue, 15 Nov 2016 10:16:05 +0100
changeset 350843 a8873fe7b7c83793a1015555a7b641e0577094c2
parent 350842 b0f086350aaf4da3625b9dc520c4a0d4f9027625
child 350844 0da56750be97361ba349e591b699b66911a0ce9c
push id10621
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 16:02:43 +0000
treeherdermozilla-aurora@dca7b42e6c67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1316850
milestone53.0a1
Bug 1316850 - reduce code duplication. r=bbouvier
js/src/wasm/WasmBaselineCompile.cpp
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -3553,16 +3553,44 @@ class BaseCompiler
         *r0 = popF32();
     }
 
     void pop2xF64(RegF64* r0, RegF64* r1) {
         *r1 = popF64();
         *r0 = popF64();
     }
 
+    template<bool freeIt> void freeOrPushI32(RegI32 r) {
+        if (freeIt)
+            freeI32(r);
+        else
+            pushI32(r);
+    }
+
+    template<bool freeIt> void freeOrPushI64(RegI64 r) {
+        if (freeIt)
+            freeI64(r);
+        else
+            pushI64(r);
+    }
+
+    template<bool freeIt> void freeOrPushF32(RegF32 r) {
+        if (freeIt)
+            freeF32(r);
+        else
+            pushF32(r);
+    }
+
+    template<bool freeIt> void freeOrPushF64(RegF64 r) {
+        if (freeIt)
+            freeF64(r);
+        else
+            pushF64(r);
+    }
+
     ////////////////////////////////////////////////////////////
     //
     // Sundry helpers.
 
     uint32_t readCallSiteLineOrBytecode() {
         if (!func_.callSiteLineNums().empty())
             return func_.callSiteLineNums()[lastReadCallSite_++];
         return trapOffset().bytecodeOffset;
@@ -3616,16 +3644,26 @@ class BaseCompiler
     MOZ_MUST_USE bool emitSetGlobal();
     MOZ_MUST_USE bool emitTeeGlobal();
     MOZ_MUST_USE bool emitLoad(ValType type, Scalar::Type viewType);
     MOZ_MUST_USE bool emitStore(ValType resultType, Scalar::Type viewType);
     MOZ_MUST_USE bool emitTeeStore(ValType resultType, Scalar::Type viewType);
     MOZ_MUST_USE bool emitTeeStoreWithCoercion(ValType resultType, Scalar::Type viewType);
     MOZ_MUST_USE bool emitSelect();
 
+    // Mark these templates as inline to work around a compiler crash in
+    // gcc 4.8.5 when compiling for linux64-opt.
+
+    template<bool isSetLocal> MOZ_MUST_USE inline bool emitSetOrTeeLocal(uint32_t slot);
+    template<bool isSetGlobal> MOZ_MUST_USE inline bool emitSetOrTeeGlobal(uint32_t id);
+    template<bool isStore>
+    MOZ_MUST_USE inline bool emitStoreOrTeeStore(ValType resultType,
+                                                 Scalar::Type viewType,
+                                                 LinearMemoryAddress<Nothing> addr);
+
     void endBlock(ExprType type, bool isFunctionBody);
     void endLoop(ExprType type);
     void endIfThen();
     void endIfThenElse(ExprType type);
 
     void doReturn(ExprType returnType);
     void pushReturned(const FunctionCall& call, ExprType type);
 
@@ -5718,108 +5756,77 @@ BaseCompiler::emitGetLocal()
         break;
       default:
         MOZ_CRASH("Local variable type");
     }
 
     return true;
 }
 
+template<bool isSetLocal>
 bool
-BaseCompiler::emitSetLocal()
-{
-    uint32_t slot;
-    Nothing unused_value;
-    if (!iter_.readSetLocal(locals_, &slot, &unused_value))
-        return false;
-
+BaseCompiler::emitSetOrTeeLocal(uint32_t slot)
+{
     if (deadCode_)
         return true;
 
     switch (locals_[slot]) {
       case ValType::I32: {
         RegI32 rv = popI32();
         syncLocal(slot);
         storeToFrameI32(rv.reg, frameOffsetFromSlot(slot, MIRType::Int32));
-        freeI32(rv);
+        freeOrPushI32<isSetLocal>(rv);
         break;
       }
       case ValType::I64: {
         RegI64 rv = popI64();
         syncLocal(slot);
         storeToFrameI64(rv.reg, frameOffsetFromSlot(slot, MIRType::Int64));
-        freeI64(rv);
+        freeOrPushI64<isSetLocal>(rv);
         break;
       }
       case ValType::F64: {
         RegF64 rv = popF64();
         syncLocal(slot);
         storeToFrameF64(rv.reg, frameOffsetFromSlot(slot, MIRType::Double));
-        freeF64(rv);
+        freeOrPushF64<isSetLocal>(rv);
         break;
       }
       case ValType::F32: {
         RegF32 rv = popF32();
         syncLocal(slot);
         storeToFrameF32(rv.reg, frameOffsetFromSlot(slot, MIRType::Float32));
-        freeF32(rv);
+        freeOrPushF32<isSetLocal>(rv);
         break;
       }
       default:
         MOZ_CRASH("Local variable type");
     }
 
     return true;
 }
 
 bool
+BaseCompiler::emitSetLocal()
+{
+    uint32_t slot;
+    Nothing unused_value;
+    if (!iter_.readSetLocal(locals_, &slot, &unused_value))
+        return false;
+    return emitSetOrTeeLocal<true>(slot);
+}
+
+bool
 BaseCompiler::emitTeeLocal()
 {
     uint32_t slot;
     Nothing unused_value;
     if (!iter_.readTeeLocal(locals_, &slot, &unused_value))
         return false;
-
-    if (deadCode_)
-        return true;
-
-    switch (locals_[slot]) {
-      case ValType::I32: {
-        RegI32 rv = popI32();
-        syncLocal(slot);
-        storeToFrameI32(rv.reg, frameOffsetFromSlot(slot, MIRType::Int32));
-        pushI32(rv);
-        break;
-      }
-      case ValType::I64: {
-        RegI64 rv = popI64();
-        syncLocal(slot);
-        storeToFrameI64(rv.reg, frameOffsetFromSlot(slot, MIRType::Int64));
-        pushI64(rv);
-        break;
-      }
-      case ValType::F64: {
-        RegF64 rv = popF64();
-        syncLocal(slot);
-        storeToFrameF64(rv.reg, frameOffsetFromSlot(slot, MIRType::Double));
-        pushF64(rv);
-        break;
-      }
-      case ValType::F32: {
-        RegF32 rv = popF32();
-        syncLocal(slot);
-        storeToFrameF32(rv.reg, frameOffsetFromSlot(slot, MIRType::Float32));
-        pushF32(rv);
-        break;
-      }
-      default:
-        MOZ_CRASH("Local variable type");
-    }
-
-    return true;
+    return emitSetOrTeeLocal<false>(slot);
 }
 
 bool
 BaseCompiler::emitGetGlobal()
 {
     uint32_t id;
     if (!iter_.readGetGlobal(mg_.globals, &id))
         return false;
@@ -5877,104 +5884,77 @@ BaseCompiler::emitGetGlobal()
       }
       default:
         MOZ_CRASH("Global variable type");
         break;
     }
     return true;
 }
 
+template<bool isSetGlobal>
 bool
-BaseCompiler::emitSetGlobal()
-{
-    uint32_t id;
-    Nothing unused_value;
-    if (!iter_.readSetGlobal(mg_.globals, &id, &unused_value))
-        return false;
-
+BaseCompiler::emitSetOrTeeGlobal(uint32_t id)
+{
     if (deadCode_)
         return true;
 
     const GlobalDesc& global = mg_.globals[id];
 
     switch (global.type()) {
       case ValType::I32: {
         RegI32 rv = popI32();
         storeGlobalVarI32(global.offset(), rv);
-        freeI32(rv);
+        freeOrPushI32<isSetGlobal>(rv);
         break;
       }
       case ValType::I64: {
         RegI64 rv = popI64();
         storeGlobalVarI64(global.offset(), rv);
-        freeI64(rv);
+        freeOrPushI64<isSetGlobal>(rv);
         break;
       }
       case ValType::F32: {
         RegF32 rv = popF32();
         storeGlobalVarF32(global.offset(), rv);
-        freeF32(rv);
+        freeOrPushF32<isSetGlobal>(rv);
         break;
       }
       case ValType::F64: {
         RegF64 rv = popF64();
         storeGlobalVarF64(global.offset(), rv);
-        freeF64(rv);
+        freeOrPushF64<isSetGlobal>(rv);
         break;
       }
       default:
         MOZ_CRASH("Global variable type");
         break;
     }
     return true;
 }
 
 bool
+BaseCompiler::emitSetGlobal()
+{
+    uint32_t id;
+    Nothing unused_value;
+    if (!iter_.readSetGlobal(mg_.globals, &id, &unused_value))
+        return false;
+
+    return emitSetOrTeeGlobal<true>(id);
+}
+
+bool
 BaseCompiler::emitTeeGlobal()
 {
     uint32_t id;
     Nothing unused_value;
     if (!iter_.readTeeGlobal(mg_.globals, &id, &unused_value))
         return false;
 
-    if (deadCode_)
-        return true;
-
-    const GlobalDesc& global = mg_.globals[id];
-
-    switch (global.type()) {
-      case ValType::I32: {
-        RegI32 rv = popI32();
-        storeGlobalVarI32(global.offset(), rv);
-        pushI32(rv);
-        break;
-      }
-      case ValType::I64: {
-        RegI64 rv = popI64();
-        storeGlobalVarI64(global.offset(), rv);
-        pushI64(rv);
-        break;
-      }
-      case ValType::F32: {
-        RegF32 rv = popF32();
-        storeGlobalVarF32(global.offset(), rv);
-        pushF32(rv);
-        break;
-      }
-      case ValType::F64: {
-        RegF64 rv = popF64();
-        storeGlobalVarF64(global.offset(), rv);
-        pushF64(rv);
-        break;
-      }
-      default:
-        MOZ_CRASH("Global variable type");
-        break;
-    }
-    return true;
+    return emitSetOrTeeGlobal<false>(id);
 }
 
 bool
 BaseCompiler::emitLoad(ValType type, Scalar::Type viewType)
 {
     LinearMemoryAddress<Nothing> addr;
     if (!iter_.readLoad(type, Scalar::byteSize(viewType), &addr))
         return false;
@@ -6049,24 +6029,21 @@ BaseCompiler::emitLoad(ValType type, Sca
     if (temps >= 1)
         freeI32(tmp1);
     if (temps >= 2)
         freeI32(tmp2);
 
     return true;
 }
 
+template<bool isStore>
 bool
-BaseCompiler::emitStore(ValType resultType, Scalar::Type viewType)
-{
-    LinearMemoryAddress<Nothing> addr;
-    Nothing unused_value;
-    if (!iter_.readStore(resultType, Scalar::byteSize(viewType), &addr, &unused_value))
-        return false;
-
+BaseCompiler::emitStoreOrTeeStore(ValType resultType, Scalar::Type viewType,
+                                  LinearMemoryAddress<Nothing> addr)
+{
     if (deadCode_)
         return true;
 
     // TODO / OPTIMIZE (bug 1316831): Disable bounds checking on constant
     // accesses below the minimum heap length.
 
     MemoryAccessDesc access(viewType, addr.align, addr.offset, trapIfNotAsmJS());
 
@@ -6076,127 +6053,79 @@ BaseCompiler::emitStore(ValType resultTy
 
     switch (resultType) {
       case ValType::I32: {
         RegI32 rp, rv;
         pop2xI32(&rp, &rv);
         if (!store(access, rp, AnyReg(rv), tmp1, tmp2))
             return false;
         freeI32(rp);
-        freeI32(rv);
+        freeOrPushI32<isStore>(rv);
         break;
       }
       case ValType::I64: {
         RegI64 rv = popI64();
         RegI32 rp = popI32();
         if (!store(access, rp, AnyReg(rv), tmp1, tmp2))
             return false;
         freeI32(rp);
-        freeI64(rv);
+        freeOrPushI64<isStore>(rv);
         break;
       }
       case ValType::F32: {
         RegF32 rv = popF32();
         RegI32 rp = popI32();
         if (!store(access, rp, AnyReg(rv), tmp1, tmp2))
             return false;
         freeI32(rp);
-        freeF32(rv);
+        freeOrPushF32<isStore>(rv);
         break;
       }
       case ValType::F64: {
         RegF64 rv = popF64();
         RegI32 rp = popI32();
         if (!store(access, rp, AnyReg(rv), tmp1, tmp2))
             return false;
         freeI32(rp);
-        freeF64(rv);
+        freeOrPushF64<isStore>(rv);
         break;
       }
       default:
         MOZ_CRASH("store type");
         break;
     }
 
     if (temps >= 1)
         freeI32(tmp1);
     if (temps >= 2)
         freeI32(tmp2);
 
     return true;
 }
 
 bool
+BaseCompiler::emitStore(ValType resultType, Scalar::Type viewType)
+{
+    LinearMemoryAddress<Nothing> addr;
+    Nothing unused_value;
+    if (!iter_.readStore(resultType, Scalar::byteSize(viewType), &addr, &unused_value))
+        return false;
+
+    return emitStoreOrTeeStore<true>(resultType, viewType, addr);
+}
+
+bool
 BaseCompiler::emitTeeStore(ValType resultType, Scalar::Type viewType)
 {
     LinearMemoryAddress<Nothing> addr;
     Nothing unused_value;
     if (!iter_.readTeeStore(resultType, Scalar::byteSize(viewType), &addr, &unused_value))
         return false;
 
-    if (deadCode_)
-        return true;
-
-    // TODO / OPTIMIZE (bug 1316831): Disable bounds checking on constant
-    // accesses below the minimum heap length.
-
-    MemoryAccessDesc access(viewType, addr.align, addr.offset, trapIfNotAsmJS());
-
-    size_t temps = loadStoreTemps(access);
-    RegI32 tmp1 = temps >= 1 ? needI32() : invalidI32();
-    RegI32 tmp2 = temps >= 2 ? needI32() : invalidI32();
-
-    switch (resultType) {
-      case ValType::I32: {
-        RegI32 rp, rv;
-        pop2xI32(&rp, &rv);
-        if (!store(access, rp, AnyReg(rv), tmp1, tmp2))
-            return false;
-        freeI32(rp);
-        pushI32(rv);
-        break;
-      }
-      case ValType::I64: {
-        RegI64 rv = popI64();
-        RegI32 rp = popI32();
-        if (!store(access, rp, AnyReg(rv), tmp1, tmp2))
-            return false;
-        freeI32(rp);
-        pushI64(rv);
-        break;
-      }
-      case ValType::F32: {
-        RegF32 rv = popF32();
-        RegI32 rp = popI32();
-        if (!store(access, rp, AnyReg(rv), tmp1, tmp2))
-            return false;
-        freeI32(rp);
-        pushF32(rv);
-        break;
-      }
-      case ValType::F64: {
-        RegF64 rv = popF64();
-        RegI32 rp = popI32();
-        if (!store(access, rp, AnyReg(rv), tmp1, tmp2))
-            return false;
-        freeI32(rp);
-        pushF64(rv);
-        break;
-      }
-      default:
-        MOZ_CRASH("store type");
-        break;
-    }
-
-    if (temps >= 1)
-        freeI32(tmp1);
-    if (temps >= 2)
-        freeI32(tmp2);
-
-    return true;
+    return emitStoreOrTeeStore<false>(resultType, viewType, addr);
 }
 
 bool
 BaseCompiler::emitSelect()
 {
     ValType type;
     Nothing unused_trueValue;
     Nothing unused_falseValue;