Modified: trunk/Source/_javascript_Core/ChangeLog (215907 => 215908)
--- trunk/Source/_javascript_Core/ChangeLog 2017-04-27 23:48:51 UTC (rev 215907)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-04-27 23:52:41 UTC (rev 215908)
@@ -1,3 +1,54 @@
+2017-04-27 Saam Barati <sbar...@apple.com>
+
+ B3::FoldPathConstants does not consider the fall through case for Switch
+ https://bugs.webkit.org/show_bug.cgi?id=171390
+
+ Reviewed by Filip Pizlo.
+
+ foldPathConstants was not taking into account a Switch's default
+ case when it tried to constant propagate the switch's operand value.
+ e.g, we incorrectly transformed this code:
+
+ ```
+ x = argumentGPR0;
+ switch (x) {
+ case 10: return 20;
+
+ case 0:
+ default: return x == 0;
+ }
+ ```
+
+ into:
+ ```
+ x = argumentGPR0;
+ switch (x) {
+ case 10: return 20;
+
+ case 0:
+ default: return 1;
+ }
+ ```
+
+ Because we didn't take into account the default case, we incorrectly
+ optimized the code as if case 0's block was only reachable if x is
+ equal to zero. This is obviously not true, since it's the same block
+ as the default case.
+
+ This fix ensures that we can run the WebAssembly Tanks demo even when
+ we set webAssemblyBBQOptimizationLevel=2.
+
+ * b3/B3FoldPathConstants.cpp:
+ * b3/B3SwitchValue.cpp:
+ (JSC::B3::SwitchValue::fallThrough):
+ (JSC::B3::SwitchValue::removeCase): Deleted.
+ * b3/B3SwitchValue.h:
+ * b3/testb3.cpp:
+ (JSC::B3::testCallFunctionWithHellaArguments):
+ (JSC::B3::testSwitchSameCaseAsDefault):
+ (JSC::B3::testWasmBoundsCheck):
+ (JSC::B3::run):
+
2017-04-27 Keith Miller <keith_mil...@apple.com>
WebAssembly: Don't tier up the same function twice
Modified: trunk/Source/_javascript_Core/b3/B3FoldPathConstants.cpp (215907 => 215908)
--- trunk/Source/_javascript_Core/b3/B3FoldPathConstants.cpp 2017-04-27 23:48:51 UTC (rev 215907)
+++ trunk/Source/_javascript_Core/b3/B3FoldPathConstants.cpp 2017-04-27 23:52:41 UTC (rev 215908)
@@ -100,11 +100,14 @@
Override::constant(block->successorBlock(1), 0));
break;
case Switch: {
+ SwitchValue* switchValue = branch->as<SwitchValue>();
+
HashMap<BasicBlock*, unsigned> targetUses;
- for (const SwitchCase& switchCase : branch->as<SwitchValue>()->cases(block))
+ for (const SwitchCase& switchCase : switchValue->cases(block))
targetUses.add(switchCase.targetBlock(), 0).iterator->value++;
+ targetUses.add(switchValue->fallThrough(block), 0).iterator->value++;
- for (const SwitchCase& switchCase : branch->as<SwitchValue>()->cases(block)) {
+ for (const SwitchCase& switchCase : switchValue->cases(block)) {
if (targetUses.find(switchCase.targetBlock())->value != 1)
continue;
Modified: trunk/Source/_javascript_Core/b3/B3SwitchValue.cpp (215907 => 215908)
--- trunk/Source/_javascript_Core/b3/B3SwitchValue.cpp 2017-04-27 23:48:51 UTC (rev 215907)
+++ trunk/Source/_javascript_Core/b3/B3SwitchValue.cpp 2017-04-27 23:52:41 UTC (rev 215908)
@@ -37,15 +37,12 @@
{
}
-SwitchCase SwitchValue::removeCase(BasicBlock* block, unsigned index)
+BasicBlock* SwitchValue::fallThrough(const BasicBlock* owner)
{
- FrequentedBlock resultBlock = block->successor(index);
- int64_t resultValue = m_values[index];
- block->successor(index) = block->successors().last();
- block->successors().removeLast();
- m_values[index] = m_values.last();
- m_values.removeLast();
- return SwitchCase(resultValue, resultBlock);
+ ASSERT(hasFallThrough());
+ BasicBlock* fallThrough = owner->successor(owner->numSuccessors() - 1).block();
+ ASSERT(fallThrough == owner->fallThrough().block());
+ return fallThrough;
}
bool SwitchValue::hasFallThrough(const BasicBlock* block) const
Modified: trunk/Source/_javascript_Core/b3/B3SwitchValue.h (215907 => 215908)
--- trunk/Source/_javascript_Core/b3/B3SwitchValue.h 2017-04-27 23:48:51 UTC (rev 215907)
+++ trunk/Source/_javascript_Core/b3/B3SwitchValue.h 2017-04-27 23:52:41 UTC (rev 215908)
@@ -50,14 +50,11 @@
CaseCollection cases(const BasicBlock* owner) const { return CaseCollection(this, owner); }
CaseCollection cases() const { return cases(owner); }
- // This removes the case and reorders things a bit. If you're iterating the cases from 0 to N,
- // then you can keep iterating after this so long as you revisit this same index (which will now
- // contain some other case value). This removes the case that was removed.
- SwitchCase removeCase(BasicBlock*, unsigned index);
-
bool hasFallThrough(const BasicBlock*) const;
bool hasFallThrough() const;
+ BasicBlock* fallThrough(const BasicBlock* owner);
+
// These two functions can be called in any order.
void setFallThrough(BasicBlock*, const FrequentedBlock&);
void appendCase(BasicBlock*, const SwitchCase&);
Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (215907 => 215908)
--- trunk/Source/_javascript_Core/b3/testb3.cpp 2017-04-27 23:48:51 UTC (rev 215907)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp 2017-04-27 23:52:41 UTC (rev 215908)
@@ -10291,6 +10291,9 @@
void testCallFunctionWithHellaArguments()
{
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=171392
+ return;
+
Procedure proc;
BasicBlock* root = proc.addBlock();
@@ -10748,6 +10751,44 @@
CHECK(!invoke<int32_t>(*code, degree * gap + 1, 42, 11));
}
+void testSwitchSameCaseAsDefault()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ BasicBlock* return10 = proc.addBlock();
+ return10->appendNewControlValue(
+ proc, Return, Origin(),
+ return10->appendNew<Const32Value>(proc, Origin(), 10));
+
+ Value* switchOperand = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+
+ BasicBlock* caseAndDefault = proc.addBlock();
+ caseAndDefault->appendNewControlValue(
+ proc, Return, Origin(),
+ caseAndDefault->appendNew<Value>(
+ proc, Equal, Origin(),
+ switchOperand, caseAndDefault->appendNew<ConstPtrValue>(proc, Origin(), 0)));
+
+ SwitchValue* switchValue = root->appendNew<SwitchValue>(proc, Origin(), switchOperand);
+
+ switchValue->appendCase(SwitchCase(100, FrequentedBlock(return10)));
+
+ // Because caseAndDefault is reached both as default case, and when it's 0,
+ // we should not incorrectly optimize and assume that switchOperand==0.
+ switchValue->appendCase(SwitchCase(0, FrequentedBlock(caseAndDefault)));
+ switchValue->setFallThrough(FrequentedBlock(caseAndDefault));
+
+ auto code = compileProc(proc);
+
+ CHECK(invoke<int32_t>(*code, 100) == 10);
+ CHECK(invoke<int32_t>(*code, 0) == 1);
+ CHECK(invoke<int32_t>(*code, 1) == 0);
+ CHECK(invoke<int32_t>(*code, 2) == 0);
+ CHECK(invoke<int32_t>(*code, 99) == 0);
+ CHECK(invoke<int32_t>(*code, 0xbaadbeef) == 0);
+}
+
void testSwitchChillDiv(unsigned degree, unsigned gap = 1)
{
Procedure proc;
@@ -15166,6 +15207,9 @@
void testWasmBoundsCheck(unsigned offset)
{
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=171392
+ return;
+
Procedure proc;
GPRReg pinned = GPRInfo::argumentGPR1;
proc.pinRegister(pinned);
@@ -16317,6 +16361,8 @@
RUN(testSwitch(100, 1));
RUN(testSwitch(100, 100));
+ RUN(testSwitchSameCaseAsDefault());
+
RUN(testSwitchChillDiv(0, 1));
RUN(testSwitchChillDiv(1, 1));
RUN(testSwitchChillDiv(2, 1));