Bug 1242342: Replace Ternary by IfElse which return expressions; r=luke
authorBenjamin Bouvier <benj@benj.me>
Wed, 03 Feb 2016 16:04:39 +0100
changeset 283081 3cfbbaeadb0b89aba2e9f771072148164db5d604
parent 283080 633d74f817b253cc9b424de664bfa23911fa8c03
child 283082 c4044ca82798f6c0a0d0d868c8a8bcb3394f1d0a
push id29974
push usercbook@mozilla.com
push dateFri, 05 Feb 2016 10:53:43 +0000
treeherdermozilla-central@1dbe350b57b1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1242342
milestone47.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 1242342: Replace Ternary by IfElse which return expressions; r=luke
js/src/asmjs/AsmJS.cpp
js/src/asmjs/WasmBinary.h
js/src/asmjs/WasmIonCompile.cpp
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -5694,17 +5694,17 @@ CheckComma(FunctionValidator& f, ParseNo
     return CheckExpr(f, pn, type);
 }
 
 static bool
 CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type)
 {
     MOZ_ASSERT(ternary->isKind(PNK_CONDITIONAL));
 
-    if (!f.writeOp(Expr::Ternary))
+    if (!f.writeOp(Expr::IfElse))
         return false;
 
     ParseNode* cond = TernaryKid1(ternary);
     ParseNode* thenExpr = TernaryKid2(ternary);
     ParseNode* elseExpr = TernaryKid3(ternary);
 
     Type condType;
     if (!CheckExpr(f, cond, &condType))
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -229,18 +229,16 @@ enum class Expr : uint16_t
     I64StoreMem16,
     I64StoreMem32,
     I32StoreMem,
     I64StoreMem,
     F32StoreMem,
     F64StoreMem,
 
     // asm.js specific
-    Ternary,        // to be merged with IfElse
-
     While,          // all CFG ops to be deleted in favor of Loop/Br/BrIf
     DoWhile,
 
     ForInitInc,
     ForInitNoInc,
     ForNoInitNoInc,
     ForNoInitInc,
 
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -880,29 +880,34 @@ class FunctionCompiler
                 if (!join->addPredecessor(alloc(), thenBlocks[i]))
                     return false;
             }
         }
         curBlock_ = join;
         return true;
     }
 
+    bool usesPhiSlot()
+    {
+        return curBlock_->stackDepth() == info().firstStackSlot() + 1;
+    }
+
     void pushPhiInput(MDefinition* def)
     {
         if (inDeadCode())
             return;
-        MOZ_ASSERT(curBlock_->stackDepth() == info().firstStackSlot());
+        MOZ_ASSERT(!usesPhiSlot());
         curBlock_->push(def);
     }
 
     MDefinition* popPhiOutput()
     {
         if (inDeadCode())
             return nullptr;
-        MOZ_ASSERT(curBlock_->stackDepth() == info().firstStackSlot() + 1);
+        MOZ_ASSERT(usesPhiSlot());
         return curBlock_->pop();
     }
 
     bool startPendingLoop(size_t id, MBasicBlock** loopEntry)
     {
         if (!loopStack_.append(id) || !breakableStack_.append(id))
             return false;
         if (inDeadCode()) {
@@ -1334,27 +1339,27 @@ EmitLiteral(FunctionCompiler& f, ExprTyp
     MOZ_CRASH("unexpected literal type");
 }
 
 static bool
 EmitGetLocal(FunctionCompiler& f, ExprType type, MDefinition** def)
 {
     uint32_t slot = f.readVarU32();
     *def = f.getLocalDef(slot);
-    MOZ_ASSERT_IF(type != ExprType::Limit, f.localType(slot) == type);
+    MOZ_ASSERT_IF(type != ExprType::Void, f.localType(slot) == type);
     return true;
 }
 
 static bool
 EmitLoadGlobal(FunctionCompiler& f, ExprType type, MDefinition** def)
 {
     uint32_t index = f.readVarU32();
     const AsmJSGlobalVariable& global = f.mg().globalVar(index);
     *def = f.loadGlobalVar(global.globalDataOffset, global.isConst, ToMIRType(global.type));
-    MOZ_ASSERT_IF(type != ExprType::Limit, global.type == type);
+    MOZ_ASSERT_IF(type != ExprType::Void, global.type == type);
     return true;
 }
 
 static bool EmitExpr(FunctionCompiler&, ExprType, MDefinition**, LabelVector* = nullptr);
 static bool EmitExprStmt(FunctionCompiler&, MDefinition**, LabelVector* = nullptr);
 
 static bool
 EmitLoadArray(FunctionCompiler& f, Scalar::Type scalarType, MDefinition** def)
@@ -1429,30 +1434,30 @@ EmitStoreWithCoercion(FunctionCompiler& 
 }
 
 static bool
 EmitSetLocal(FunctionCompiler& f, ExprType expected, MDefinition** def)
 {
     uint32_t slot = f.readVarU32();
     MDefinition* expr;
     ExprType actual = f.localType(slot);
-    MOZ_ASSERT_IF(expected != ExprType::Limit, actual == expected);
+    MOZ_ASSERT_IF(expected != ExprType::Void, actual == expected);
     if (!EmitExpr(f, actual, &expr))
         return false;
     f.assign(slot, expr);
     *def = expr;
     return true;
 }
 
 static bool
 EmitStoreGlobal(FunctionCompiler& f, ExprType type, MDefinition**def)
 {
     uint32_t index = f.readVarU32();
     const AsmJSGlobalVariable& global = f.mg().globalVar(index);
-    MOZ_ASSERT_IF(type != ExprType::Limit, global.type == type);
+    MOZ_ASSERT_IF(type != ExprType::Void, global.type == type);
     MDefinition* expr;
     if (!EmitExpr(f, global.type, &expr))
         return false;
     f.storeGlobalVar(global.globalDataOffset, expr);
     *def = expr;
     return true;
 }
 
@@ -1566,17 +1571,17 @@ EmitCallArgs(FunctionCompiler& f, const 
 
 static bool
 EmitCall(FunctionCompiler& f, ExprType ret, MDefinition** def)
 {
     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
     uint32_t funcIndex = f.readU32();
 
     const Sig& sig = f.mg().funcSig(funcIndex);
-    MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Limit, sig.ret() == ret);
+    MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Void, sig.ret() == ret);
 
     FunctionCompiler::Call call(f, lineOrBytecode);
     if (!EmitCallArgs(f, sig, &call))
         return false;
 
     return f.internalCall(sig, funcIndex, call, def);
 }
 
@@ -1584,17 +1589,17 @@ static bool
 EmitFuncPtrCall(FunctionCompiler& f, ExprType ret, MDefinition** def)
 {
     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
     uint32_t mask = f.readU32();
     uint32_t globalDataOffset = f.readU32();
     uint32_t sigIndex = f.readU32();
 
     const Sig& sig = f.mg().sig(sigIndex);
-    MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Limit, sig.ret() == ret);
+    MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Void, sig.ret() == ret);
 
     MDefinition *index;
     if (!EmitExpr(f, ExprType::I32, &index))
         return false;
 
     FunctionCompiler::Call call(f, lineOrBytecode);
     if (!EmitCallArgs(f, sig, &call))
         return false;
