testb3 and testair should test O0/O1/O2
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Feb 2019 03:16:44 +0000 (03:16 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Feb 2019 03:16:44 +0000 (03:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194637

Reviewed by Mark Lam.

This patch makes it so that we run all tests in testair and testb3
in O0, O1, and O2. However, some tests are invalid for O0 and O1.
This patch makes it so we only run those tests in O2. These are
often tests that assert certain optimizations have occurred. There
are also a class of tests that rely on using patchpoints to stress
the register allocator into only a single valid allocation. The
O0, and sometimes O1, register allocators are not always good enough
to allocate such programs. To make these valid allocators to use, we rely
on the FTL and Wasm to not emit such patchpoints.

* b3/air/testair.cpp:
(main):
* b3/testb3.cpp:
(JSC::B3::compileProc):
(JSC::B3::testAddLoadTwice):
(JSC::B3::testMulLoadTwice):
(JSC::B3::testSimplePatchpointWithOuputClobbersGPArgs):
(JSC::B3::testSimplePatchpointWithOuputClobbersFPArgs):
(JSC::B3::testPatchpointWithEarlyClobber):
(JSC::B3::testSimpleCheck):
(JSC::B3::testCheckFalse):
(JSC::B3::testCheckTrue):
(JSC::B3::testCheckLessThan):
(JSC::B3::testCheckMegaCombo):
(JSC::B3::testCheckTrickyMegaCombo):
(JSC::B3::testCheckTwoMegaCombos):
(JSC::B3::testCheckTwoNonRedundantMegaCombos):
(JSC::B3::testCheckAddImm):
(JSC::B3::testCheckAddImmCommute):
(JSC::B3::testCheckAddImmSomeRegister):
(JSC::B3::testCheckAdd):
(JSC::B3::testCheckAdd64):
(JSC::B3::testCheckAddFold):
(JSC::B3::testCheckAddFoldFail):
(JSC::B3::testCheckAddSelfOverflow64):
(JSC::B3::testCheckAddSelfOverflow32):
(JSC::B3::testCheckSubImm):
(JSC::B3::testCheckSubBadImm):
(JSC::B3::testCheckSub):
(JSC::B3::testCheckSub64):
(JSC::B3::testCheckSubFold):
(JSC::B3::testCheckSubFoldFail):
(JSC::B3::testCheckNeg):
(JSC::B3::testCheckNeg64):
(JSC::B3::testCheckMul):
(JSC::B3::testCheckMulMemory):
(JSC::B3::testCheckMul2):
(JSC::B3::testCheckMul64):
(JSC::B3::testCheckMulFold):
(JSC::B3::testCheckMulFoldFail):
(JSC::B3::testCheckMul64SShr):
(JSC::B3::testLinearScanWithCalleeOnStack):
(JSC::B3::testCheckSelect):
(JSC::B3::testCheckSelectCheckSelect):
(JSC::B3::testCheckSelectAndCSE):
(JSC::B3::testLateRegister):
(JSC::B3::testReduceStrengthCheckBottomUseInAnotherBlock):
(JSC::B3::testSomeEarlyRegister):
(JSC::B3::testTerminalPatchpointThatNeedsToBeSpilled2):
(JSC::B3::testPinRegisters):
(JSC::B3::testX86LeaAddAddShlLeft):
(JSC::B3::testX86LeaAddAddShlRight):
(JSC::B3::testX86LeaAddAdd):
(JSC::B3::testX86LeaAddShlRight):
(JSC::B3::testX86LeaAddShlLeftScale1):
(JSC::B3::testX86LeaAddShlLeftScale2):
(JSC::B3::testX86LeaAddShlLeftScale4):
(JSC::B3::testX86LeaAddShlLeftScale8):
(JSC::B3::testLoadBaseIndexShift2):
(JSC::B3::testOptimizeMaterialization):
(JSC::B3::testLICMPure):
(JSC::B3::testLICMPureSideExits):
(JSC::B3::testLICMPureWritesPinned):
(JSC::B3::testLICMPureWrites):
(JSC::B3::testLICMReadsPinned):
(JSC::B3::testLICMReads):
(JSC::B3::testLICMPureNotBackwardsDominant):
(JSC::B3::testLICMPureNotBackwardsDominantFoiledByChild):
(JSC::B3::testLICMControlDependent):
(JSC::B3::testLICMControlDependentNotBackwardsDominant):
(JSC::B3::testLICMReadsWritesDifferentHeaps):
(JSC::B3::testWasmBoundsCheck):
(JSC::B3::run):
(main):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242068 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/b3/air/testair.cpp
Source/JavaScriptCore/b3/testb3.cpp

index e340025..81d2b8b 100644 (file)
@@ -1,3 +1,95 @@
+2019-02-25  Saam Barati  <sbarati@apple.com>
+
+        testb3 and testair should test O0/O1/O2
+        https://bugs.webkit.org/show_bug.cgi?id=194637
+
+        Reviewed by Mark Lam.
+
+        This patch makes it so that we run all tests in testair and testb3
+        in O0, O1, and O2. However, some tests are invalid for O0 and O1.
+        This patch makes it so we only run those tests in O2. These are
+        often tests that assert certain optimizations have occurred. There
+        are also a class of tests that rely on using patchpoints to stress 
+        the register allocator into only a single valid allocation. The
+        O0, and sometimes O1, register allocators are not always good enough
+        to allocate such programs. To make these valid allocators to use, we rely
+        on the FTL and Wasm to not emit such patchpoints.
+
+        * b3/air/testair.cpp:
+        (main):
+        * b3/testb3.cpp:
+        (JSC::B3::compileProc):
+        (JSC::B3::testAddLoadTwice):
+        (JSC::B3::testMulLoadTwice):
+        (JSC::B3::testSimplePatchpointWithOuputClobbersGPArgs):
+        (JSC::B3::testSimplePatchpointWithOuputClobbersFPArgs):
+        (JSC::B3::testPatchpointWithEarlyClobber):
+        (JSC::B3::testSimpleCheck):
+        (JSC::B3::testCheckFalse):
+        (JSC::B3::testCheckTrue):
+        (JSC::B3::testCheckLessThan):
+        (JSC::B3::testCheckMegaCombo):
+        (JSC::B3::testCheckTrickyMegaCombo):
+        (JSC::B3::testCheckTwoMegaCombos):
+        (JSC::B3::testCheckTwoNonRedundantMegaCombos):
+        (JSC::B3::testCheckAddImm):
+        (JSC::B3::testCheckAddImmCommute):
+        (JSC::B3::testCheckAddImmSomeRegister):
+        (JSC::B3::testCheckAdd):
+        (JSC::B3::testCheckAdd64):
+        (JSC::B3::testCheckAddFold):
+        (JSC::B3::testCheckAddFoldFail):
+        (JSC::B3::testCheckAddSelfOverflow64):
+        (JSC::B3::testCheckAddSelfOverflow32):
+        (JSC::B3::testCheckSubImm):
+        (JSC::B3::testCheckSubBadImm):
+        (JSC::B3::testCheckSub):
+        (JSC::B3::testCheckSub64):
+        (JSC::B3::testCheckSubFold):
+        (JSC::B3::testCheckSubFoldFail):
+        (JSC::B3::testCheckNeg):
+        (JSC::B3::testCheckNeg64):
+        (JSC::B3::testCheckMul):
+        (JSC::B3::testCheckMulMemory):
+        (JSC::B3::testCheckMul2):
+        (JSC::B3::testCheckMul64):
+        (JSC::B3::testCheckMulFold):
+        (JSC::B3::testCheckMulFoldFail):
+        (JSC::B3::testCheckMul64SShr):
+        (JSC::B3::testLinearScanWithCalleeOnStack):
+        (JSC::B3::testCheckSelect):
+        (JSC::B3::testCheckSelectCheckSelect):
+        (JSC::B3::testCheckSelectAndCSE):
+        (JSC::B3::testLateRegister):
+        (JSC::B3::testReduceStrengthCheckBottomUseInAnotherBlock):
+        (JSC::B3::testSomeEarlyRegister):
+        (JSC::B3::testTerminalPatchpointThatNeedsToBeSpilled2):
+        (JSC::B3::testPinRegisters):
+        (JSC::B3::testX86LeaAddAddShlLeft):
+        (JSC::B3::testX86LeaAddAddShlRight):
+        (JSC::B3::testX86LeaAddAdd):
+        (JSC::B3::testX86LeaAddShlRight):
+        (JSC::B3::testX86LeaAddShlLeftScale1):
+        (JSC::B3::testX86LeaAddShlLeftScale2):
+        (JSC::B3::testX86LeaAddShlLeftScale4):
+        (JSC::B3::testX86LeaAddShlLeftScale8):
+        (JSC::B3::testLoadBaseIndexShift2):
+        (JSC::B3::testOptimizeMaterialization):
+        (JSC::B3::testLICMPure):
+        (JSC::B3::testLICMPureSideExits):
+        (JSC::B3::testLICMPureWritesPinned):
+        (JSC::B3::testLICMPureWrites):
+        (JSC::B3::testLICMReadsPinned):
+        (JSC::B3::testLICMReads):
+        (JSC::B3::testLICMPureNotBackwardsDominant):
+        (JSC::B3::testLICMPureNotBackwardsDominantFoiledByChild):
+        (JSC::B3::testLICMControlDependent):
+        (JSC::B3::testLICMControlDependentNotBackwardsDominant):
+        (JSC::B3::testLICMReadsWritesDifferentHeaps):
+        (JSC::B3::testWasmBoundsCheck):
+        (JSC::B3::run):
+        (main):
+
 2019-02-25  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] stress/function-constructor-reading-from-global-lexical-environment.js fails in 32bit arch
index 498487e..a564bc7 100644 (file)
@@ -2062,22 +2062,22 @@ void testLea32()
     CHECK(r == a + b);
 }
 
-#define RUN(test) do {                          \
-        if (!shouldRun(#test))                  \
-            break;                              \
-        tasks.append(                           \
-            createSharedTask<void()>(           \
-                [&] () {                        \
-                    dataLog(#test "...\n");     \
-                    test;                       \
-                    dataLog(#test ": OK!\n");   \
-                }));                            \
+#define PREFIX "O", Options::defaultB3OptLevel(), ": "
+
+#define RUN(test) do {                                 \
+        if (!shouldRun(#test))                         \
+            break;                                     \
+        tasks.append(                                  \
+            createSharedTask<void()>(                  \
+                [&] () {                               \
+                    dataLog(PREFIX #test "...\n");     \
+                    test;                              \
+                    dataLog(PREFIX #test ": OK!\n");   \
+                }));                                   \
     } while (false);
 
 void run(const char* filter)
 {
-    JSC::initializeThreading();
-
     Deque<RefPtr<SharedTask<void()>>> tasks;
 
     auto shouldRun = [&] (const char* testName) -> bool {
@@ -2178,6 +2178,7 @@ void run(const char* filter)
     for (auto& thread : threads)
         thread->waitForCompletion();
     crashLock.lock();
+    crashLock.unlock();
 }
 
 } // anonymous namespace
@@ -2205,6 +2206,12 @@ int main(int argc, char** argv)
         break;
     }
     
-    run(filter);
+    JSC::initializeThreading();
+
+    for (unsigned i = 0; i <= 2; ++i) {
+        JSC::Options::defaultB3OptLevel() = i;
+        run(filter);
+    }
+
     return 0;
 }
index 08be457..3f18842 100644 (file)
@@ -121,7 +121,7 @@ Lock crashLock;
         CRASH(); \
     } while (false)
 
-std::unique_ptr<Compilation> compileProc(Procedure& procedure, unsigned optLevel = defaultOptLevel())
+std::unique_ptr<Compilation> compileProc(Procedure& procedure, unsigned optLevel = Options::defaultB3OptLevel())
 {
     procedure.setOptLevel(optLevel);
     return std::make_unique<Compilation>(B3::compile(procedure));
@@ -660,7 +660,7 @@ void testAddArgZeroImmZDef()
 
 void testAddLoadTwice()
 {
-    auto test = [&] (unsigned optLevel) {
+    auto test = [&] () {
         Procedure proc;
         BasicBlock* root = proc.addBlock();
         int32_t value = 42;
@@ -671,12 +671,11 @@ void testAddLoadTwice()
             proc, Return, Origin(),
             root->appendNew<Value>(proc, Add, Origin(), load, load));
 
-        auto code = compileProc(proc, optLevel);
+        auto code = compileProc(proc);
         CHECK(invoke<int32_t>(*code) == 42 * 2);
     };
 
-    test(0);
-    test(1);
+    test();
 }
 
 void testAddArgDouble(double a)
@@ -1012,7 +1011,7 @@ void testMulArgs32(int a, int b)
 
 void testMulLoadTwice()
 {
-    auto test = [&] (unsigned optLevel) {
+    auto test = [&] () {
         Procedure proc;
         BasicBlock* root = proc.addBlock();
         int32_t value = 42;
@@ -1023,13 +1022,11 @@ void testMulLoadTwice()
             proc, Return, Origin(),
             root->appendNew<Value>(proc, Mul, Origin(), load, load));
 
-        auto code = compileProc(proc, optLevel);
+        auto code = compileProc(proc);
         CHECK(invoke<int32_t>(*code) == 42 * 42);
     };
 
-    test(0);
-    test(1);
-    test(2);
+    test();
 }
 
 void testMulAddArgsLeft()
@@ -3749,7 +3746,7 @@ void testBitNotOnBooleanAndBranch32(int64_t a, int64_t b)
     elseCase->appendNewControlValue(proc, Return, Origin(),
         elseCase->appendNew<Const32Value>(proc, Origin(), -42));
 
-    int32_t expectedValue = ~(a == b) ? 42 : -42; // always 42
+    static constexpr int32_t expectedValue = 42;
     CHECK(compileAndRun<int32_t>(proc, a, b) == expectedValue);
 }
 
@@ -8456,6 +8453,13 @@ void testSimplePatchpointWithOuputClobbersGPArgs()
     // spill everything else.
 
     Procedure proc;
+    if (proc.optLevel() < 1) {
+        // FIXME: Air O0 allocator can't handle such programs. We rely on WasmAirIRGenerator
+        // to not use any such constructs where the register allocator is cornered in such
+        // a way.
+        // https://bugs.webkit.org/show_bug.cgi?id=194633
+        return;
+    }
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
@@ -8529,6 +8533,13 @@ void testSimplePatchpointWithoutOuputClobbersFPArgs()
 void testSimplePatchpointWithOuputClobbersFPArgs()
 {
     Procedure proc;
+    if (proc.optLevel() < 1) {
+        // FIXME: Air O0 allocator can't handle such programs. We rely on WasmAirIRGenerator
+        // to not use any such constructs where the register allocator is cornered in such
+        // a way.
+        // https://bugs.webkit.org/show_bug.cgi?id=194633
+        return;
+    }
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
     Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
@@ -8579,10 +8590,13 @@ void testPatchpointWithEarlyClobber()
         patchpoint->append(ConstrainedValue(arg1, ValueRep::SomeRegister));
         patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
         patchpoint->clobberEarly(RegisterSet(registerToClobber));
+        unsigned optLevel = proc.optLevel();
         patchpoint->setGenerator(
             [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-                CHECK((params[1].gpr() == GPRInfo::argumentGPR0) == arg1InArgGPR);
-                CHECK((params[2].gpr() == GPRInfo::argumentGPR1) == arg2InArgGPR);
+                if (optLevel > 1) {
+                    CHECK((params[1].gpr() == GPRInfo::argumentGPR0) == arg1InArgGPR);
+                    CHECK((params[2].gpr() == GPRInfo::argumentGPR1) == arg2InArgGPR);
+                }
                 
                 add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr());
             });
@@ -8918,6 +8932,8 @@ void testPatchpointWithAnyResult()
 void testSimpleCheck()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     CheckValue* check = root->appendNew<CheckValue>(proc, Check, Origin(), arg);
@@ -8947,9 +8963,11 @@ void testCheckFalse()
     BasicBlock* root = proc.addBlock();
     CheckValue* check = root->appendNew<CheckValue>(
         proc, Check, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+    unsigned optLevel = proc.optLevel();
     check->setGenerator(
         [&] (CCallHelpers&, const StackmapGenerationParams&) {
-            CHECK(!"This should not have executed");
+            if (optLevel > 1)
+                CHECK(!"This should not have executed");
         });
     root->appendNewControlValue(
         proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -8962,13 +8980,17 @@ void testCheckFalse()
 void testCheckTrue()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     CheckValue* check = root->appendNew<CheckValue>(
         proc, Check, Origin(), root->appendNew<Const32Value>(proc, Origin(), 1));
+    unsigned optLevel = proc.optLevel();
     check->setGenerator(
         [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.value()->opcode() == Patchpoint);
+            if (optLevel > 1)
+                CHECK(params.value()->opcode() == Patchpoint);
             CHECK(!params.size());
 
             // This should always work because a function this simple should never have callee
@@ -8988,6 +9010,8 @@ void testCheckTrue()
 void testCheckLessThan()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9023,6 +9047,8 @@ void testCheckLessThan()
 void testCheckMegaCombo()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     Value* index = root->appendNew<Value>(
@@ -9075,6 +9101,8 @@ void testCheckMegaCombo()
 void testCheckTrickyMegaCombo()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     Value* index = root->appendNew<Value>(
@@ -9130,6 +9158,8 @@ void testCheckTrickyMegaCombo()
 void testCheckTwoMegaCombos()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     Value* index = root->appendNew<Value>(
@@ -9194,6 +9224,8 @@ void testCheckTwoMegaCombos()
 void testCheckTwoNonRedundantMegaCombos()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     
     BasicBlock* root = proc.addBlock();
     BasicBlock* thenCase = proc.addBlock();
@@ -9287,6 +9319,8 @@ void testCheckTwoNonRedundantMegaCombos()
 void testCheckAddImm()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9323,6 +9357,8 @@ void testCheckAddImm()
 void testCheckAddImmCommute()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9359,6 +9395,8 @@ void testCheckAddImmCommute()
 void testCheckAddImmSomeRegister()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9394,6 +9432,8 @@ void testCheckAddImmSomeRegister()
 void testCheckAdd()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9431,6 +9471,8 @@ void testCheckAdd()
 void testCheckAdd64()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
@@ -9468,9 +9510,11 @@ void testCheckAddFold(int a, int b)
     Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a);
     Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b);
     CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
+    unsigned optLevel = proc.optLevel();
     checkAdd->setGenerator(
         [&] (CCallHelpers&, const StackmapGenerationParams&) {
-            CHECK(!"Should have been folded");
+            if (optLevel > 1)
+                CHECK(!"Should have been folded");
         });
     root->appendNewControlValue(proc, Return, Origin(), checkAdd);
 
@@ -9482,6 +9526,8 @@ void testCheckAddFold(int a, int b)
 void testCheckAddFoldFail(int a, int b)
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a);
     Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b);
@@ -9583,6 +9629,8 @@ void testCheckAddArgumentAliasing32()
 void testCheckAddSelfOverflow64()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg, arg);
@@ -9612,6 +9660,8 @@ void testCheckAddSelfOverflow64()
 void testCheckAddSelfOverflow32()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9643,6 +9693,8 @@ void testCheckAddSelfOverflow32()
 void testCheckSubImm()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9679,6 +9731,8 @@ void testCheckSubImm()
 void testCheckSubBadImm()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9721,6 +9775,8 @@ void testCheckSubBadImm()
 void testCheckSub()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9763,6 +9819,8 @@ NEVER_INLINE double doubleSub(double a, double b)
 void testCheckSub64()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
@@ -9800,9 +9858,11 @@ void testCheckSubFold(int a, int b)
     Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a);
     Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b);
     CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
+    unsigned optLevel = proc.optLevel();
     checkSub->setGenerator(
         [&] (CCallHelpers&, const StackmapGenerationParams&) {
-            CHECK(!"Should have been folded");
+            if (optLevel > 1)
+                CHECK(!"Should have been folded");
         });
     root->appendNewControlValue(proc, Return, Origin(), checkSub);
 
@@ -9814,6 +9874,8 @@ void testCheckSubFold(int a, int b)
 void testCheckSubFoldFail(int a, int b)
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a);
     Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b);
@@ -9835,6 +9897,8 @@ void testCheckSubFoldFail(int a, int b)
 void testCheckNeg()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), 0);
     Value* arg2 = root->appendNew<Value>(
@@ -9867,6 +9931,8 @@ void testCheckNeg()
 void testCheckNeg64()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Const64Value>(proc, Origin(), 0);
     Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
@@ -9897,6 +9963,8 @@ void testCheckNeg64()
 void testCheckMul()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -9934,6 +10002,8 @@ void testCheckMul()
 void testCheckMulMemory()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
 
     int left;
@@ -9986,6 +10056,8 @@ void testCheckMulMemory()
 void testCheckMul2()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, Trunc, Origin(),
@@ -10022,6 +10094,8 @@ void testCheckMul2()
 void testCheckMul64()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
@@ -10059,9 +10133,11 @@ void testCheckMulFold(int a, int b)
     Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a);
     Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b);
     CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