@@ -1605,17 +1610,17 @@ EmitFuncPtrCall(FunctionCompiler& f, Exp
 static bool
 EmitCallImport(FunctionCompiler& f, ExprType ret, MDefinition** def)
 {
     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
     uint32_t importIndex = f.readU32();
 
     const ModuleImportGeneratorData& import = f.mg().import(importIndex);
     const Sig& sig = *import.sig;
-    MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Limit, sig.ret() == ret);
+    MOZ_ASSERT_IF(!IsVoid(sig.ret()) && ret != ExprType::Void, sig.ret() == ret);
 
     FunctionCompiler::Call call(f, lineOrBytecode);
     if (!EmitCallArgs(f, sig, &call))
         return false;
 
     return f.ffiCall(import.globalDataOffset, call, sig.ret(), def);
 }
 
@@ -2049,55 +2054,16 @@ EmitUnaryMir(FunctionCompiler& f, ExprTy
     MDefinition* in;
     if (!EmitExpr(f, type, &in))
         return false;
     *def = f.unary<T>(in, ToMIRType(type));
     return true;
 }
 
 static bool
-EmitTernary(FunctionCompiler& f, ExprType type, MDefinition** def)
-{
-    MDefinition* cond;
-    if (!EmitExpr(f, ExprType::I32, &cond))
-        return false;
-
-    MBasicBlock* thenBlock = nullptr;
-    MBasicBlock* elseBlock = nullptr;
-    if (!f.branchAndStartThen(cond, &thenBlock, &elseBlock))
-        return false;
-
-    MDefinition* ifTrue;
-    if (!EmitExpr(f, type, &ifTrue))
-        return false;
-
-    BlockVector thenBlocks;
-    if (!f.appendThenBlock(&thenBlocks))
-        return false;
-
-    f.pushPhiInput(ifTrue);
-
-    f.switchToElse(elseBlock);
-
-    MDefinition* ifFalse;
-    if (!EmitExpr(f, type, &ifFalse))
-        return false;
-
-    f.pushPhiInput(ifFalse);
-
-    if (!f.joinIfElse(thenBlocks))
-        return false;
-
-    MOZ_ASSERT_IF(ifTrue && ifFalse, ifTrue->type() == ifFalse->type());
-
-    *def = f.popPhiOutput();
-    return true;
-}
-
-static bool
 EmitMultiply(FunctionCompiler& f, ExprType type, MDefinition** def)
 {
     MDefinition* lhs;
     if (!EmitExpr(f, type, &lhs))
         return false;
     MDefinition* rhs;
     if (!EmitExpr(f, type, &rhs))
         return false;
@@ -2488,59 +2454,78 @@ EmitLabel(FunctionCompiler& f, LabelVect
         return false;
 
     return f.bindLabeledBreaks(&labels);
 }
 
 typedef bool HasElseBlock;
 
 static bool
-EmitIfElse(FunctionCompiler& f, bool hasElse)
+EmitIfElse(FunctionCompiler& f, bool hasElse, ExprType expected, MDefinition** def)
 {
     // Handle if/else-if chains using iteration instead of recursion. This
     // avoids blowing the C stack quota for long if/else-if chains and also
     // creates fewer MBasicBlocks at join points (by creating one join block
     // for the entire if/else-if chain).
     BlockVector thenBlocks;
 
+    *def = nullptr;
+
   recurse:
+    MOZ_ASSERT_IF(!hasElse, expected == ExprType::Void);
+
     MDefinition* condition;
     if (!EmitExpr(f, ExprType::I32, &condition))
         return false;
 
     MBasicBlock* thenBlock = nullptr;
     MBasicBlock* elseOrJoinBlock = nullptr;
     if (!f.branchAndStartThen(condition, &thenBlock, &elseOrJoinBlock))
         return false;
 
-    MDefinition* _;
-    if (!EmitExprStmt(f, &_))
+    // From this point, then block.
+    MDefinition* ifExpr;
+    if (!EmitExpr(f, expected, &ifExpr))
         return false;
 
+    if (expected != ExprType::Void)
+        f.pushPhiInput(ifExpr);
+
     if (!f.appendThenBlock(&thenBlocks))
         return false;
 
-    if (hasElse) {
-        f.switchToElse(elseOrJoinBlock);
-
-        Expr nextStmt = f.peekOpcode();
-        if (nextStmt == Expr::If || nextStmt == Expr::IfElse) {
-            hasElse = nextStmt == Expr::IfElse;
-            JS_ALWAYS_TRUE(f.readOpcode() == nextStmt);
-            goto recurse;
-        }
-
-        MDefinition* _;
-        if (!EmitExprStmt(f, &_))
-            return false;
-
-        return f.joinIfElse(thenBlocks);
-    } else {
+    if (!hasElse)
         return f.joinIf(thenBlocks, elseOrJoinBlock);
+
+    f.switchToElse(elseOrJoinBlock);
+
+    Expr nextStmt = f.peekOpcode();
+    if (nextStmt == Expr::If || nextStmt == Expr::IfElse) {
+        hasElse = nextStmt == Expr::IfElse;
+        JS_ALWAYS_TRUE(f.readOpcode() == nextStmt);
+        goto recurse;
     }
+
+    // From this point, else block.
+    MDefinition* elseExpr;
+    if (!EmitExpr(f, expected, &elseExpr))
+        return false;
+
+    if (expected != ExprType::Void)
+        f.pushPhiInput(elseExpr);
+
+    if (!f.joinIfElse(thenBlocks))
+        return false;
+
+    // Now we're on the join block.
+    if (expected != ExprType::Void)
+        *def = f.popPhiOutput();
+
+    MOZ_ASSERT((expected != ExprType::Void) == !!*def);
+    return true;
 }
 
 static bool
 EmitTableSwitch(FunctionCompiler& f)
 {
     bool hasDefault = f.readU8();
     int32_t low = f.readI32();
     int32_t high = f.readI32();
@@ -2645,21 +2630,19 @@ EmitExpr(FunctionCompiler& f, ExprType t
 
     switch (Expr op = f.readOpcode()) {
       case Expr::Nop:
         return true;
       case Expr::Block:
         return EmitBlock(f, type, def);
       case Expr::If:
       case Expr::IfElse:
-        return EmitIfElse(f, HasElseBlock(op == Expr::IfElse));
+        return EmitIfElse(f, HasElseBlock(op == Expr::IfElse), type, def);
       case Expr::TableSwitch:
         return EmitTableSwitch(f);
-      case Expr::Ternary:
-        return EmitTernary(f, type, def);
       case Expr::While:
         return EmitWhile(f, maybeLabels);
       case Expr::DoWhile:
         return EmitDoWhile(f, maybeLabels);
       case Expr::ForInitInc:
       case Expr::ForInitNoInc:
       case Expr::ForNoInitNoInc:
       case Expr::ForNoInitInc:
@@ -2977,17 +2960,17 @@ EmitExpr(FunctionCompiler& f, ExprType t
     }
 
     MOZ_CRASH("unexpected wasm opcode");
 }
 
 static bool
 EmitExprStmt(FunctionCompiler& f, MDefinition** def, LabelVector* maybeLabels)
 {
-    return EmitExpr(f, ExprType::Limit, def, maybeLabels);
+    return EmitExpr(f, ExprType::Void, def, maybeLabels);
 }
 
 bool
 wasm::IonCompileFunction(IonCompileTask* task)
 {
     int64_t before = PRMJ_Now();
 
     const FuncBytecode& func = task->func();