+    unsigned optLevel = proc.optLevel();
     checkMul->setGenerator(
         [&] (CCallHelpers&, const StackmapGenerationParams&) {
-            CHECK(!"Should have been folded");
+            if (optLevel > 1)
+                CHECK(!"Should have been folded");
         });
     root->appendNewControlValue(proc, Return, Origin(), checkMul);
 
@@ -10073,6 +10149,8 @@ void testCheckMulFold(int a, int b)
 void testCheckMulFoldFail(int a, int b)
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a);
     Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b);
@@ -10174,6 +10252,8 @@ void testCheckMulArgumentAliasing32()
 void testCheckMul64SShr()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
     Value* arg1 = root->appendNew<Value>(
         proc, SShr, Origin(),
@@ -10824,7 +10904,7 @@ void testLinearScanWithCalleeOnStack()
 
     // Compiling with 1 as the optimization level enforces the use of linear scan
     // for register allocation.
-    auto code = compileProc(proc, 1);
+    auto code = compileProc(proc);
     CHECK_EQ(invoke<int>(*code, 41, 1), 42);
 
     Options::airLinearScanSpillsEverything() = original;
@@ -12379,6 +12459,8 @@ void testSelectInvert()
 void testCheckSelect()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
 
     CheckValue* check = root->appendNew<CheckValue>(
@@ -12421,6 +12503,8 @@ void testCheckSelect()
 void testCheckSelectCheckSelect()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
 
     CheckValue* check = root->appendNew<CheckValue>(
@@ -12494,6 +12578,8 @@ void testCheckSelectCheckSelect()
 void testCheckSelectAndCSE()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     BasicBlock* root = proc.addBlock();
 
     auto* selectValue = root->appendNew<Value>(
@@ -13228,6 +13314,13 @@ void testSpillUseLargerThanDef()
 void testLateRegister()
 {
     Procedure proc;
+
+    if (!proc.optLevel()) {
+        // FIXME: Make O0 handle such situations:
+        // https://bugs.webkit.org/show_bug.cgi?id=194633
+        return;
+    }
+
     BasicBlock* root = proc.addBlock();
 
     // This works by making all but 1 register be input to the first patchpoint as LateRegister.
@@ -13539,6 +13632,8 @@ void testInterpreter()
 void testReduceStrengthCheckBottomUseInAnotherBlock()
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     
     BasicBlock* one = proc.addBlock();
     BasicBlock* two = proc.addBlock();
@@ -13981,11 +14076,12 @@ void testSomeEarlyRegister()
         if (succeed)
             patchpoint->resultConstraint = ValueRep::SomeEarlyRegister;
         bool ranSecondPatchpoint = false;
+        unsigned optLevel = proc.optLevel();
         patchpoint->setGenerator(
             [&] (CCallHelpers&, const StackmapGenerationParams& params) {
                 if (succeed)
                     CHECK(params[0].gpr() != params[1].gpr());
-                else
+                else if (optLevel > 1)
                     CHECK(params[0].gpr() == params[1].gpr());
                 ranSecondPatchpoint = true;
             });
@@ -14111,6 +14207,13 @@ void testTerminalPatchpointThatNeedsToBeSpilled2()
 {
     // This is a unit test for how FTL's heap allocation fast paths behave.
     Procedure proc;
+
+    // FIXME: Air O0/O1 allocator can't handle such programs. We rely on WasmAirIRGenerator
+    // to not use any such constructs where the register allocator is cornered in such
+    // a way.
+    // https://bugs.webkit.org/show_bug.cgi?id=194633
+    if (proc.optLevel() < 2)
+        return;
     
     BasicBlock* root = proc.addBlock();
     BasicBlock* one = proc.addBlock();
@@ -14571,9 +14674,11 @@ void testPinRegisters()
             a, b, c);
         PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
         patchpoint->appendSomeRegister(d);
+        unsigned optLevel = proc.optLevel();
         patchpoint->setGenerator(
             [&] (CCallHelpers&, const StackmapGenerationParams& params) {
-                CHECK_EQ(params[0].gpr(), GPRInfo::regCS0);
+                if (optLevel > 1)
+                    CHECK_EQ(params[0].gpr(), GPRInfo::regCS0);
             });
         root->appendNew<Value>(proc, Return, Origin());
         auto code = compileProc(proc);
@@ -14589,6 +14694,11 @@ void testPinRegisters()
                     });
             }
         }
+        if (proc.optLevel() < 2) {
+            // Our less good register allocators may use the
+            // pinned CSRs in a move.
+            usesCSRs = false;
+        }
         for (const RegisterAtOffset& regAtOffset : proc.calleeSaveRegisterAtOffsetList())
             usesCSRs |= csrs.get(regAtOffset.reg());
         CHECK_EQ(usesCSRs, !pin);
@@ -14616,7 +14726,10 @@ void testX86LeaAddAddShlLeft()
     root->appendNew<Value>(proc, Return, Origin(), result);
     
     auto code = compileProc(proc);
-    checkUsesInstruction(*code, "lea 0x64(%rdi,%rsi,4), %rax");
+    if (proc.optLevel() > 1)
+        checkUsesInstruction(*code, "lea 0x64(%rdi,%rsi,4), %rax");
+    else
+        checkUsesInstruction(*code, "lea");
     CHECK_EQ(invoke<intptr_t>(*code, 1, 2), (1 + (2 << 2)) + 100);
 }
 
@@ -14638,7 +14751,10 @@ void testX86LeaAddAddShlRight()
     root->appendNew<Value>(proc, Return, Origin(), result);
     
     auto code = compileProc(proc);
-    checkUsesInstruction(*code, "lea 0x64(%rdi,%rsi,4), %rax");
+    if (proc.optLevel() > 1)
+        checkUsesInstruction(*code, "lea 0x64(%rdi,%rsi,4), %rax");
+    else
+        checkUsesInstruction(*code, "lea");
     CHECK_EQ(invoke<intptr_t>(*code, 1, 2), (1 + (2 << 2)) + 100);
 }
 
@@ -14658,13 +14774,15 @@ void testX86LeaAddAdd()
     
     auto code = compileProc(proc);
     CHECK_EQ(invoke<intptr_t>(*code, 1, 2), (1 + 2) + 100);
-    checkDisassembly(
-        *code,
-        [&] (const char* disassembly) -> bool {
-            return strstr(disassembly, "lea 0x64(%rdi,%rsi), %rax")
-                || strstr(disassembly, "lea 0x64(%rsi,%rdi), %rax");
-        },
-        "Expected to find something like lea 0x64(%rdi,%rsi), %rax but didn't!");
+    if (proc.optLevel() > 1) {
+        checkDisassembly(
+            *code,
+            [&] (const char* disassembly) -> bool {
+                return strstr(disassembly, "lea 0x64(%rdi,%rsi), %rax")
+                    || strstr(disassembly, "lea 0x64(%rsi,%rdi), %rax");
+            },
+            "Expected to find something like lea 0x64(%rdi,%rsi), %rax but didn't!");
+    }
 }
 
 void testX86LeaAddShlRight()
@@ -14682,7 +14800,10 @@ void testX86LeaAddShlRight()
     root->appendNew<Value>(proc, Return, Origin(), result);
     
     auto code = compileProc(proc);
-    checkUsesInstruction(*code, "lea (%rdi,%rsi,4), %rax");
+    if (proc.optLevel() > 1)
+        checkUsesInstruction(*code, "lea (%rdi,%rsi,4), %rax");
+    else
+        checkUsesInstruction(*code, "lea");
     CHECK_EQ(invoke<intptr_t>(*code, 1, 2), 1 + (2 << 2));
 }
 
@@ -14702,13 +14823,15 @@ void testX86LeaAddShlLeftScale1()
     
     auto code = compileProc(proc);
     CHECK_EQ(invoke<intptr_t>(*code, 1, 2), 1 + 2);
-    checkDisassembly(
-        *code,
-        [&] (const char* disassembly) -> bool {
-            return strstr(disassembly, "lea (%rdi,%rsi), %rax")
-                || strstr(disassembly, "lea (%rsi,%rdi), %rax");
-        },
-        "Expected to find something like lea (%rdi,%rsi), %rax but didn't!");
+    if (proc.optLevel() > 1) {
+        checkDisassembly(
+            *code,
+            [&] (const char* disassembly) -> bool {
+                return strstr(disassembly, "lea (%rdi,%rsi), %rax")
+                    || strstr(disassembly, "lea (%rsi,%rdi), %rax");
+            },
+            "Expected to find something like lea (%rdi,%rsi), %rax but didn't!");
+    }
 }
 
 void testX86LeaAddShlLeftScale2()
@@ -14726,7 +14849,10 @@ void testX86LeaAddShlLeftScale2()
     root->appendNew<Value>(proc, Return, Origin(), result);
     
     auto code = compileProc(proc);
-    checkUsesInstruction(*code, "lea (%rdi,%rsi,2), %rax");
+    if (proc.optLevel() > 1)
+        checkUsesInstruction(*code, "lea (%rdi,%rsi,2), %rax");
+    else
+        checkUsesInstruction(*code, "lea");
     CHECK_EQ(invoke<intptr_t>(*code, 1, 2), 1 + (2 << 1));
 }
 
@@ -14745,7 +14871,10 @@ void testX86LeaAddShlLeftScale4()
     root->appendNew<Value>(proc, Return, Origin(), result);
     
     auto code = compileProc(proc);
-    checkUsesInstruction(*code, "lea (%rdi,%rsi,4), %rax");
+    if (proc.optLevel() > 1)
+        checkUsesInstruction(*code, "lea (%rdi,%rsi,4), %rax");
+    else
+        checkUsesInstruction(*code, "lea");
     CHECK_EQ(invoke<intptr_t>(*code, 1, 2), 1 + (2 << 2));
 }
 
@@ -14764,7 +14893,10 @@ void testX86LeaAddShlLeftScale8()
     root->appendNew<Value>(proc, Return, Origin(), result);
     
     auto code = compileProc(proc);
-    checkUsesInstruction(*code, "lea (%rdi,%rsi,8), %rax");
+    if (proc.optLevel() > 1)
+        checkUsesInstruction(*code, "lea (%rdi,%rsi,8), %rax");
+    else
+        checkUsesInstruction(*code, "lea");
     CHECK_EQ(invoke<intptr_t>(*code, 1, 2), 1 + (2 << 3));
 }
 
@@ -14883,7 +15015,7 @@ void testLoadBaseIndexShift2()
                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
                     root->appendNew<Const32Value>(proc, Origin(), 2)))));
     auto code = compileProc(proc);
-    if (isX86())
+    if (isX86() && proc.optLevel() > 1)
         checkUsesInstruction(*code, "(%rdi,%rsi,4)");
     int32_t value = 12341234;
     char* ptr = bitwise_cast<char*>(&value);
@@ -14918,6 +15050,9 @@ void testLoadBaseIndexShift32()
 void testOptimizeMaterialization()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
+
     BasicBlock* root = proc.addBlock();
     root->appendNew<CCallValue>(
         proc, Void, Origin(),
@@ -15046,6 +15181,10 @@ static void noOpFunction()
 void testLICMPure()
 {
     Procedure proc;
+
+    if (proc.optLevel() < 2)
+        return;
+
     generateLoop(
         proc,
         [&] (BasicBlock* loop, Value*) -> Value* {
@@ -15063,6 +15202,8 @@ void testLICMPure()
 void testLICMPureSideExits()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     generateLoop(
         proc,
         [&] (BasicBlock* loop, Value*) -> Value* {
@@ -15086,6 +15227,8 @@ void testLICMPureSideExits()
 void testLICMPureWritesPinned()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     generateLoop(
         proc,
         [&] (BasicBlock* loop, Value*) -> Value* {
@@ -15109,6 +15252,8 @@ void testLICMPureWritesPinned()
 void testLICMPureWrites()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     generateLoop(
         proc,
         [&] (BasicBlock* loop, Value*) -> Value* {
@@ -15151,6 +15296,8 @@ void testLICMReadsLocalState()
 void testLICMReadsPinned()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     generateLoop(
         proc,
         [&] (BasicBlock* loop, Value*) -> Value* {
@@ -15170,6 +15317,8 @@ void testLICMReadsPinned()
 void testLICMReads()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     generateLoop(
         proc,
         [&] (BasicBlock* loop, Value*) -> Value* {
@@ -15189,6 +15338,8 @@ void testLICMReads()
 void testLICMPureNotBackwardsDominant()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     auto array = makeArrayForLoops();
     generateLoopNotBackwardsDominant(
         proc, array,
@@ -15225,6 +15376,8 @@ void testLICMPureFoiledByChild()
 void testLICMPureNotBackwardsDominantFoiledByChild()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     auto array = makeArrayForLoops();
     generateLoopNotBackwardsDominant(
         proc, array,
@@ -15339,6 +15492,8 @@ void testLICMWritesPinned()
 void testLICMControlDependent()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     generateLoop(
         proc,
         [&] (BasicBlock* loop, Value*) -> Value* {
@@ -15358,6 +15513,8 @@ void testLICMControlDependent()
 void testLICMControlDependentNotBackwardsDominant()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     auto array = makeArrayForLoops();
     generateLoopNotBackwardsDominant(
         proc, array,
@@ -15428,6 +15585,8 @@ void testLICMReadsPinnedWritesPinned()
 void testLICMReadsWritesDifferentHeaps()
 {
     Procedure proc;
+    if (proc.optLevel() < 2)
+        return;
     generateLoop(
         proc,
         [&] (BasicBlock* loop, Value*) -> Value* {
@@ -16209,6 +16368,8 @@ void testDepend64()
 void testWasmBoundsCheck(unsigned offset)
 {
     Procedure proc;
+    if (proc.optLevel() < 1)
+        return;
     GPRReg pinned = GPRInfo::argumentGPR1;
     proc.pinRegister(pinned);
 
@@ -16576,28 +16737,30 @@ double negativeZero()
     return -zero();
 }
 
+#define PREFIX "O", Options::defaultB3OptLevel(), ": "
+
 #define RUN_NOW(test) do {                      \
         if (!shouldRun(#test))                  \
             break;                              \
-        dataLog(#test "...\n");                 \
+        dataLog(PREFIX #test "...\n");          \
         test;                                   \
-        dataLog(#test ": OK!\n");               \
+        dataLog(PREFIX #test ": OK!\n");        \
     } while (false)
-#define RUN(test) do {                          \
-        if (!shouldRun(#test))                  \
-            break;                              \
-        tasks.append(                           \
-            createSharedTask<void()>(           \
-                [&] () {                        \
-                    dataLog(#test "...\n");     \
-                    test;                       \
-                    dataLog(#test ": OK!\n");   \
-                }));                            \
+#define RUN(test) do {                                 \
+        if (!shouldRun(#test))                         \
+            break;                                     \
+        tasks.append(                                  \
+            createSharedTask<void()>(                  \
+                [&] () {                               \
+                    dataLog(PREFIX #test "...\n");     \
+                    test;                              \
+                    dataLog(PREFIX #test ": OK!\n");   \
+                }));                                   \
     } while (false);
 
 #define RUN_UNARY(test, values) \
     for (auto a : values) {                             \
-        CString testStr = toCString(#test, "(", a.name, ")"); \
+        CString testStr = toCString(PREFIX #test, "(", a.name, ")"); \
         if (!shouldRun(testStr.data()))                 \
             continue;                                   \
         tasks.append(createSharedTask<void()>(          \
@@ -16611,7 +16774,7 @@ double negativeZero()
 #define RUN_BINARY(test, valuesA, valuesB) \
     for (auto a : valuesA) {                                \
         for (auto b : valuesB) {                            \
-            CString testStr = toCString(#test, "(", a.name, ", ", b.name, ")"); \
+            CString testStr = toCString(PREFIX #test, "(", a.name, ", ", b.name, ")"); \
             if (!shouldRun(testStr.data()))                 \
                 continue;                                   \
             tasks.append(createSharedTask<void()>(          \
@@ -16641,8 +16804,6 @@ double negativeZero()
 
 void run(const char* filter)
 {
-    JSC::initializeThreading();
-
     Deque<RefPtr<SharedTask<void()>>> tasks;
 
     auto shouldRun = [&] (const char* testName) -> bool {
@@ -18219,6 +18380,7 @@ void run(const char* filter)
     for (auto& thread : threads)
         thread->waitForCompletion();
     crashLock.lock();
+    crashLock.unlock();
 }
 
 } // anonymous namespace
@@ -18245,8 +18407,14 @@ int main(int argc, char** argv)
         usage();
         break;
     }
+
+    JSC::initializeThreading();
     
-    run(filter);
+    for (unsigned i = 0; i <= 2; ++i) {
+        JSC::Options::defaultB3OptLevel() = i;
+        run(filter);
+    }
+
     return 0;
 }