MacroAssemblerX86 should be happy with shift(cx, cx)
[WebKit-https.git] / Source / JavaScriptCore / b3 / testb3.cpp
index eee1226..f792c00 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
 #include "B3BasicBlockInlines.h"
 #include "B3CCallValue.h"
 #include "B3Compilation.h"
+#include "B3ComputeDivisionMagic.h"
 #include "B3Const32Value.h"
 #include "B3ConstPtrValue.h"
 #include "B3ControlValue.h"
@@ -37,7 +38,8 @@
 #include "B3MathExtras.h"
 #include "B3MemoryValue.h"
 #include "B3Procedure.h"
-#include "B3StackSlotValue.h"
+#include "B3SlotBaseValue.h"
+#include "B3StackSlot.h"
 #include "B3StackmapGenerationParams.h"
 #include "B3SwitchValue.h"
 #include "B3UpsilonValue.h"
@@ -136,6 +138,77 @@ void testLoad42()
     CHECK(compileAndRun<int>(proc) == 42);
 }
 
+void testLoadWithOffsetImpl(int32_t offset64, int32_t offset32)
+{
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        int64_t x = -42;
+        Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, Load, Int64, Origin(),
+                base,
+                offset64));
+
+        char* address = reinterpret_cast<char*>(&x) - offset64;
+        CHECK(compileAndRun<int64_t>(proc, address) == -42);
+    }
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        int32_t x = -42;
+        Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, Load, Int32, Origin(),
+                base,
+                offset32));
+
+        char* address = reinterpret_cast<char*>(&x) - offset32;
+        CHECK(compileAndRun<int32_t>(proc, address) == -42);
+    }
+}
+
+void testLoadOffsetImm9Max()
+{
+    testLoadWithOffsetImpl(255, 255);
+}
+
+void testLoadOffsetImm9MaxPlusOne()
+{
+    testLoadWithOffsetImpl(256, 256);
+}
+
+void testLoadOffsetImm9MaxPlusTwo()
+{
+    testLoadWithOffsetImpl(257, 257);
+}
+
+void testLoadOffsetImm9Min()
+{
+    testLoadWithOffsetImpl(-256, -256);
+}
+
+void testLoadOffsetImm9MinMinusOne()
+{
+    testLoadWithOffsetImpl(-257, -257);
+}
+
+void testLoadOffsetScaledUnsignedImm12Max()
+{
+    testLoadWithOffsetImpl(32760, 16380);
+}
+
+void testLoadOffsetScaledUnsignedOverImm12Max()
+{
+    testLoadWithOffsetImpl(32760, 32760);
+    testLoadWithOffsetImpl(32761, 16381);
+    testLoadWithOffsetImpl(32768, 16384);
+}
+
 void testArg(int argument)
 {
     Procedure proc;
@@ -4044,6 +4117,84 @@ void testStorePartial8BitRegisterOnX86()
     CHECK(!storage);
 }
 
+void testStore16Arg()
+{
+    { // Direct addressing.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* value = root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+
+        root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address);
+        root->appendNew<ControlValue>(proc, Return, Origin(), value);
+
+        int16_t storage = -1;
+        CHECK(compileAndRun<int64_t>(proc, 42, &storage) == 42);
+        CHECK(storage == 42);
+    }
+
+    { // Indexed addressing.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* value = root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+        Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
+        Value* displacement = root->appendNew<Const64Value>(proc, Origin(), -1);
+
+        Value* baseDisplacement = root->appendNew<Value>(proc, Add, Origin(), displacement, base);
+        Value* address = root->appendNew<Value>(proc, Add, Origin(), baseDisplacement, offset);
+
+        root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address);
+        root->appendNew<ControlValue>(proc, Return, Origin(), value);
+
+        int16_t storage = -1;
+        CHECK(compileAndRun<int64_t>(proc, 42, &storage, 1) == 42);
+        CHECK(storage == 42);
+    }
+}
+
+void testStore16Imm()
+{
+    { // Direct addressing.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* value = root->appendNew<Const32Value>(proc, Origin(), 42);
+        Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+
+        root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address);
+        root->appendNew<ControlValue>(proc, Return, Origin(), value);
+
+        int16_t storage = -1;
+        CHECK(compileAndRun<int64_t>(proc, &storage) == 42);
+        CHECK(storage == 42);
+    }
+
+    { // Indexed addressing.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* value = root->appendNew<Const32Value>(proc, Origin(), 42);
+        Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+        Value* displacement = root->appendNew<Const64Value>(proc, Origin(), -1);
+
+        Value* baseDisplacement = root->appendNew<Value>(proc, Add, Origin(), displacement, base);
+        Value* address = root->appendNew<Value>(proc, Add, Origin(), baseDisplacement, offset);
+
+        root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address);
+        root->appendNew<ControlValue>(proc, Return, Origin(), value);
+
+        int16_t storage = -1;
+        CHECK(compileAndRun<int64_t>(proc, &storage, 1) == 42);
+        CHECK(storage == 42);
+    }
+}
+
 void testTrunc(int64_t value)
 {
     Procedure proc;
@@ -4117,7 +4268,7 @@ void testNegPtr(intptr_t value)
     CHECK(compileAndRun<intptr_t>(proc, value) == -value);
 }
 
-void testStoreAddLoad(int amount)
+void testStoreAddLoad32(int amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
@@ -4128,28 +4279,50 @@ void testStoreAddLoad(int amount)
         root->appendNew<Value>(
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
-            root->appendNew<Const32Value>(proc, Origin(), amount)),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
         slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(!compileAndRun<int>(proc));
+    CHECK(!compileAndRun<int>(proc, amount));
     CHECK(slot == 37 + amount);
 }
 
-void testStoreSubLoad(int amount)
+void testStoreAddLoadImm32(int amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int32_t startValue = std::numeric_limits<int32_t>::min();
-    int32_t slot = startValue;
+    int slot = 37;
     ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
     root->appendNew<MemoryValue>(
         proc, Store, Origin(),
         root->appendNew<Value>(
-            proc, Sub, Origin(),
+            proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
+            root->appendNew<Const32Value>(proc, Origin(), amount)),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
+}
+
+void testStoreAddLoad8(int amount, B3::Opcode loadOpcode)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int8_t slot = 37;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    root->appendNew<MemoryValue>(
+        proc, Store8, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
@@ -4159,865 +4332,1063 @@ void testStoreSubLoad(int amount)
         root->appendNew<Const32Value>(proc, Origin(), 0));
 
     CHECK(!compileAndRun<int>(proc, amount));
-    CHECK(slot == startValue - amount);
+    CHECK(slot == 37 + amount);
 }
 
-void testStoreAddLoadInterference(int amount)
+void testStoreAddLoadImm8(int amount, B3::Opcode loadOpcode)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int slot = 37;
+    int8_t slot = 37;
     ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
-    ArgumentRegValue* otherSlotPtr =
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr);
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 666),
-        otherSlotPtr);
     root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
+        proc, Store8, Origin(),
         root->appendNew<Value>(
             proc, Add, Origin(),
-            load, root->appendNew<Const32Value>(proc, Origin(), amount)),
+            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
+            root->appendNew<Const32Value>(proc, Origin(), amount)),
         slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(!compileAndRun<int>(proc, &slot));
+    CHECK(!compileAndRun<int>(proc));
     CHECK(slot == 37 + amount);
 }
 
-void testStoreAddAndLoad(int amount, int mask)
+void testStoreAddLoad16(int amount, B3::Opcode loadOpcode)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int slot = 37;
+    int16_t slot = 37;
     ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
     root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
+        proc, Store16, Origin(),
         root->appendNew<Value>(
-            proc, BitAnd, Origin(),
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
             root->appendNew<Value>(
-                proc, Add, Origin(),
-                root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
-                root->appendNew<Const32Value>(proc, Origin(), amount)),
-            root->appendNew<Const32Value>(proc, Origin(), mask)),
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
         slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == ((37 + amount) & mask));
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37 + amount);
 }
 
-void testStoreNegLoad32(int32_t value)
+void testStoreAddLoadImm16(int amount, B3::Opcode loadOpcode)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-
-    int32_t slot = value;
-
+    int16_t slot = 37;
     ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
-    
     root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
+        proc, Store16, Origin(),
         root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), 0),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr)),
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
+            root->appendNew<Const32Value>(proc, Origin(), amount)),
         slotPtr);
-    
     root->appendNew<ControlValue>(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(!compileAndRun<int32_t>(proc));
-    CHECK(slot == -value);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
 }
 
-void testStoreNegLoadPtr(intptr_t value)
+void testStoreAddLoad64(int amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-
-    intptr_t slot = value;
-
+    int64_t slot = 37000000000ll;
     ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
-    
     root->appendNew<MemoryValue>(
         proc, Store, Origin(),
         root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), 0),
-            root->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), slotPtr)),
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
         slotPtr);
-    
     root->appendNew<ControlValue>(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(!compileAndRun<int32_t>(proc));
-    CHECK(slot == -value);
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37000000000ll + amount);
 }
 
-void testAdd1Uncommuted(int value)
+void testStoreAddLoadImm64(int64_t amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
+    int64_t slot = 370000000000ll;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
         root->appendNew<Value>(
             proc, Add, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), 1),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
+            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
+            root->appendNew<Const64Value>(proc, Origin(), amount)),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, value) == value + 1);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 370000000000ll + amount);
 }
 
-void testLoadOffset()
+void testStoreAddLoad32Index(int amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int array[] = { 1, 2 };
-    ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array);
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
+    int slot = 37;
+    int* ptr = &slot;
+    intptr_t zero = 0;
+    Value* slotPtr = root->appendNew<Value>(
+        proc, Add, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &zero)));
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
         root->appendNew<Value>(
             proc, Add, Origin(),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37 + amount);
 }
 
-void testLoadOffsetNotConstant()
+void testStoreAddLoadImm32Index(int amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int array[] = { 1, 2 };
-    Value* arrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
+    int slot = 37;
+    int* ptr = &slot;
+    intptr_t zero = 0;
+    Value* slotPtr = root->appendNew<Value>(
+        proc, Add, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &zero)));
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
+            root->appendNew<Const32Value>(proc, Origin(), amount)),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
 }
 
-void testLoadOffsetUsingAdd()
+void testStoreAddLoad8Index(int amount, B3::Opcode loadOpcode)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int array[] = { 1, 2 };
-    ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array);
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
+    int8_t slot = 37;
+    int8_t* ptr = &slot;
+    intptr_t zero = 0;
+    Value* slotPtr = root->appendNew<Value>(
+        proc, Add, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &zero)));
+    root->appendNew<MemoryValue>(
+        proc, Store8, Origin(),
         root->appendNew<Value>(
             proc, Add, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, Load, Int32, Origin(),
-                root->appendNew<Value>(
-                    proc, Add, Origin(), arrayPtr,
-                    root->appendNew<ConstPtrValue>(proc, Origin(), 0))),
-            root->appendNew<MemoryValue>(
-                proc, Load, Int32, Origin(),
-                root->appendNew<Value>(
-                    proc, Add, Origin(), arrayPtr,
-                    root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
-    
-    CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
+            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37 + amount);
 }
 
-void testLoadOffsetUsingAddInterference()
+void testStoreAddLoadImm8Index(int amount, B3::Opcode loadOpcode)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int array[] = { 1, 2 };
-    ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array);
-    ArgumentRegValue* otherArrayPtr =
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Const32Value* theNumberOfTheBeast = root->appendNew<Const32Value>(proc, Origin(), 666);
-    MemoryValue* left = root->appendNew<MemoryValue>(
-        proc, Load, Int32, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(), arrayPtr,
-            root->appendNew<ConstPtrValue>(proc, Origin(), 0)));
-    MemoryValue* right = root->appendNew<MemoryValue>(
-        proc, Load, Int32, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(), arrayPtr,
-            root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))));
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, 0);
+    int8_t slot = 37;
+    int8_t* ptr = &slot;
+    intptr_t zero = 0;
+    Value* slotPtr = root->appendNew<Value>(
+        proc, Add, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &zero)));
     root->appendNew<MemoryValue>(
-        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, sizeof(int));
+        proc, Store8, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
+            root->appendNew<Const32Value>(proc, Origin(), amount)),
+        slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(), left, right));
-    
-    CHECK(compileAndRun<int>(proc, &array[0]) == 1 + 2);
-    CHECK(array[0] == 666);
-    CHECK(array[1] == 666);
+        root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
 }
 
-void testLoadOffsetUsingAddNotConstant()
+void testStoreAddLoad16Index(int amount, B3::Opcode loadOpcode)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int array[] = { 1, 2 };
-    Value* arrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
+    int16_t slot = 37;
+    int16_t* ptr = &slot;
+    intptr_t zero = 0;
+    Value* slotPtr = root->appendNew<Value>(
+        proc, Add, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &zero)));
+    root->appendNew<MemoryValue>(
+        proc, Store16, Origin(),
         root->appendNew<Value>(
             proc, Add, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, Load, Int32, Origin(),
-                root->appendNew<Value>(
-                    proc, Add, Origin(), arrayPtr,
-                    root->appendNew<ConstPtrValue>(proc, Origin(), 0))),
-            root->appendNew<MemoryValue>(
-                proc, Load, Int32, Origin(),
-                root->appendNew<Value>(
-                    proc, Add, Origin(), arrayPtr,
-                    root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
-    
-    CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
+            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37 + amount);
 }
 
-void testLoadAddrShift(unsigned shift)
+void testStoreAddLoadImm16Index(int amount, B3::Opcode loadOpcode)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int slots[2];
-
-    // Figure out which slot to use while having proper alignment for the shift.
-    int* slot;
-    uintptr_t arg;
-    for (unsigned i = sizeof(slots)/sizeof(slots[0]); i--;) {
-        slot = slots + i;
-        arg = bitwise_cast<uintptr_t>(slot) >> shift;
-        if (bitwise_cast<int*>(arg << shift) == slot)
-            break;
-    }
-
-    *slot = 8675309;
-    
+    int16_t slot = 37;
+    int16_t* ptr = &slot;
+    intptr_t zero = 0;
+    Value* slotPtr = root->appendNew<Value>(
+        proc, Add, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &zero)));
+    root->appendNew<MemoryValue>(
+        proc, Store16, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
+            root->appendNew<Const32Value>(proc, Origin(), amount)),
+        slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load, Int32, Origin(),
-            root->appendNew<Value>(
-                proc, Shl, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                root->appendNew<Const32Value>(proc, Origin(), shift))));
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, arg) == 8675309);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
 }
 
-void testFramePointer()
+void testStoreAddLoad64Index(int amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    int64_t slot = 37000000000ll;
+    int64_t* ptr = &slot;
+    intptr_t zero = 0;
+    Value* slotPtr = root->appendNew<Value>(
+        proc, Add, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &zero)));
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, FramePointer, Origin()));
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    void* fp = compileAndRun<void*>(proc);
-    CHECK(fp < &proc);
-    CHECK(fp >= bitwise_cast<char*>(&proc) - 10000);
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37000000000ll + amount);
 }
 
-void testStackSlot()
+void testStoreAddLoadImm64Index(int64_t amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    int64_t slot = 370000000000ll;
+    int64_t* ptr = &slot;
+    intptr_t zero = 0;
+    Value* slotPtr = root->appendNew<Value>(
+        proc, Add, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &zero)));
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
+            root->appendNew<Const64Value>(proc, Origin(), amount)),
+        slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<StackSlotValue>(proc, Origin(), 1, StackSlotKind::Anonymous));
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    void* stackSlot = compileAndRun<void*>(proc);
-    CHECK(stackSlot < &proc);
-    CHECK(stackSlot >= bitwise_cast<char*>(&proc) - 10000);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 370000000000ll + amount);
 }
 
-void testLoadFromFramePointer()
+void testStoreSubLoad(int amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    int32_t startValue = std::numeric_limits<int32_t>::min();
+    int32_t slot = startValue;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Sub, Origin(),
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load, pointerType(), Origin(),
-            root->appendNew<Value>(proc, FramePointer, Origin())));
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    void* fp = compileAndRun<void*>(proc);
-    void* myFP = __builtin_frame_address(0);
-    CHECK(fp <= myFP);
-    CHECK(fp >= bitwise_cast<char*>(myFP) - 10000);
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == startValue - amount);
 }
 
-void testStoreLoadStackSlot(int value)
+void testStoreAddLoadInterference(int amount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    int slot = 37;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    ArgumentRegValue* otherSlotPtr =
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr);
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 666),
+        otherSlotPtr);
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            load, root->appendNew<Const32Value>(proc, Origin(), amount)),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    StackSlotValue* stack = root->appendNew<StackSlotValue>(
-        proc, Origin(), sizeof(int), StackSlotKind::Anonymous);
+    CHECK(!compileAndRun<int>(proc, &slot));
+    CHECK(slot == 37 + amount);
+}
 
+void testStoreAddAndLoad(int amount, int mask)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int slot = 37;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
     root->appendNew<MemoryValue>(
         proc, Store, Origin(),
         root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        stack);
-    
+            proc, BitAnd, Origin(),
+            root->appendNew<Value>(
+                proc, Add, Origin(),
+                root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
+                root->appendNew<Const32Value>(proc, Origin(), amount)),
+            root->appendNew<Const32Value>(proc, Origin(), mask)),
+        slotPtr);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), stack));
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, value) == value);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == ((37 + amount) & mask));
 }
 
-template<typename LoadedType, typename EffectiveType>
-EffectiveType modelLoad(EffectiveType value)
+void testStoreNegLoad32(int32_t value)
 {
-    union {
-        EffectiveType original;
-        LoadedType loaded;
-    } u;
-
-    u.original = value;
-    if (std::is_signed<LoadedType>::value)
-        return static_cast<EffectiveType>(u.loaded);
-    return static_cast<EffectiveType>(static_cast<typename std::make_unsigned<EffectiveType>::type>(u.loaded));
-}
-
-template<>
-float modelLoad<float, float>(float value) { return value; }
-
-template<>
-double modelLoad<double, double>(double value) { return value; }
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
 
-template<B3::Type type, typename CType, typename InputType>
-void testLoad(B3::Opcode opcode, InputType value)
-{
-    // Simple load from an absolute address.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, opcode, type, Origin(),
-                root->appendNew<ConstPtrValue>(proc, Origin(), &value)));
+    int32_t slot = value;
 
-        CHECK(isIdentical(compileAndRun<CType>(proc), modelLoad<CType>(value)));
-    }
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
     
-    // Simple load from an address in a register.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, opcode, type, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-        CHECK(isIdentical(compileAndRun<CType>(proc, &value), modelLoad<CType>(value)));
-    }
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Sub, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), 0),
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr)),
+        slotPtr);
     
-    // Simple load from an address in a register, at an offset.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, opcode, type, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                sizeof(InputType)));
-
-        CHECK(isIdentical(compileAndRun<CType>(proc, &value - 1), modelLoad<CType>(value)));
-    }
-
-    // Load from a simple base-index with various scales.
-    for (unsigned logScale = 0; logScale <= 3; ++logScale) {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, opcode, type, Origin(),
-                root->appendNew<Value>(
-                    proc, Add, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                    root->appendNew<Value>(
-                        proc, Shl, Origin(),
-                        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
-                        root->appendNew<Const32Value>(proc, Origin(), logScale)))));
-
-        CHECK(isIdentical(compileAndRun<CType>(proc, &value - 2, (sizeof(InputType) * 2) >> logScale), modelLoad<CType>(value)));
-    }
-
-    // Load from a simple base-index with various scales, but commuted.
-    for (unsigned logScale = 0; logScale <= 3; ++logScale) {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, opcode, type, Origin(),
-                root->appendNew<Value>(
-                    proc, Add, Origin(),
-                    root->appendNew<Value>(
-                        proc, Shl, Origin(),
-                        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
-                        root->appendNew<Const32Value>(proc, Origin(), logScale)),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
-
-        CHECK(isIdentical(compileAndRun<CType>(proc, &value - 2, (sizeof(InputType) * 2) >> logScale), modelLoad<CType>(value)));
-    }
-}
-
-template<typename T>
-void testLoad(B3::Opcode opcode, int32_t value)
-{
-    return testLoad<Int32, T>(opcode, value);
-}
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-template<B3::Type type, typename T>
-void testLoad(T value)
-{
-    return testLoad<type, T>(Load, value);
+    CHECK(!compileAndRun<int32_t>(proc));
+    CHECK(slot == -value);
 }
 
-void testStoreFloat(double input)
+void testStoreNegLoadPtr(intptr_t value)
 {
-    // Simple store from an address in a register.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-        Value* argumentAsFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
-
-        Value* destinationAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-        root->appendNew<MemoryValue>(proc, Store, Origin(), argumentAsFloat, destinationAddress);
-
-        root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-        float output = 0.;
-        CHECK(!compileAndRun<int64_t>(proc, input, &output));
-        CHECK(isIdentical(static_cast<float>(input), output));
-    }
-
-    // Simple indexed store.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-        Value* argumentAsFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
-
-        Value* destinationBaseAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-        Value* index = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-        Value* scaledIndex = root->appendNew<Value>(
-            proc, Shl, Origin(),
-            index,
-            root->appendNew<Const32Value>(proc, Origin(), 2));
-        Value* destinationAddress = root->appendNew<Value>(proc, Add, Origin(), scaledIndex, destinationBaseAddress);
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
 
-        root->appendNew<MemoryValue>(proc, Store, Origin(), argumentAsFloat, destinationAddress);
+    intptr_t slot = value;
 
-        root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Sub, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), 0),
+            root->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), slotPtr)),
+        slotPtr);
+    
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-        float output = 0.;
-        CHECK(!compileAndRun<int64_t>(proc, input, &output - 1, 1));
-        CHECK(isIdentical(static_cast<float>(input), output));
-    }
+    CHECK(!compileAndRun<int32_t>(proc));
+    CHECK(slot == -value);
 }
 
-void testSpillGP()
+void testAdd1Uncommuted(int value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), 1),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    Vector<Value*> sources;
-    sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-
-    for (unsigned i = 0; i < 30; ++i) {
-        sources.append(
-            root->appendNew<Value>(proc, Add, Origin(), sources[sources.size() - 1], sources[sources.size() - 2])
-        );
-    }
-
-    Value* total = root->appendNew<Const64Value>(proc, Origin(), 0);
-    for (Value* value : sources)
-        total = root->appendNew<Value>(proc, Add, Origin(), total, value);
-
-    root->appendNew<ControlValue>(proc, Return, Origin(), total);
-    compileAndRun<int>(proc, 1, 2);
+    CHECK(compileAndRun<int>(proc, value) == value + 1);
 }
 
-void testSpillFP()
+void testLoadOffset()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    int array[] = { 1, 2 };
+    ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
 
-    Vector<Value*> sources;
-    sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
-    sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1));
-
-    for (unsigned i = 0; i < 30; ++i) {
-        sources.append(
-            root->appendNew<Value>(proc, Add, Origin(), sources[sources.size() - 1], sources[sources.size() - 2])
-        );
-    }
-
-    Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.);
-    for (Value* value : sources)
-        total = root->appendNew<Value>(proc, Add, Origin(), total, value);
-
-    root->appendNew<ControlValue>(proc, Return, Origin(), total);
-    compileAndRun<double>(proc, 1.1, 2.5);
+    CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
 }
 
-void testInt32ToDoublePartialRegisterStall()
+void testLoadOffsetNotConstant()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* loop = proc.addBlock();
-    BasicBlock* done = proc.addBlock();
+    int array[] = { 1, 2 };
+    Value* arrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
 
-    // Head.
-    Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.);
-    Value* counter = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    UpsilonValue* originalTotal = root->appendNew<UpsilonValue>(proc, Origin(), total);
-    UpsilonValue* originalCounter = root->appendNew<UpsilonValue>(proc, Origin(), counter);
-    root->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop));
+    CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
+}
 
-    // Loop.
-    Value* loopCounter = loop->appendNew<Value>(proc, Phi, Int64, Origin());
-    Value* loopTotal = loop->appendNew<Value>(proc, Phi, Double, Origin());
-    originalCounter->setPhi(loopCounter);
-    originalTotal->setPhi(loopTotal);
+void testLoadOffsetUsingAdd()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int array[] = { 1, 2 };
+    ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, Load, Int32, Origin(),
+                root->appendNew<Value>(
+                    proc, Add, Origin(), arrayPtr,
+                    root->appendNew<ConstPtrValue>(proc, Origin(), 0))),
+            root->appendNew<MemoryValue>(
+                proc, Load, Int32, Origin(),
+                root->appendNew<Value>(
+                    proc, Add, Origin(), arrayPtr,
+                    root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
+    
+    CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
+}
 
-    Value* truncatedCounter = loop->appendNew<Value>(proc, Trunc, Origin(), loopCounter);
-    Value* doubleCounter = loop->appendNew<Value>(proc, IToD, Origin(), truncatedCounter);
-    Value* updatedTotal = loop->appendNew<Value>(proc, Add, Origin(), doubleCounter, loopTotal);
-    UpsilonValue* updatedTotalUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), updatedTotal);
-    updatedTotalUpsilon->setPhi(loopTotal);
+void testLoadOffsetUsingAddInterference()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int array[] = { 1, 2 };
+    ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array);
+    ArgumentRegValue* otherArrayPtr =
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Const32Value* theNumberOfTheBeast = root->appendNew<Const32Value>(proc, Origin(), 666);
+    MemoryValue* left = root->appendNew<MemoryValue>(
+        proc, Load, Int32, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(), arrayPtr,
+            root->appendNew<ConstPtrValue>(proc, Origin(), 0)));
+    MemoryValue* right = root->appendNew<MemoryValue>(
+        proc, Load, Int32, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(), arrayPtr,
+            root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))));
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, 0);
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, sizeof(int));
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(), left, right));
+    
+    CHECK(compileAndRun<int>(proc, &array[0]) == 1 + 2);
+    CHECK(array[0] == 666);
+    CHECK(array[1] == 666);
+}
 
-    Value* decCounter = loop->appendNew<Value>(proc, Sub, Origin(), loopCounter, loop->appendNew<Const64Value>(proc, Origin(), 1));
-    UpsilonValue* decCounterUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), decCounter);
-    decCounterUpsilon->setPhi(loopCounter);
-    loop->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        decCounter,
-        FrequentedBlock(loop), FrequentedBlock(done));
+void testLoadOffsetUsingAddNotConstant()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int array[] = { 1, 2 };
+    Value* arrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, Load, Int32, Origin(),
+                root->appendNew<Value>(
+                    proc, Add, Origin(), arrayPtr,
+                    root->appendNew<ConstPtrValue>(proc, Origin(), 0))),
+            root->appendNew<MemoryValue>(
+                proc, Load, Int32, Origin(),
+                root->appendNew<Value>(
+                    proc, Add, Origin(), arrayPtr,
+                    root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
+    
+    CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
+}
 
-    // Tail.
-    done->appendNew<ControlValue>(proc, Return, Origin(), updatedTotal);
-    CHECK(isIdentical(compileAndRun<double>(proc, 100000), 5000050000.));
+void testLoadAddrShift(unsigned shift)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int slots[2];
+
+    // Figure out which slot to use while having proper alignment for the shift.
+    int* slot;
+    uintptr_t arg;
+    for (unsigned i = sizeof(slots)/sizeof(slots[0]); i--;) {
+        slot = slots + i;
+        arg = bitwise_cast<uintptr_t>(slot) >> shift;
+        if (bitwise_cast<int*>(arg << shift) == slot)
+            break;
+    }
+
+    *slot = 8675309;
+    
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, Int32, Origin(),
+            root->appendNew<Value>(
+                proc, Shl, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<Const32Value>(proc, Origin(), shift))));
+
+    CHECK(compileAndRun<int>(proc, arg) == 8675309);
 }
 
-void testInt32ToDoublePartialRegisterWithoutStall()
+void testFramePointer()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* loop = proc.addBlock();
-    BasicBlock* done = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, FramePointer, Origin()));
 
-    // Head.
-    Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.);
-    Value* counter = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    UpsilonValue* originalTotal = root->appendNew<UpsilonValue>(proc, Origin(), total);
-    UpsilonValue* originalCounter = root->appendNew<UpsilonValue>(proc, Origin(), counter);
-    uint64_t forPaddingInput;
-    Value* forPaddingInputAddress = root->appendNew<ConstPtrValue>(proc, Origin(), &forPaddingInput);
-    uint64_t forPaddingOutput;
-    Value* forPaddingOutputAddress = root->appendNew<ConstPtrValue>(proc, Origin(), &forPaddingOutput);
-    root->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop));
+    void* fp = compileAndRun<void*>(proc);
+    CHECK(fp < &proc);
+    CHECK(fp >= bitwise_cast<char*>(&proc) - 10000);
+}
 
-    // Loop.
-    Value* loopCounter = loop->appendNew<Value>(proc, Phi, Int64, Origin());
-    Value* loopTotal = loop->appendNew<Value>(proc, Phi, Double, Origin());
-    originalCounter->setPhi(loopCounter);
-    originalTotal->setPhi(loopTotal);
+void testOverrideFramePointer()
+{
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
 
-    Value* truncatedCounter = loop->appendNew<Value>(proc, Trunc, Origin(), loopCounter);
-    Value* doubleCounter = loop->appendNew<Value>(proc, IToD, Origin(), truncatedCounter);
-    Value* updatedTotal = loop->appendNew<Value>(proc, Add, Origin(), doubleCounter, loopTotal);
+        // Add a stack slot to make the frame non trivial.
+        root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(8));
 
-    // Add enough padding instructions to avoid a stall.
-    Value* loadPadding = loop->appendNew<MemoryValue>(proc, Load, Int64, Origin(), forPaddingInputAddress);
-    Value* padding = loop->appendNew<Value>(proc, BitXor, Origin(), loadPadding, loopCounter);
-    padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, BitXor, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, BitXor, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter);
-    padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter);
-    loop->appendNew<MemoryValue>(proc, Store, Origin(), padding, forPaddingOutputAddress);
+        // Sub on x86 UseDef the source. If FP is not protected correctly, it will be overridden since it is the last visible use.
+        Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* fp = root->appendNew<Value>(proc, FramePointer, Origin());
+        Value* result = root->appendNew<Value>(proc, Sub, Origin(), fp, offset);
 
-    UpsilonValue* updatedTotalUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), updatedTotal);
-    updatedTotalUpsilon->setPhi(loopTotal);
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        CHECK(compileAndRun<int64_t>(proc, 1));
+    }
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
 
-    Value* decCounter = loop->appendNew<Value>(proc, Sub, Origin(), loopCounter, loop->appendNew<Const64Value>(proc, Origin(), 1));
-    UpsilonValue* decCounterUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), decCounter);
-    decCounterUpsilon->setPhi(loopCounter);
-    loop->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        decCounter,
-        FrequentedBlock(loop), FrequentedBlock(done));
+        root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(8));
 
-    // Tail.
-    done->appendNew<ControlValue>(proc, Return, Origin(), updatedTotal);
-    CHECK(isIdentical(compileAndRun<double>(proc, 100000), 5000050000.));
+        Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* fp = root->appendNew<Value>(proc, FramePointer, Origin());
+        Value* offsetFP = root->appendNew<Value>(proc, BitAnd, Origin(), offset, fp);
+        Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+        Value* offsetArg = root->appendNew<Value>(proc, Add, Origin(), offset, arg);
+        Value* result = root->appendNew<Value>(proc, Add, Origin(), offsetArg, offsetFP);
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        CHECK(compileAndRun<int64_t>(proc, 1, 2));
+    }
 }
 
-void testBranch()
+void testStackSlot()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(1)));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    void* stackSlot = compileAndRun<void*>(proc);
+    CHECK(stackSlot < &proc);
+    CHECK(stackSlot >= bitwise_cast<char*>(&proc) - 10000);
 }
 
-void testBranchPtr()
+void testLoadFromFramePointer()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<Value>(proc, FramePointer, Origin())));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, static_cast<intptr_t>(42)) == 1);
-    CHECK(invoke<int>(*code, static_cast<intptr_t>(0)) == 0);
+    void* fp = compileAndRun<void*>(proc);
+    void* myFP = __builtin_frame_address(0);
+    CHECK(fp <= myFP);
+    CHECK(fp >= bitwise_cast<char*>(myFP) - 10000);
 }
 
-void testDiamond()
+void testStoreLoadStackSlot(int value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* done = proc.addBlock();
 
-    root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
+    SlotBaseValue* stack =
+        root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(sizeof(int)));
+
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
         root->appendNew<Value>(
             proc, Trunc, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+        stack);
+    
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), stack));
 
-    UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>(
-        proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-    thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
-
-    UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(
-        proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-    elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+    CHECK(compileAndRun<int>(proc, value) == value);
+}
 
-    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
-    thenResult->setPhi(phi);
-    elseResult->setPhi(phi);
-    done->appendNew<ControlValue>(proc, Return, Origin(), phi);
+template<typename LoadedType, typename EffectiveType>
+EffectiveType modelLoad(EffectiveType value)
+{
+    union {
+        EffectiveType original;
+        LoadedType loaded;
+    } u;
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    u.original = value;
+    if (std::is_signed<LoadedType>::value)
+        return static_cast<EffectiveType>(u.loaded);
+    return static_cast<EffectiveType>(static_cast<typename std::make_unsigned<EffectiveType>::type>(u.loaded));
 }
 
-void testBranchNotEqual()
+template<>
+float modelLoad<float, float>(float value) { return value; }
+
+template<>
+double modelLoad<double, double>(double value) { return value; }
+
+template<B3::Type type, typename CType, typename InputType>
+void testLoad(B3::Opcode opcode, InputType value)
 {
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
+    // Simple load from an absolute address.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, opcode, type, Origin(),
+                root->appendNew<ConstPtrValue>(proc, Origin(), &value)));
 
-    root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, NotEqual, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), 0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+        CHECK(isIdentical(compileAndRun<CType>(proc), modelLoad<CType>(value)));
+    }
+    
+    // Simple load from an address in a register.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, opcode, type, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+        CHECK(isIdentical(compileAndRun<CType>(proc, &value), modelLoad<CType>(value)));
+    }
+    
+    // Simple load from an address in a register, at an offset.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, opcode, type, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                sizeof(InputType)));
 
-    elseCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        CHECK(isIdentical(compileAndRun<CType>(proc, &value - 1), modelLoad<CType>(value)));
+    }
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
-}
+    // Load from a simple base-index with various scales.
+    for (unsigned logScale = 0; logScale <= 3; ++logScale) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
 
-void testBranchNotEqualCommute()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, opcode, type, Origin(),
+                root->appendNew<Value>(
+                    proc, Add, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                    root->appendNew<Value>(
+                        proc, Shl, Origin(),
+                        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+                        root->appendNew<Const32Value>(proc, Origin(), logScale)))));
 
-    root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, NotEqual, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), 0),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+        CHECK(isIdentical(compileAndRun<CType>(proc, &value - 2, (sizeof(InputType) * 2) >> logScale), modelLoad<CType>(value)));
+    }
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+    // Load from a simple base-index with various scales, but commuted.
+    for (unsigned logScale = 0; logScale <= 3; ++logScale) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
 
-    elseCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<MemoryValue>(
+                proc, opcode, type, Origin(),
+                root->appendNew<Value>(
+                    proc, Add, Origin(),
+                    root->appendNew<Value>(
+                        proc, Shl, Origin(),
+                        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+                        root->appendNew<Const32Value>(proc, Origin(), logScale)),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+        CHECK(isIdentical(compileAndRun<CType>(proc, &value - 2, (sizeof(InputType) * 2) >> logScale), modelLoad<CType>(value)));
+    }
 }
 
-void testBranchNotEqualNotEqual()
+template<typename T>
+void testLoad(B3::Opcode opcode, int32_t value)
 {
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
+    return testLoad<Int32, T>(opcode, value);
+}
 
-    root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, NotEqual, Origin(),
-            root->appendNew<Value>(
-                proc, NotEqual, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-                root->appendNew<Const32Value>(proc, Origin(), 0)),
-            root->appendNew<Const32Value>(proc, Origin(), 0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+template<B3::Type type, typename T>
+void testLoad(T value)
+{
+    return testLoad<type, T>(Load, value);
+}
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+void testStoreFloat(double input)
+{
+    // Simple store from an address in a register.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* argumentAsFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
 
-    elseCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        Value* destinationAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        root->appendNew<MemoryValue>(proc, Store, Origin(), argumentAsFloat, destinationAddress);
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
-}
+        root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-void testBranchEqual()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
+        float output = 0.;
+        CHECK(!compileAndRun<int64_t>(proc, input, &output));
+        CHECK(isIdentical(static_cast<float>(input), output));
+    }
 
-    root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, Equal, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), 0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+    // Simple indexed store.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* argumentAsFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+        Value* destinationBaseAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+        Value* scaledIndex = root->appendNew<Value>(
+            proc, Shl, Origin(),
+            index,
+            root->appendNew<Const32Value>(proc, Origin(), 2));
+        Value* destinationAddress = root->appendNew<Value>(proc, Add, Origin(), scaledIndex, destinationBaseAddress);
 
-    elseCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+        root->appendNew<MemoryValue>(proc, Store, Origin(), argumentAsFloat, destinationAddress);
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+        root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+        float output = 0.;
+        CHECK(!compileAndRun<int64_t>(proc, input, &output - 1, 1));
+        CHECK(isIdentical(static_cast<float>(input), output));
+    }
 }
 
-void testBranchEqualEqual()
+void testSpillGP()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
 
-    root->appendNew<ControlValue>(
+    Vector<Value*> sources;
+    sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+
+    for (unsigned i = 0; i < 30; ++i) {
+        sources.append(
+            root->appendNew<Value>(proc, Add, Origin(), sources[sources.size() - 1], sources[sources.size() - 2])
+        );
+    }
+
+    Value* total = root->appendNew<Const64Value>(proc, Origin(), 0);
+    for (Value* value : sources)
+        total = root->appendNew<Value>(proc, Add, Origin(), total, value);
+
+    root->appendNew<ControlValue>(proc, Return, Origin(), total);
+    compileAndRun<int>(proc, 1, 2);
+}
+
+void testSpillFP()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Vector<Value*> sources;
+    sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
+    sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1));
+
+    for (unsigned i = 0; i < 30; ++i) {
+        sources.append(
+            root->appendNew<Value>(proc, Add, Origin(), sources[sources.size() - 1], sources[sources.size() - 2])
+        );
+    }
+
+    Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.);
+    for (Value* value : sources)
+        total = root->appendNew<Value>(proc, Add, Origin(), total, value);
+
+    root->appendNew<ControlValue>(proc, Return, Origin(), total);
+    compileAndRun<double>(proc, 1.1, 2.5);
+}
+
+void testInt32ToDoublePartialRegisterStall()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* loop = proc.addBlock();
+    BasicBlock* done = proc.addBlock();
+
+    // Head.
+    Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.);
+    Value* counter = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    UpsilonValue* originalTotal = root->appendNew<UpsilonValue>(proc, Origin(), total);
+    UpsilonValue* originalCounter = root->appendNew<UpsilonValue>(proc, Origin(), counter);
+    root->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop));
+
+    // Loop.
+    Value* loopCounter = loop->appendNew<Value>(proc, Phi, Int64, Origin());
+    Value* loopTotal = loop->appendNew<Value>(proc, Phi, Double, Origin());
+    originalCounter->setPhi(loopCounter);
+    originalTotal->setPhi(loopTotal);
+
+    Value* truncatedCounter = loop->appendNew<Value>(proc, Trunc, Origin(), loopCounter);
+    Value* doubleCounter = loop->appendNew<Value>(proc, IToD, Origin(), truncatedCounter);
+    Value* updatedTotal = loop->appendNew<Value>(proc, Add, Origin(), doubleCounter, loopTotal);
+    UpsilonValue* updatedTotalUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), updatedTotal);
+    updatedTotalUpsilon->setPhi(loopTotal);
+
+    Value* decCounter = loop->appendNew<Value>(proc, Sub, Origin(), loopCounter, loop->appendNew<Const64Value>(proc, Origin(), 1));
+    UpsilonValue* decCounterUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), decCounter);
+    decCounterUpsilon->setPhi(loopCounter);
+    loop->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        decCounter,
+        FrequentedBlock(loop), FrequentedBlock(done));
+
+    // Tail.
+    done->appendNew<ControlValue>(proc, Return, Origin(), updatedTotal);
+    CHECK(isIdentical(compileAndRun<double>(proc, 100000), 5000050000.));
+}
+
+void testInt32ToDoublePartialRegisterWithoutStall()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* loop = proc.addBlock();
+    BasicBlock* done = proc.addBlock();
+
+    // Head.
+    Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.);
+    Value* counter = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    UpsilonValue* originalTotal = root->appendNew<UpsilonValue>(proc, Origin(), total);
+    UpsilonValue* originalCounter = root->appendNew<UpsilonValue>(proc, Origin(), counter);
+    uint64_t forPaddingInput;
+    Value* forPaddingInputAddress = root->appendNew<ConstPtrValue>(proc, Origin(), &forPaddingInput);
+    uint64_t forPaddingOutput;
+    Value* forPaddingOutputAddress = root->appendNew<ConstPtrValue>(proc, Origin(), &forPaddingOutput);
+    root->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop));
+
+    // Loop.
+    Value* loopCounter = loop->appendNew<Value>(proc, Phi, Int64, Origin());
+    Value* loopTotal = loop->appendNew<Value>(proc, Phi, Double, Origin());
+    originalCounter->setPhi(loopCounter);
+    originalTotal->setPhi(loopTotal);
+
+    Value* truncatedCounter = loop->appendNew<Value>(proc, Trunc, Origin(), loopCounter);
+    Value* doubleCounter = loop->appendNew<Value>(proc, IToD, Origin(), truncatedCounter);
+    Value* updatedTotal = loop->appendNew<Value>(proc, Add, Origin(), doubleCounter, loopTotal);
+
+    // Add enough padding instructions to avoid a stall.
+    Value* loadPadding = loop->appendNew<MemoryValue>(proc, Load, Int64, Origin(), forPaddingInputAddress);
+    Value* padding = loop->appendNew<Value>(proc, BitXor, Origin(), loadPadding, loopCounter);
+    padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, BitXor, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, BitXor, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter);
+    padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter);
+    loop->appendNew<MemoryValue>(proc, Store, Origin(), padding, forPaddingOutputAddress);
+
+    UpsilonValue* updatedTotalUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), updatedTotal);
+    updatedTotalUpsilon->setPhi(loopTotal);
+
+    Value* decCounter = loop->appendNew<Value>(proc, Sub, Origin(), loopCounter, loop->appendNew<Const64Value>(proc, Origin(), 1));
+    UpsilonValue* decCounterUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), decCounter);
+    decCounterUpsilon->setPhi(loopCounter);
+    loop->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        decCounter,
+        FrequentedBlock(loop), FrequentedBlock(done));
+
+    // Tail.
+    done->appendNew<ControlValue>(proc, Return, Origin(), updatedTotal);
+    CHECK(isIdentical(compileAndRun<double>(proc, 100000), 5000050000.));
+}
+
+void testBranch()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
         proc, Branch, Origin(),
         root->appendNew<Value>(
-            proc, Equal, Origin(),
-            root->appendNew<Value>(
-                proc, Equal, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-                root->appendNew<Const32Value>(proc, Origin(), 0)),
-            root->appendNew<Const32Value>(proc, Origin(), 0)),
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
         FrequentedBlock(thenCase), FrequentedBlock(elseCase));
 
     thenCase->appendNew<ControlValue>(
@@ -5033,7 +5404,7 @@ void testBranchEqualEqual()
     CHECK(invoke<int>(*code, 0) == 0);
 }
 
-void testBranchEqualCommute()
+void testBranchPtr()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
@@ -5042,132 +5413,346 @@ void testBranchEqualCommute()
 
     root->appendNew<ControlValue>(
         proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, Equal, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), 0),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
         FrequentedBlock(thenCase), FrequentedBlock(elseCase));
 
     thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
 
     elseCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
 
     auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(invoke<int>(*code, static_cast<intptr_t>(42)) == 1);
+    CHECK(invoke<int>(*code, static_cast<intptr_t>(0)) == 0);
 }
 
-void testBranchEqualEqual1()
+void testDiamond()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     BasicBlock* thenCase = proc.addBlock();
     BasicBlock* elseCase = proc.addBlock();
+    BasicBlock* done = proc.addBlock();
 
     root->appendNew<ControlValue>(
         proc, Branch, Origin(),
         root->appendNew<Value>(
-            proc, Equal, Origin(),
-            root->appendNew<Value>(
-                proc, Equal, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-                root->appendNew<Const32Value>(proc, Origin(), 0)),
-            root->appendNew<Const32Value>(proc, Origin(), 1)),
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
         FrequentedBlock(thenCase), FrequentedBlock(elseCase));
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+    UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>(
+        proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+    thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
 
-    elseCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+    UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(
+        proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+    elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+
+    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
+    thenResult->setPhi(phi);
+    elseResult->setPhi(phi);
+    done->appendNew<ControlValue>(proc, Return, Origin(), phi);
 
     auto code = compile(proc);
     CHECK(invoke<int>(*code, 42) == 1);
     CHECK(invoke<int>(*code, 0) == 0);
 }
 
-void testBranchEqualOrUnorderedArgs(double a, double b)
+void testBranchNotEqual()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     BasicBlock* thenCase = proc.addBlock();
     BasicBlock* elseCase = proc.addBlock();
 
-    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
     root->appendNew<ControlValue>(
         proc, Branch, Origin(),
         root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argumentA,
-            argumentB),
+            proc, NotEqual, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), 0)),
         FrequentedBlock(thenCase), FrequentedBlock(elseCase));
 
     thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
 
     elseCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), -13));
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
 
-    int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13;
-    CHECK(compileAndRun<int64_t>(proc, a, b) == expected);
+    auto code = compile(proc);
+    CHECK(invoke<int>(*code, 42) == 1);
+    CHECK(invoke<int>(*code, 0) == 0);
 }
 
-void testBranchEqualOrUnorderedArgs(float a, float b)
+void testBranchNotEqualCommute()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     BasicBlock* thenCase = proc.addBlock();
     BasicBlock* elseCase = proc.addBlock();
 
-    Value* argumentA = root->appendNew<MemoryValue>(proc, Load, Float, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argumentB = root->appendNew<MemoryValue>(proc, Load, Float, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-
     root->appendNew<ControlValue>(
         proc, Branch, Origin(),
         root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argumentA,
-            argumentB),
+            proc, NotEqual, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), 0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
         FrequentedBlock(thenCase), FrequentedBlock(elseCase));
 
     thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
 
     elseCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), -13));
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
 
-    int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13;
-    CHECK(compileAndRun<int64_t>(proc, &a, &b) == expected);
+    auto code = compile(proc);
+    CHECK(invoke<int>(*code, 42) == 1);
+    CHECK(invoke<int>(*code, 0) == 0);
 }
 
-void testBranchNotEqualAndOrderedArgs(double a, double b)
+void testBranchNotEqualNotEqual()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     BasicBlock* thenCase = proc.addBlock();
     BasicBlock* elseCase = proc.addBlock();
 
-    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
-    Value* equalOrUnordered = root->appendNew<Value>(
-        proc, EqualOrUnordered, Origin(),
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, NotEqual, Origin(),
+            root->appendNew<Value>(
+                proc, NotEqual, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), 0)),
+            root->appendNew<Const32Value>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(*code, 42) == 1);
+    CHECK(invoke<int>(*code, 0) == 0);
+}
+
+void testBranchEqual()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(*code, 42) == 1);
+    CHECK(invoke<int>(*code, 0) == 0);
+}
+
+void testBranchEqualEqual()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<Value>(
+                proc, Equal, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), 0)),
+            root->appendNew<Const32Value>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(*code, 42) == 1);
+    CHECK(invoke<int>(*code, 0) == 0);
+}
+
+void testBranchEqualCommute()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), 0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(*code, 42) == 1);
+    CHECK(invoke<int>(*code, 0) == 0);
+}
+
+void testBranchEqualEqual1()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<Value>(
+                proc, Equal, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), 0)),
+            root->appendNew<Const32Value>(proc, Origin(), 1)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(*code, 42) == 1);
+    CHECK(invoke<int>(*code, 0) == 0);
+}
+
+void testBranchEqualOrUnorderedArgs(double a, double b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, EqualOrUnordered, Origin(),
+            argumentA,
+            argumentB),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), -13));
+
+    int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13;
+    CHECK(compileAndRun<int64_t>(proc, a, b) == expected);
+}
+
+void testBranchEqualOrUnorderedArgs(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* argumentA = root->appendNew<MemoryValue>(proc, Load, Float, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argumentB = root->appendNew<MemoryValue>(proc, Load, Float, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, EqualOrUnordered, Origin(),
+            argumentA,
+            argumentB),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), -13));
+
+    int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13;
+    CHECK(compileAndRun<int64_t>(proc, &a, &b) == expected);
+}
+
+void testBranchNotEqualAndOrderedArgs(double a, double b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+    Value* equalOrUnordered = root->appendNew<Value>(
+        proc, EqualOrUnordered, Origin(),
         argumentA,
         argumentB);
     Value* notEqualAndOrdered = root->appendNew<Value>(
@@ -6079,41 +6664,108 @@ void testPatchpointAny(ValueRep rep)
     CHECK(compileAndRun<int>(proc, 1, 2) == 3);
 }
 
-void testPatchpointLotsOfLateAnys()
+void testPatchpointGPScratch()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Vector<int> things;
-    for (unsigned i = 200; i--;)
-        things.append(i);
-
-    Vector<Value*> values;
-    for (int& thing : things) {
-        Value* value = root->appendNew<MemoryValue>(
-            proc, Load, Int32, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), &thing));
-        values.append(value);
-    }
-
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
-    for (Value* value : values)
-        patchpoint->append(ConstrainedValue(value, ValueRep::LateColdAny));
+    patchpoint->append(arg1, ValueRep::SomeRegister);
+    patchpoint->append(arg2, ValueRep::SomeRegister);
+    patchpoint->numGPScratchRegisters = 2;
     patchpoint->setGenerator(
         [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
             // We shouldn't have spilled the inputs, so we assert that they're in registers.
-            CHECK(params.size() == things.size() + 1);
+            CHECK(params.size() == 3);
             CHECK(params[0].isGPR());
-            jit.move(CCallHelpers::TrustedImm32(0), params[0].gpr());
-            for (unsigned i = 1; i < params.size(); ++i) {
-                if (params[i].isGPR()) {
-                    CHECK(params[i] != params[0]);
-                    jit.add32(params[i].gpr(), params[0].gpr());
-                } else {
-                    CHECK(params[i].isStack());
-                    jit.add32(CCallHelpers::Address(GPRInfo::callFrameRegister, params[i].offsetFromFP()), params[0].gpr());
-                }
-            }
+            CHECK(params[1].isGPR());
+            CHECK(params[2].isGPR());
+            CHECK(params.gpScratch(0) != InvalidGPRReg);
+            CHECK(params.gpScratch(0) != params[0].gpr());
+            CHECK(params.gpScratch(0) != params[1].gpr());
+            CHECK(params.gpScratch(0) != params[2].gpr());
+            CHECK(params.gpScratch(1) != InvalidGPRReg);
+            CHECK(params.gpScratch(1) != params.gpScratch(0));
+            CHECK(params.gpScratch(1) != params[0].gpr());
+            CHECK(params.gpScratch(1) != params[1].gpr());
+            CHECK(params.gpScratch(1) != params[2].gpr());
+            CHECK(!params.unavailableRegisters().get(params.gpScratch(0)));
+            CHECK(!params.unavailableRegisters().get(params.gpScratch(1)));
+            add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr());
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
+void testPatchpointFPScratch()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
+    patchpoint->append(arg1, ValueRep::SomeRegister);
+    patchpoint->append(arg2, ValueRep::SomeRegister);
+    patchpoint->numFPScratchRegisters = 2;
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            // We shouldn't have spilled the inputs, so we assert that they're in registers.
+            CHECK(params.size() == 3);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            CHECK(params[2].isGPR());
+            CHECK(params.fpScratch(0) != InvalidFPRReg);
+            CHECK(params.fpScratch(1) != InvalidFPRReg);
+            CHECK(params.fpScratch(1) != params.fpScratch(0));
+            CHECK(!params.unavailableRegisters().get(params.fpScratch(0)));
+            CHECK(!params.unavailableRegisters().get(params.fpScratch(1)));
+            add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr());
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
+void testPatchpointLotsOfLateAnys()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Vector<int> things;
+    for (unsigned i = 200; i--;)
+        things.append(i);
+
+    Vector<Value*> values;
+    for (int& thing : things) {
+        Value* value = root->appendNew<MemoryValue>(
+            proc, Load, Int32, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), &thing));
+        values.append(value);
+    }
+
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
+    patchpoint->clobber(RegisterSet::macroScratchRegisters());
+    for (Value* value : values)
+        patchpoint->append(ConstrainedValue(value, ValueRep::LateColdAny));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            // We shouldn't have spilled the inputs, so we assert that they're in registers.
+            CHECK(params.size() == things.size() + 1);
+            CHECK(params[0].isGPR());
+            jit.move(CCallHelpers::TrustedImm32(0), params[0].gpr());
+            for (unsigned i = 1; i < params.size(); ++i) {
+                if (params[i].isGPR()) {
+                    CHECK(params[i] != params[0]);
+                    jit.add32(params[i].gpr(), params[0].gpr());
+                } else {
+                    CHECK(params[i].isStack());
+                    jit.add32(CCallHelpers::Address(GPRInfo::callFrameRegister, params[i].offsetFromFP()), params[0].gpr());
+                }
+            }
         });
     root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
 
@@ -6218,8 +6870,8 @@ void testPatchpointWithStackArgumentResult()
             CHECK(params[0] == ValueRep::stack(-static_cast<intptr_t>(proc.frameSize())));
             CHECK(params[1].isGPR());
             CHECK(params[2].isGPR());
-            jit.store32(params[1].gpr(), CCallHelpers::Address(CCallHelpers::stackPointerRegister, 0));
-            jit.add32(params[2].gpr(), CCallHelpers::Address(CCallHelpers::stackPointerRegister, 0));
+            jit.add32(params[1].gpr(), params[2].gpr(), jit.scratchRegister());
+            jit.store32(jit.scratchRegister(), CCallHelpers::Address(CCallHelpers::stackPointerRegister, 0));
         });
     root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
 
@@ -6281,6 +6933,50 @@ void testSimpleCheck()
     CHECK(invoke<int>(*code, 1) == 42);
 }
 
+void testCheckFalse()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    CheckValue* check = root->appendNew<CheckValue>(
+        proc, Check, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+    check->setGenerator(
+        [&] (CCallHelpers&, const StackmapGenerationParams&) {
+            CHECK(!"This should not have executed");
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    
+    CHECK(invoke<int>(*code) == 0);
+}
+
+void testCheckTrue()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    CheckValue* check = root->appendNew<CheckValue>(
+        proc, Check, Origin(), root->appendNew<Const32Value>(proc, Origin(), 1));
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.value()->opcode() == Patchpoint);
+            CHECK(!params.size());
+
+            // This should always work because a function this simple should never have callee
+            // saves.
+            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    
+    CHECK(invoke<int>(*code) == 42);
+}
+
 void testCheckLessThan()
 {
     Procedure proc;
@@ -6793,1930 +7489,2721 @@ void testCheckAddFoldFail(int a, int b)
 
     auto code = compile(proc);
 
-    CHECK(invoke<int>(*code) == 42);
+    CHECK(invoke<int>(*code) == 42);
+}
+
+void testCheckSubImm()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 42);
+    CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
+    checkSub->append(arg1);
+    checkSub->append(arg2);
+    checkSub->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isConstant());
+            CHECK(params[1].value() == 42);
+            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1);
+            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0) == -42.0);
+    CHECK(invoke<double>(*code, 1) == -41.0);
+    CHECK(invoke<double>(*code, 42) == 0.0);
+    CHECK(invoke<double>(*code, -2147483647) == -2147483689.0);
+}
+
+void testCheckSubBadImm()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    int32_t badImm = std::numeric_limits<int>::min();
+    Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), badImm);
+    CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
+    checkSub->append(arg1);
+    checkSub->append(arg2);
+    checkSub->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+
+            if (params[1].isConstant()) {
+                CHECK(params[1].value() == badImm);
+                jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(badImm), FPRInfo::fpRegT1);
+            } else {
+                CHECK(params[1].isGPR());
+                jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
+            }
+            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0) == -static_cast<double>(badImm));
+    CHECK(invoke<double>(*code, -1) == -static_cast<double>(badImm) - 1);
+    CHECK(invoke<double>(*code, 1) == -static_cast<double>(badImm) + 1);
+    CHECK(invoke<double>(*code, 42) == -static_cast<double>(badImm) + 42);
+}
+
+void testCheckSub()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
+    checkSub->append(arg1);
+    checkSub->append(arg2);
+    checkSub->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
+            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0, 42) == -42.0);
+    CHECK(invoke<double>(*code, 1, 42) == -41.0);
+    CHECK(invoke<double>(*code, 42, 42) == 0.0);
+    CHECK(invoke<double>(*code, -2147483647, 42) == -2147483689.0);
+}
+
+NEVER_INLINE double doubleSub(double a, double b)
+{
+    return a - b;
+}
+
+void testCheckSub64()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
+    checkSub->append(arg1);
+    checkSub->append(arg2);
+    checkSub->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
+            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0ll, 42ll) == -42.0);
+    CHECK(invoke<double>(*code, 1ll, 42ll) == -41.0);
+    CHECK(invoke<double>(*code, 42ll, 42ll) == 0.0);
+    CHECK(invoke<double>(*code, -9223372036854775807ll, 42ll) == doubleSub(static_cast<double>(-9223372036854775807ll), 42.0));
+}
+
+void testCheckSubFold(int a, int b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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);
+    checkSub->setGenerator(
+        [&] (CCallHelpers&, const StackmapGenerationParams&) {
+            CHECK(!"Should have been folded");
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), checkSub);
+
+    auto code = compile(proc);
+
+    CHECK(invoke<int>(*code) == a - b);
+}
+
+void testCheckSubFoldFail(int a, int b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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);
+    checkSub->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), checkSub);
+
+    auto code = compile(proc);
+
+    CHECK(invoke<int>(*code) == 42);
+}
+
+void testCheckNeg()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), 0);
+    Value* arg2 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    CheckValue* checkNeg = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
+    checkNeg->append(arg2);
+    checkNeg->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 1);
+            CHECK(params[0].isGPR());
+            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT1);
+            jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkNeg));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0) == 0.0);
+    CHECK(invoke<double>(*code, 1) == -1.0);
+    CHECK(invoke<double>(*code, 42) == -42.0);
+    CHECK(invoke<double>(*code, -2147483647 - 1) == 2147483648.0);
+}
+
+void testCheckNeg64()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Const64Value>(proc, Origin(), 0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    CheckValue* checkNeg = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
+    checkNeg->append(arg2);
+    checkNeg->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 1);
+            CHECK(params[0].isGPR());
+            jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT1);
+            jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkNeg));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0ll) == 0.0);
+    CHECK(invoke<double>(*code, 1ll) == -1.0);
+    CHECK(invoke<double>(*code, 42ll) == -42.0);
+    CHECK(invoke<double>(*code, -9223372036854775807ll - 1) == 9223372036854775808.0);
+}
+
+void testCheckMul()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
+    checkMul->append(arg1);
+    checkMul->append(arg2);
+    checkMul->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
+            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0, 42) == 0.0);
+    CHECK(invoke<double>(*code, 1, 42) == 42.0);
+    CHECK(invoke<double>(*code, 42, 42) == 42.0 * 42.0);
+    CHECK(invoke<double>(*code, 2147483647, 42) == 2147483647.0 * 42.0);
+}
+
+void testCheckMulMemory()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    int left;
+    int right;
+    
+    Value* arg1 = root->appendNew<MemoryValue>(
+        proc, Load, Int32, Origin(),
+        root->appendNew<ConstPtrValue>(proc, Origin(), &left));
+    Value* arg2 = root->appendNew<MemoryValue>(
+        proc, Load, Int32, Origin(),
+        root->appendNew<ConstPtrValue>(proc, Origin(), &right));
+    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
+    checkMul->append(arg1);
+    checkMul->append(arg2);
+    checkMul->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
+            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
+
+    auto code = compile(proc);
+
+    left = 0;
+    right = 42;
+    CHECK(invoke<double>(*code) == 0.0);
+    
+    left = 1;
+    right = 42;
+    CHECK(invoke<double>(*code) == 42.0);
+
+    left = 42;
+    right = 42;
+    CHECK(invoke<double>(*code) == 42.0 * 42.0);
+
+    left = 2147483647;
+    right = 42;
+    CHECK(invoke<double>(*code) == 2147483647.0 * 42.0);
+}
+
+void testCheckMul2()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 2);
+    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
+    checkMul->append(arg1);
+    checkMul->append(arg2);
+    checkMul->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isConstant());
+            CHECK(params[1].value() == 2);
+            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(2), FPRInfo::fpRegT1);
+            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0) == 0.0);
+    CHECK(invoke<double>(*code, 1) == 2.0);
+    CHECK(invoke<double>(*code, 42) == 42.0 * 2.0);
+    CHECK(invoke<double>(*code, 2147483647) == 2147483647.0 * 2.0);
+}
+
+void testCheckMul64()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
+    checkMul->append(arg1);
+    checkMul->append(arg2);
+    checkMul->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
+            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0, 42) == 0.0);
+    CHECK(invoke<double>(*code, 1, 42) == 42.0);
+    CHECK(invoke<double>(*code, 42, 42) == 42.0 * 42.0);
+    CHECK(invoke<double>(*code, 9223372036854775807ll, 42) == static_cast<double>(9223372036854775807ll) * 42.0);
+}
+
+void testCheckMulFold(int a, int b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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);
+    checkMul->setGenerator(
+        [&] (CCallHelpers&, const StackmapGenerationParams&) {
+            CHECK(!"Should have been folded");
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), checkMul);
+
+    auto code = compile(proc);
+
+    CHECK(invoke<int>(*code) == a * b);
+}
+
+void testCheckMulFoldFail(int a, int b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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);
+    checkMul->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), checkMul);
+
+    auto code = compile(proc);
+
+    CHECK(invoke<int>(*code) == 42);
+}
+
+void testCheckMul64SShr()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Value>(
+        proc, SShr, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        root->appendNew<Const32Value>(proc, Origin(), 1));
+    Value* arg2 = root->appendNew<Value>(
+        proc, SShr, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+        root->appendNew<Const32Value>(proc, Origin(), 1));
+    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
+    checkMul->append(arg1);
+    checkMul->append(arg2);
+    checkMul->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
+            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
+
+    auto code = compile(proc);
+
+    CHECK(invoke<double>(*code, 0ll, 42ll) == 0.0);
+    CHECK(invoke<double>(*code, 1ll, 42ll) == 0.0);
+    CHECK(invoke<double>(*code, 42ll, 42ll) == (42.0 / 2.0) * (42.0 / 2.0));
+    CHECK(invoke<double>(*code, 10000000000ll, 10000000000ll) == 25000000000000000000.0);
+}
+
+template<typename LeftFunctor, typename RightFunctor, typename InputType>
+void genericTestCompare(
+    B3::Opcode opcode, const LeftFunctor& leftFunctor, const RightFunctor& rightFunctor,
+    InputType left, InputType right, int result)
+{
+    // Using a compare.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* leftValue = leftFunctor(root, proc);
+        Value* rightValue = rightFunctor(root, proc);
+        Value* comparisonResult = root->appendNew<Value>(proc, opcode, Origin(), leftValue, rightValue);
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, NotEqual, Origin(),
+                comparisonResult,
+                root->appendIntConstant(proc, Origin(), comparisonResult->type(), 0)));
+
+        CHECK(compileAndRun<int>(proc, left, right) == result);
+    }
+    
+    // Using a branch.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        BasicBlock* thenCase = proc.addBlock();
+        BasicBlock* elseCase = proc.addBlock();
+
+        Value* leftValue = leftFunctor(root, proc);
+        Value* rightValue = rightFunctor(root, proc);
+
+        root->appendNew<ControlValue>(
+            proc, Branch, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), leftValue, rightValue),
+            FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+        // We use a patchpoint on the then case to ensure that this doesn't get if-converted.
+        PatchpointValue* patchpoint = thenCase->appendNew<PatchpointValue>(proc, Int32, Origin());
+        patchpoint->setGenerator(
+            [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                AllowMacroScratchRegisterUsage allowScratch(jit);
+                CHECK(params.size() == 1);
+                CHECK(params[0].isGPR());
+                jit.move(CCallHelpers::TrustedImm32(1), params[0].gpr());
+            });
+        thenCase->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+        elseCase->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+        CHECK(compileAndRun<int>(proc, left, right) == result);
+    }
+}
+
+int modelCompare(B3::Opcode opcode, int left, int right)
+{
+    switch (opcode) {
+    case Equal:
+        return left == right;
+    case NotEqual:
+        return left != right;
+    case LessThan:
+        return left < right;
+    case GreaterThan:
+        return left > right;
+    case LessEqual:
+        return left <= right;
+    case GreaterEqual:
+        return left >= right;
+    case Above:
+        return static_cast<unsigned>(left) > static_cast<unsigned>(right);
+    case Below:
+        return static_cast<unsigned>(left) < static_cast<unsigned>(right);
+    case AboveEqual:
+        return static_cast<unsigned>(left) >= static_cast<unsigned>(right);
+    case BelowEqual:
+        return static_cast<unsigned>(left) <= static_cast<unsigned>(right);
+    case BitAnd:
+        return !!(left & right);
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
+template<typename T>
+void testCompareLoad(B3::Opcode opcode, B3::Opcode loadOpcode, int left, int right)
+{
+    int result = modelCompare(opcode, modelLoad<T>(left), right);
+    
+    // Test addr-to-tmp
+    int slot = left;
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<MemoryValue>(
+                proc, loadOpcode, Int32, Origin(),
+                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Value>(
+                proc, Trunc, Origin(),
+                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        },
+        left, right, result);
+
+    // Test addr-to-imm
+    slot = left;
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<MemoryValue>(
+                proc, loadOpcode, Int32, Origin(),
+                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const32Value>(proc, Origin(), right);
+        },
+        left, right, result);
+
+    result = modelCompare(opcode, left, modelLoad<T>(right));
+    
+    // Test tmp-to-addr
+    slot = right;
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Value>(
+                proc, Trunc, Origin(),
+                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<MemoryValue>(
+                proc, loadOpcode, Int32, Origin(),
+                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+        },
+        left, right, result);
+
+    // Test imm-to-addr
+    slot = right;
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const32Value>(proc, Origin(), left);
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<MemoryValue>(
+                proc, loadOpcode, Int32, Origin(),
+                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+        },
+        left, right, result);
+
+    // Test addr-to-addr, with the same addr.
+    slot = left;
+    Value* value;
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            value = block->appendNew<MemoryValue>(
+                proc, loadOpcode, Int32, Origin(),
+                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+            return value;
+        },
+        [&] (BasicBlock*, Procedure&) {
+            return value;
+        },
+        left, left, modelCompare(opcode, modelLoad<T>(left), modelLoad<T>(left)));
+}
+
+void testCompareImpl(B3::Opcode opcode, int64_t left, int64_t right)
+{
+    int result = modelCompare(opcode, left, right);
+    
+    // Test tmp-to-tmp.
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+        },
+        left, right, result);
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Value>(
+                proc, Trunc, Origin(),
+                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Value>(
+                proc, Trunc, Origin(),
+                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        },
+        left, right, result);
+
+    // Test imm-to-tmp.
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const64Value>(proc, Origin(), left);
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+        },
+        left, right, result);
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const32Value>(proc, Origin(), left);
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Value>(
+                proc, Trunc, Origin(),
+                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        },
+        left, right, result);
+
+    // Test tmp-to-imm.
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const64Value>(proc, Origin(), right);
+        },
+        left, right, result);
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Value>(
+                proc, Trunc, Origin(),
+                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const32Value>(proc, Origin(), right);
+        },
+        left, right, result);
+
+    // Test imm-to-imm.
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const64Value>(proc, Origin(), left);
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const64Value>(proc, Origin(), right);
+        },
+        left, right, result);
+    genericTestCompare(
+        opcode,
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const32Value>(proc, Origin(), left);
+        },
+        [&] (BasicBlock* block, Procedure& proc) {
+            return block->appendNew<Const32Value>(proc, Origin(), right);
+        },
+        left, right, result);
+
+    testCompareLoad<int32_t>(opcode, Load, left, right);
+    testCompareLoad<int8_t>(opcode, Load8S, left, right);
+    testCompareLoad<uint8_t>(opcode, Load8Z, left, right);
+    testCompareLoad<int16_t>(opcode, Load16S, left, right);
+    testCompareLoad<uint16_t>(opcode, Load16Z, left, right);
+}
+
+void testCompare(B3::Opcode opcode, int left, int right)
+{
+    auto variants = [&] (int left, int right) {
+        testCompareImpl(opcode, left, right);
+        testCompareImpl(opcode, left, right + 1);
+        testCompareImpl(opcode, left, right - 1);
+
+        auto multipliedTests = [&] (int factor) {
+            testCompareImpl(opcode, left * factor, right);
+            testCompareImpl(opcode, left * factor, right + 1);
+            testCompareImpl(opcode, left * factor, right - 1);
+        
+            testCompareImpl(opcode, left, right * factor);
+            testCompareImpl(opcode, left, (right + 1) * factor);
+            testCompareImpl(opcode, left, (right - 1) * factor);
+        
+            testCompareImpl(opcode, left * factor, right * factor);
+            testCompareImpl(opcode, left * factor, (right + 1) * factor);
+            testCompareImpl(opcode, left * factor, (right - 1) * factor);
+        };
+
+        multipliedTests(10);
+        multipliedTests(100);
+        multipliedTests(1000);
+        multipliedTests(100000);
+    };
+
+    variants(left, right);
+    variants(-left, right);
+    variants(left, -right);
+    variants(-left, -right);
 }
 
-void testCheckSubImm()
+void testEqualDouble(double left, double right, bool result)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 42);
-    CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
-    checkSub->append(arg1);
-    checkSub->append(arg2);
-    checkSub->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 2);
-            CHECK(params[0].isGPR());
-            CHECK(params[1].isConstant());
-            CHECK(params[1].value() == 42);
-            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1);
-            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
 
-    auto code = compile(proc);
+    CHECK(compileAndRun<bool>(proc, left, right) == result);
+}
 
-    CHECK(invoke<double>(*code, 0) == -42.0);
-    CHECK(invoke<double>(*code, 1) == -41.0);
-    CHECK(invoke<double>(*code, 42) == 0.0);
-    CHECK(invoke<double>(*code, -2147483647) == -2147483689.0);
+int simpleFunction(int a, int b)
+{
+    return a + b;
 }
 
-void testCheckSubBadImm()
+void testCallSimple(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    int32_t badImm = std::numeric_limits<int>::min();
-    Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), badImm);
-    CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
-    checkSub->append(arg1);
-    checkSub->append(arg2);
-    checkSub->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 2);
-            CHECK(params[0].isGPR());
-            CHECK(params[1].isConstant());
-            CHECK(params[1].value() == badImm);
-            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(badImm), FPRInfo::fpRegT1);
-            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
-
-    auto code = compile(proc);
+        root->appendNew<CCallValue>(
+            proc, Int32, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    CHECK(invoke<double>(*code, 0) == -static_cast<double>(badImm));
-    CHECK(invoke<double>(*code, -1) == -static_cast<double>(badImm) - 1);
-    CHECK(invoke<double>(*code, 1) == -static_cast<double>(badImm) + 1);
-    CHECK(invoke<double>(*code, 42) == -static_cast<double>(badImm) + 42);
+    CHECK(compileAndRun<int>(proc, a, b) == a + b);
 }
 
-void testCheckSub()
+void testCallRare(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg2 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
-    checkSub->append(arg1);
-    checkSub->append(arg2);
-    checkSub->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 2);
-            CHECK(params[0].isGPR());
-            CHECK(params[1].isGPR());
-            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
-            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
+    BasicBlock* common = proc.addBlock();
+    BasicBlock* rare = proc.addBlock();
+
     root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
+        proc, Branch, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        FrequentedBlock(rare, FrequencyClass::Rare),
+        FrequentedBlock(common));
 
-    auto code = compile(proc);
+    common->appendNew<ControlValue>(
+        proc, Return, Origin(), common->appendNew<Const32Value>(proc, Origin(), 0));
+    
+    rare->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        rare->appendNew<CCallValue>(
+            proc, Int32, Origin(),
+            rare->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)),
+            rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+            rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
 
-    CHECK(invoke<double>(*code, 0, 42) == -42.0);
-    CHECK(invoke<double>(*code, 1, 42) == -41.0);
-    CHECK(invoke<double>(*code, 42, 42) == 0.0);
-    CHECK(invoke<double>(*code, -2147483647, 42) == -2147483689.0);
+    CHECK(compileAndRun<int>(proc, true, a, b) == a + b);
 }
 
-NEVER_INLINE double doubleSub(double a, double b)
+void testCallRareLive(int a, int b, int c)
 {
-    return a - b;
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* common = proc.addBlock();
+    BasicBlock* rare = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        FrequentedBlock(rare, FrequencyClass::Rare),
+        FrequentedBlock(common));
+
+    common->appendNew<ControlValue>(
+        proc, Return, Origin(), common->appendNew<Const32Value>(proc, Origin(), 0));
+    
+    rare->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        rare->appendNew<Value>(
+            proc, Add, Origin(),
+            rare->appendNew<CCallValue>(
+                proc, Int32, Origin(),
+                rare->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)),
+                rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+                rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)),
+            rare->appendNew<Value>(
+                proc, Trunc, Origin(),
+                rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))));
+
+    CHECK(compileAndRun<int>(proc, true, a, b, c) == a + b + c);
 }
 
-void testCheckSub64()
+void testCallSimplePure(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
-    checkSub->append(arg1);
-    checkSub->append(arg2);
-    checkSub->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 2);
-            CHECK(params[0].isGPR());
-            CHECK(params[1].isGPR());
-            jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
-            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
+        root->appendNew<CCallValue>(
+            proc, Int32, Origin(), Effects::none(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    auto code = compile(proc);
+    CHECK(compileAndRun<int>(proc, a, b) == a + b);
+}
 
-    CHECK(invoke<double>(*code, 0ll, 42ll) == -42.0);
-    CHECK(invoke<double>(*code, 1ll, 42ll) == -41.0);
-    CHECK(invoke<double>(*code, 42ll, 42ll) == 0.0);
-    CHECK(invoke<double>(*code, -9223372036854775807ll, 42ll) == doubleSub(static_cast<double>(-9223372036854775807ll), 42.0));
+int functionWithHellaArguments(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, int s, int t, int u, int v, int w, int x, int y, int z)
+{
+    return (a << 0) + (b << 1) + (c << 2) + (d << 3) + (e << 4) + (f << 5) + (g << 6) + (h << 7) + (i << 8) + (j << 9) + (k << 10) + (l << 11) + (m << 12) + (n << 13) + (o << 14) + (p << 15) + (q << 16) + (r << 17) + (s << 18) + (t << 19) + (u << 20) + (v << 21) + (w << 22) + (x << 23) + (y << 24) + (z << 25);
 }
 
-void testCheckSubFold(int a, int b)
+void testCallFunctionWithHellaArguments()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    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);
-    checkSub->setGenerator(
-        [&] (CCallHelpers&, const StackmapGenerationParams&) {
-            CHECK(!"Should have been folded");
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkSub);
 
-    auto code = compile(proc);
+    Vector<Value*> args;
+    for (unsigned i = 0; i < 26; ++i)
+        args.append(root->appendNew<Const32Value>(proc, Origin(), i + 1));
 
-    CHECK(invoke<int>(*code) == a - b);
+    CCallValue* call = root->appendNew<CCallValue>(
+        proc, Int32, Origin(),
+        root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaArguments)));
+    call->children().appendVector(args);
+    
+    root->appendNew<ControlValue>(proc, Return, Origin(), call);
+
+    CHECK(compileAndRun<int>(proc) == functionWithHellaArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26));
 }
 
-void testCheckSubFoldFail(int a, int b)
+void testReturnDouble(double value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    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);
-    checkSub->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkSub);
-
-    auto code = compile(proc);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<ConstDoubleValue>(proc, Origin(), value));
 
-    CHECK(invoke<int>(*code) == 42);
+    CHECK(isIdentical(compileAndRun<double>(proc), value));
 }
 
-void testCheckNeg()
+void testReturnFloat(float value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), 0);
-    Value* arg2 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    CheckValue* checkNeg = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
-    checkNeg->append(arg2);
-    checkNeg->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 1);
-            CHECK(params[0].isGPR());
-            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT1);
-            jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkNeg));
+        root->appendNew<ConstFloatValue>(proc, Origin(), value));
 
-    auto code = compile(proc);
+    CHECK(isIdentical(compileAndRun<float>(proc), value));
+}
 
-    CHECK(invoke<double>(*code, 0) == 0.0);
-    CHECK(invoke<double>(*code, 1) == -1.0);
-    CHECK(invoke<double>(*code, 42) == -42.0);
-    CHECK(invoke<double>(*code, -2147483647 - 1) == 2147483648.0);
+double simpleFunctionDouble(double a, double b)
+{
+    return a + b;
 }
 
-void testCheckNeg64()
+void testCallSimpleDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Const64Value>(proc, Origin(), 0);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    CheckValue* checkNeg = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2);
-    checkNeg->append(arg2);
-    checkNeg->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 1);
-            CHECK(params[0].isGPR());
-            jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT1);
-            jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkNeg));
+        root->appendNew<CCallValue>(
+            proc, Double, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunctionDouble)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
 
-    auto code = compile(proc);
+    CHECK(compileAndRun<double>(proc, a, b) == a + b);
+}
 
-    CHECK(invoke<double>(*code, 0ll) == 0.0);
-    CHECK(invoke<double>(*code, 1ll) == -1.0);
-    CHECK(invoke<double>(*code, 42ll) == -42.0);
-    CHECK(invoke<double>(*code, -9223372036854775807ll - 1) == 9223372036854775808.0);
+float simpleFunctionFloat(float a, float b)
+{
+    return a + b;
 }
 
-void testCheckMul()
+void testCallSimpleFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
+    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg2 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
+    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
-    checkMul->append(arg1);
-    checkMul->append(arg2);
-    checkMul->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 2);
-            CHECK(params[0].isGPR());
-            CHECK(params[1].isGPR());
-            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
-            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
+    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
+    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
+        root->appendNew<CCallValue>(
+            proc, Float, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunctionFloat)),
+            floatValue1,
+            floatValue2));
 
-    auto code = compile(proc);
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), a + b));
+}
 
-    CHECK(invoke<double>(*code, 0, 42) == 0.0);
-    CHECK(invoke<double>(*code, 1, 42) == 42.0);
-    CHECK(invoke<double>(*code, 42, 42) == 42.0 * 42.0);
-    CHECK(invoke<double>(*code, 2147483647, 42) == 2147483647.0 * 42.0);
+double functionWithHellaDoubleArguments(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j, double k, double l, double m, double n, double o, double p, double q, double r, double s, double t, double u, double v, double w, double x, double y, double z)
+{
+    return a * pow(2, 0) + b * pow(2, 1) + c * pow(2, 2) + d * pow(2, 3) + e * pow(2, 4) + f * pow(2, 5) + g * pow(2, 6) + h * pow(2, 7) + i * pow(2, 8) + j * pow(2, 9) + k * pow(2, 10) + l * pow(2, 11) + m * pow(2, 12) + n * pow(2, 13) + o * pow(2, 14) + p * pow(2, 15) + q * pow(2, 16) + r * pow(2, 17) + s * pow(2, 18) + t * pow(2, 19) + u * pow(2, 20) + v * pow(2, 21) + w * pow(2, 22) + x * pow(2, 23) + y * pow(2, 24) + z * pow(2, 25);
 }
 
-void testCheckMulMemory()
+void testCallFunctionWithHellaDoubleArguments()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
 
-    int left;
-    int right;
-    
-    Value* arg1 = root->appendNew<MemoryValue>(
-        proc, Load, Int32, Origin(),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &left));
-    Value* arg2 = root->appendNew<MemoryValue>(
-        proc, Load, Int32, Origin(),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &right));
-    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
-    checkMul->append(arg1);
-    checkMul->append(arg2);
-    checkMul->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 2);
-            CHECK(params[0].isGPR());
-            CHECK(params[1].isGPR());
-            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
-            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
-
-    auto code = compile(proc);
+    Vector<Value*> args;
+    for (unsigned i = 0; i < 26; ++i)
+        args.append(root->appendNew<ConstDoubleValue>(proc, Origin(), i + 1));
 
-    left = 0;
-    right = 42;
-    CHECK(invoke<double>(*code) == 0.0);
+    CCallValue* call = root->appendNew<CCallValue>(
+        proc, Double, Origin(),
+        root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaDoubleArguments)));
+    call->children().appendVector(args);
     
-    left = 1;
-    right = 42;
-    CHECK(invoke<double>(*code) == 42.0);
+    root->appendNew<ControlValue>(proc, Return, Origin(), call);
 
-    left = 42;
-    right = 42;
-    CHECK(invoke<double>(*code) == 42.0 * 42.0);
+    CHECK(compileAndRun<double>(proc) == functionWithHellaDoubleArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26));
+}
 
-    left = 2147483647;
-    right = 42;
-    CHECK(invoke<double>(*code) == 2147483647.0 * 42.0);
+float functionWithHellaFloatArguments(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l, float m, float n, float o, float p, float q, float r, float s, float t, float u, float v, float w, float x, float y, float z)
+{
+    return a * pow(2, 0) + b * pow(2, 1) + c * pow(2, 2) + d * pow(2, 3) + e * pow(2, 4) + f * pow(2, 5) + g * pow(2, 6) + h * pow(2, 7) + i * pow(2, 8) + j * pow(2, 9) + k * pow(2, 10) + l * pow(2, 11) + m * pow(2, 12) + n * pow(2, 13) + o * pow(2, 14) + p * pow(2, 15) + q * pow(2, 16) + r * pow(2, 17) + s * pow(2, 18) + t * pow(2, 19) + u * pow(2, 20) + v * pow(2, 21) + w * pow(2, 22) + x * pow(2, 23) + y * pow(2, 24) + z * pow(2, 25);
 }
 
-void testCheckMul2()
+void testCallFunctionWithHellaFloatArguments()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 2);
-    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
-    checkMul->append(arg1);
-    checkMul->append(arg2);
-    checkMul->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 2);
-            CHECK(params[0].isGPR());
-            CHECK(params[1].isConstant());
-            CHECK(params[1].value() == 2);
-            jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(2), FPRInfo::fpRegT1);
-            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
 
-    auto code = compile(proc);
+    Vector<Value*> args;
+    for (unsigned i = 0; i < 26; ++i)
+        args.append(root->appendNew<ConstFloatValue>(proc, Origin(), i + 1));
 
-    CHECK(invoke<double>(*code, 0) == 0.0);
-    CHECK(invoke<double>(*code, 1) == 2.0);
-    CHECK(invoke<double>(*code, 42) == 42.0 * 2.0);
-    CHECK(invoke<double>(*code, 2147483647) == 2147483647.0 * 2.0);
+    CCallValue* call = root->appendNew<CCallValue>(
+        proc, Float, Origin(),
+        root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaFloatArguments)));
+    call->children().appendVector(args);
+    
+    root->appendNew<ControlValue>(proc, Return, Origin(), call);
+
+    CHECK(compileAndRun<float>(proc) == functionWithHellaFloatArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26));
 }
 
-void testCheckMul64()
+void testChillDiv(int num, int den, int res)
+{
+    // Test non-constant.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+
+        CHECK(compileAndRun<int>(proc, num, den) == res);
+    }
+
+    // Test constant.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Const32Value>(proc, Origin(), num),
+                root->appendNew<Const32Value>(proc, Origin(), den)));
+        
+        CHECK(compileAndRun<int>(proc) == res);
+    }
+}
+
+void testChillDivTwice(int num1, int den1, int num2, int den2, int res)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
-    checkMul->append(arg1);
-    checkMul->append(arg2);
-    checkMul->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            CHECK(params.size() == 2);
-            CHECK(params[0].isGPR());
-            CHECK(params[1].isGPR());
-            jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1);
-            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkMul));
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)))));
+    
+    CHECK(compileAndRun<int>(proc, num1, den1, num2, den2) == res);
+}
 
-    auto code = compile(proc);
+void testChillDiv64(int64_t num, int64_t den, int64_t res)
+{
+    if (!is64Bit())
+        return;
 
-    CHECK(invoke<double>(*code, 0, 42) == 0.0);
-    CHECK(invoke<double>(*code, 1, 42) == 42.0);
-    CHECK(invoke<double>(*code, 42, 42) == 42.0 * 42.0);
-    CHECK(invoke<double>(*code, 9223372036854775807ll, 42) == static_cast<double>(9223372036854775807ll) * 42.0);
+    // Test non-constant.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        
+        CHECK(compileAndRun<int64_t>(proc, num, den) == res);
+    }
+
+    // Test constant.
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, ChillDiv, Origin(),
+                root->appendNew<Const64Value>(proc, Origin(), num),
+                root->appendNew<Const64Value>(proc, Origin(), den)));
+        
+        CHECK(compileAndRun<int64_t>(proc) == res);
+    }
 }
 
-void testCheckMulFold(int a, int b)
+void testModArg(int64_t value)
 {
+    if (!value)
+        return;
+
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    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);
-    checkMul->setGenerator(
-        [&] (CCallHelpers&, const StackmapGenerationParams&) {
-            CHECK(!"Should have been folded");
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkMul);
 
-    auto code = compile(proc);
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(invoke<int>(*code) == a * b);
+    CHECK(!compileAndRun<int64_t>(proc, value));
 }
 
-void testCheckMulFoldFail(int a, int b)
+void testModArgs(int64_t numerator, int64_t denominator)
 {
+    if (!denominator)
+        return;
+    if (numerator == std::numeric_limits<int64_t>::min() && denominator == -1)
+        return;
+
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    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);
-    checkMul->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkMul);
 
-    auto code = compile(proc);
+    Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(invoke<int>(*code) == 42);
+    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == numerator % denominator);
 }
 
-template<typename LeftFunctor, typename RightFunctor>
-void genericTestCompare(
-    B3::Opcode opcode, const LeftFunctor& leftFunctor, const RightFunctor& rightFunctor,
-    int left, int right, int result)
+void testModImms(int64_t numerator, int64_t denominator)
 {
-    // Using a compare.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
+    if (!denominator)
+        return;
+    if (numerator == std::numeric_limits<int64_t>::min() && denominator == -1)
+        return;
 
-        Value* leftValue = leftFunctor(root, proc);
-        Value* rightValue = rightFunctor(root, proc);
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<Value>(
-                proc, NotEqual, Origin(),
-                root->appendNew<Value>(proc, opcode, Origin(), leftValue, rightValue),
-                root->appendNew<Const32Value>(proc, Origin(), 0)));
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
 
-        CHECK(compileAndRun<int>(proc, left, right) == result);
-    }
-    
-    // Using a branch.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        BasicBlock* thenCase = proc.addBlock();
-        BasicBlock* elseCase = proc.addBlock();
+    Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator);
+    Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-        Value* leftValue = leftFunctor(root, proc);
-        Value* rightValue = rightFunctor(root, proc);
+    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == numerator % denominator);
+}
 
-        root->appendNew<ControlValue>(
-            proc, Branch, Origin(),
-            root->appendNew<Value>(proc, opcode, Origin(), leftValue, rightValue),
-            FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+void testModArg32(int32_t value)
+{
+    if (!value)
+        return;
 
-        // We use a patchpoint on the then case to ensure that this doesn't get if-converted.
-        PatchpointValue* patchpoint = thenCase->appendNew<PatchpointValue>(proc, Int32, Origin());
-        patchpoint->setGenerator(
-            [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-                AllowMacroScratchRegisterUsage allowScratch(jit);
-                CHECK(params.size() == 1);
-                CHECK(params[0].isGPR());
-                jit.move(CCallHelpers::TrustedImm32(1), params[0].gpr());
-            });
-        thenCase->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
 
-        elseCase->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-        CHECK(compileAndRun<int>(proc, left, right) == result);
-    }
+    CHECK(!compileAndRun<int32_t>(proc, value));
 }
 
-int modelCompare(B3::Opcode opcode, int left, int right)
+void testModArgs32(int32_t numerator, int32_t denominator)
 {
-    switch (opcode) {
-    case Equal:
-        return left == right;
-    case NotEqual:
-        return left != right;
-    case LessThan:
-        return left < right;
-    case GreaterThan:
-        return left > right;
-    case LessEqual:
-        return left <= right;
-    case GreaterEqual:
-        return left >= right;
-    case Above:
-        return static_cast<unsigned>(left) > static_cast<unsigned>(right);
-    case Below:
-        return static_cast<unsigned>(left) < static_cast<unsigned>(right);
-    case AboveEqual:
-        return static_cast<unsigned>(left) >= static_cast<unsigned>(right);
-    case BelowEqual:
-        return static_cast<unsigned>(left) <= static_cast<unsigned>(right);
-    case BitAnd:
-        return !!(left & right);
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        return 0;
-    }
+    if (!denominator)
+        return;
+    if (numerator == std::numeric_limits<int32_t>::min() && denominator == -1)
+        return;
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == numerator % denominator);
 }
 
-template<typename T>
-void testCompareLoad(B3::Opcode opcode, B3::Opcode loadOpcode, int left, int right)
+void testModImms32(int32_t numerator, int32_t denominator)
 {
-    int result = modelCompare(opcode, modelLoad<T>(left), right);
-    
-    // Test addr-to-tmp
-    int slot = left;
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<MemoryValue>(
-                proc, loadOpcode, Int32, Origin(),
-                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
-        },
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Value>(
-                proc, Trunc, Origin(),
-                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-        },
-        left, right, result);
-
-    // Test addr-to-imm
-    slot = left;
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<MemoryValue>(
-                proc, loadOpcode, Int32, Origin(),
-                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
-        },
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Const32Value>(proc, Origin(), right);
-        },
-        left, right, result);
+    if (!denominator)
+        return;
+    if (numerator == std::numeric_limits<int32_t>::min() && denominator == -1)
+        return;
 
-    result = modelCompare(opcode, left, modelLoad<T>(right));
-    
-    // Test tmp-to-addr
-    slot = right;
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Value>(
-                proc, Trunc, Origin(),
-                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-        },
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<MemoryValue>(
-                proc, loadOpcode, Int32, Origin(),
-                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
-        },
-        left, right, result);
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
 
-    // Test imm-to-addr
-    slot = right;
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Const32Value>(proc, Origin(), left);
-        },
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<MemoryValue>(
-                proc, loadOpcode, Int32, Origin(),
-                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
-        },
-        left, right, result);
+    Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator);
+    Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    // Test addr-to-addr, with the same addr.
-    slot = left;
-    Value* value;
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            value = block->appendNew<MemoryValue>(
-                proc, loadOpcode, Int32, Origin(),
-                block->appendNew<ConstPtrValue>(proc, Origin(), &slot));
-            return value;
-        },
-        [&] (BasicBlock*, Procedure&) {
-            return value;
-        },
-        left, left, modelCompare(opcode, modelLoad<T>(left), modelLoad<T>(left)));
+    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == numerator % denominator);
 }
 
-void testCompareImpl(B3::Opcode opcode, int left, int right)
+void testChillModArg(int64_t value)
 {
-    int result = modelCompare(opcode, left, right);
-    
-    // Test tmp-to-tmp.
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Value>(
-                proc, Trunc, Origin(),
-                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-        },
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Value>(
-                proc, Trunc, Origin(),
-                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-        },
-        left, right, result);
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
 
-    // Test imm-to-tmp.
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Const32Value>(proc, Origin(), left);
-        },
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Value>(
-                proc, Trunc, Origin(),
-                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-        },
-        left, right, result);
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    // Test tmp-to-imm.
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Value>(
-                proc, Trunc, Origin(),
-                block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-        },
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Const32Value>(proc, Origin(), right);
-        },
-        left, right, result);
+    CHECK(!compileAndRun<int64_t>(proc, value));
+}
 
-    // Test imm-to-imm.
-    genericTestCompare(
-        opcode,
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Const32Value>(proc, Origin(), left);
-        },
-        [&] (BasicBlock* block, Procedure& proc) {
-            return block->appendNew<Const32Value>(proc, Origin(), right);
-        },
-        left, right, result);
+void testChillModArgs(int64_t numerator, int64_t denominator)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
 
-    testCompareLoad<int32_t>(opcode, Load, left, right);
-    testCompareLoad<int8_t>(opcode, Load8S, left, right);
-    testCompareLoad<uint8_t>(opcode, Load8Z, left, right);
-    testCompareLoad<int16_t>(opcode, Load16S, left, right);
-    testCompareLoad<uint16_t>(opcode, Load16Z, left, right);
+    Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
 }
 
-void testCompare(B3::Opcode opcode, int left, int right)
+void testChillModImms(int64_t numerator, int64_t denominator)
 {
-    auto variants = [&] (int left, int right) {
-        testCompareImpl(opcode, left, right);
-        testCompareImpl(opcode, left, right + 1);
-        testCompareImpl(opcode, left, right - 1);
-
-        auto multipliedTests = [&] (int factor) {
-            testCompareImpl(opcode, left * factor, right);
-            testCompareImpl(opcode, left * factor, right + 1);
-            testCompareImpl(opcode, left * factor, right - 1);
-        
-            testCompareImpl(opcode, left, right * factor);
-            testCompareImpl(opcode, left, (right + 1) * factor);
-            testCompareImpl(opcode, left, (right - 1) * factor);
-        
-            testCompareImpl(opcode, left * factor, right * factor);
-            testCompareImpl(opcode, left * factor, (right + 1) * factor);
-            testCompareImpl(opcode, left * factor, (right - 1) * factor);
-        };
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
 
-        multipliedTests(10);
-        multipliedTests(100);
-        multipliedTests(1000);
-        multipliedTests(100000);
-    };
+    Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator);
+    Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator);
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    variants(left, right);
-    variants(-left, right);
-    variants(left, -right);
-    variants(-left, -right);
+    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
 }
 
-void testEqualDouble(double left, double right, bool result)
+void testChillModArg32(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Equal, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
 
-    CHECK(compileAndRun<bool>(proc, left, right) == result);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(!compileAndRun<int32_t>(proc, value));
 }
 
-int simpleFunction(int a, int b)
+void testChillModArgs32(int32_t numerator, int32_t denominator)
 {
-    return a + b;
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
 }
 
-void testCallSimple(int a, int b)
+void testChillModImms32(int32_t numerator, int32_t denominator)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<CCallValue>(
-            proc, Int32, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    CHECK(compileAndRun<int>(proc, a, b) == a + b);
+    Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator);
+    Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator);
+    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
 }
 
-void testCallSimplePure(int a, int b)
+void testSwitch(unsigned degree, unsigned gap = 1)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
+
+    BasicBlock* terminate = proc.addBlock();
+    terminate->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<CCallValue>(
-            proc, Int32, Origin(), Effects::none(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        terminate->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, a, b) == a + b);
+    SwitchValue* switchValue = root->appendNew<SwitchValue>(
+        proc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        FrequentedBlock(terminate));
+
+    for (unsigned i = 0; i < degree; ++i) {
+        BasicBlock* newBlock = proc.addBlock();
+        newBlock->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            newBlock->appendNew<ArgumentRegValue>(
+                proc, Origin(), (i & 1) ? GPRInfo::argumentGPR2 : GPRInfo::argumentGPR1));
+        switchValue->appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock)));
+    }
+
+    auto code = compile(proc);
+
+    for (unsigned i = 0; i < degree; ++i) {
+        CHECK(invoke<int32_t>(*code, i * gap, 42, 11) == ((i & 1) ? 11 : 42));
+        if (gap > 1) {
+            CHECK(!invoke<int32_t>(*code, i * gap + 1, 42, 11));
+            CHECK(!invoke<int32_t>(*code, i * gap - 1, 42, 11));
+        }
+    }
+
+    CHECK(!invoke<int32_t>(*code, -1, 42, 11));
+    CHECK(!invoke<int32_t>(*code, degree * gap, 42, 11));
+    CHECK(!invoke<int32_t>(*code, degree * gap + 1, 42, 11));
 }
 
-int functionWithHellaArguments(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, int s, int t, int u, int v, int w, int x, int y, int z)
+void testSwitchChillDiv(unsigned degree, unsigned gap = 1)
 {
-    return (a << 0) + (b << 1) + (c << 2) + (d << 3) + (e << 4) + (f << 5) + (g << 6) + (h << 7) + (i << 8) + (j << 9) + (k << 10) + (l << 11) + (m << 12) + (n << 13) + (o << 14) + (p << 15) + (q << 16) + (r << 17) + (s << 18) + (t << 19) + (u << 20) + (v << 21) + (w << 22) + (x << 23) + (y << 24) + (z << 25);
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    Value* left = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* right = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
+
+    BasicBlock* terminate = proc.addBlock();
+    terminate->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        terminate->appendNew<Const32Value>(proc, Origin(), 0));
+
+    SwitchValue* switchValue = root->appendNew<SwitchValue>(
+        proc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        FrequentedBlock(terminate));
+
+    for (unsigned i = 0; i < degree; ++i) {
+        BasicBlock* newBlock = proc.addBlock();
+
+        newBlock->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            newBlock->appendNew<Value>(
+                proc, ChillDiv, Origin(), (i & 1) ? right : left, (i & 1) ? left : right));
+        
+        switchValue->appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock)));
+    }
+
+    auto code = compile(proc);
+
+    for (unsigned i = 0; i < degree; ++i) {
+        CHECK(invoke<int32_t>(*code, i * gap, 42, 11) == ((i & 1) ? 11/42 : 42/11));
+        if (gap > 1) {
+            CHECK(!invoke<int32_t>(*code, i * gap + 1, 42, 11));
+            CHECK(!invoke<int32_t>(*code, i * gap - 1, 42, 11));
+        }
+    }
+
+    CHECK(!invoke<int32_t>(*code, -1, 42, 11));
+    CHECK(!invoke<int32_t>(*code, degree * gap, 42, 11));
+    CHECK(!invoke<int32_t>(*code, degree * gap + 1, 42, 11));
 }
 
-void testCallFunctionWithHellaArguments()
+void testSwitchTargettingSameBlock()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
 
-    Vector<Value*> args;
-    for (unsigned i = 0; i < 26; ++i)
-        args.append(root->appendNew<Const32Value>(proc, Origin(), i + 1));
+    BasicBlock* terminate = proc.addBlock();
+    terminate->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        terminate->appendNew<Const32Value>(proc, Origin(), 5));
 
-    CCallValue* call = root->appendNew<CCallValue>(
-        proc, Int32, Origin(),
-        root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaArguments)));
-    call->children().appendVector(args);
-    
-    root->appendNew<ControlValue>(proc, Return, Origin(), call);
+    SwitchValue* switchValue = root->appendNew<SwitchValue>(
+        proc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        FrequentedBlock(terminate));
+
+    BasicBlock* otherTarget = proc.addBlock();
+    otherTarget->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        otherTarget->appendNew<Const32Value>(proc, Origin(), 42));
+    switchValue->appendCase(SwitchCase(3, FrequentedBlock(otherTarget)));
+    switchValue->appendCase(SwitchCase(13, FrequentedBlock(otherTarget)));
 
-    CHECK(compileAndRun<int>(proc) == functionWithHellaArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26));
+    auto code = compile(proc);
+
+    for (unsigned i = 0; i < 20; ++i) {
+        int32_t expected = (i == 3 || i == 13) ? 42 : 5;
+        CHECK(invoke<int32_t>(*code, i) == expected);
+    }
 }
 
-void testReturnDouble(double value)
+void testSwitchTargettingSameBlockFoldPathConstant()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
+
+    BasicBlock* terminate = proc.addBlock();
+    terminate->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<ConstDoubleValue>(proc, Origin(), value));
+        terminate->appendNew<Const32Value>(proc, Origin(), 42));
 
-    CHECK(isIdentical(compileAndRun<double>(proc), value));
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    SwitchValue* switchValue = root->appendNew<SwitchValue>(
+        proc, Origin(),
+        argument,
+        FrequentedBlock(terminate));
+
+    BasicBlock* otherTarget = proc.addBlock();
+    otherTarget->appendNew<ControlValue>(
+        proc, Return, Origin(), argument);
+    switchValue->appendCase(SwitchCase(3, FrequentedBlock(otherTarget)));
+    switchValue->appendCase(SwitchCase(13, FrequentedBlock(otherTarget)));
+
+    auto code = compile(proc);
+
+    for (unsigned i = 0; i < 20; ++i) {
+        int32_t expected = (i == 3 || i == 13) ? i : 42;
+        CHECK(invoke<int32_t>(*code, i) == expected);
+    }
 }
 
-void testReturnFloat(float value)
+void testTruncFold(int64_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<ConstFloatValue>(proc, Origin(), value));
-
-    CHECK(isIdentical(compileAndRun<float>(proc), value));
-}
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), value)));
 
-double simpleFunctionDouble(double a, double b)
-{
-    return a + b;
+    CHECK(compileAndRun<int>(proc) == static_cast<int>(value));
 }
 
-void testCallSimpleDouble(double a, double b)
+void testZExt32(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<CCallValue>(
-            proc, Double, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunctionDouble)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
-
-    CHECK(compileAndRun<double>(proc, a, b) == a + b);
-}
+        root->appendNew<Value>(
+            proc, ZExt32, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-float simpleFunctionFloat(float a, float b)
-{
-    return a + b;
+    CHECK(compileAndRun<uint64_t>(proc, value) == static_cast<uint64_t>(static_cast<uint32_t>(value)));
 }
 
-void testCallSimpleFloat(float a, float b)
+void testZExt32Fold(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
-    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<CCallValue>(
-            proc, Float, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunctionFloat)),
-            floatValue1,
-            floatValue2));
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), a + b));
-}
+        root->appendNew<Value>(
+            proc, ZExt32, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), value)));
 
-double functionWithHellaDoubleArguments(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j, double k, double l, double m, double n, double o, double p, double q, double r, double s, double t, double u, double v, double w, double x, double y, double z)
-{
-    return a * pow(2, 0) + b * pow(2, 1) + c * pow(2, 2) + d * pow(2, 3) + e * pow(2, 4) + f * pow(2, 5) + g * pow(2, 6) + h * pow(2, 7) + i * pow(2, 8) + j * pow(2, 9) + k * pow(2, 10) + l * pow(2, 11) + m * pow(2, 12) + n * pow(2, 13) + o * pow(2, 14) + p * pow(2, 15) + q * pow(2, 16) + r * pow(2, 17) + s * pow(2, 18) + t * pow(2, 19) + u * pow(2, 20) + v * pow(2, 21) + w * pow(2, 22) + x * pow(2, 23) + y * pow(2, 24) + z * pow(2, 25);
+    CHECK(compileAndRun<uint64_t>(proc, value) == static_cast<uint64_t>(static_cast<uint32_t>(value)));
 }
 
-void testCallFunctionWithHellaDoubleArguments()
+void testSExt32(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt32, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    Vector<Value*> args;
-    for (unsigned i = 0; i < 26; ++i)
-        args.append(root->appendNew<ConstDoubleValue>(proc, Origin(), i + 1));
-
-    CCallValue* call = root->appendNew<CCallValue>(
-        proc, Double, Origin(),
-        root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaDoubleArguments)));
-    call->children().appendVector(args);
-    
-    root->appendNew<ControlValue>(proc, Return, Origin(), call);
-
-    CHECK(compileAndRun<double>(proc) == functionWithHellaDoubleArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26));
-}
-
-float functionWithHellaFloatArguments(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l, float m, float n, float o, float p, float q, float r, float s, float t, float u, float v, float w, float x, float y, float z)
-{
-    return a * pow(2, 0) + b * pow(2, 1) + c * pow(2, 2) + d * pow(2, 3) + e * pow(2, 4) + f * pow(2, 5) + g * pow(2, 6) + h * pow(2, 7) + i * pow(2, 8) + j * pow(2, 9) + k * pow(2, 10) + l * pow(2, 11) + m * pow(2, 12) + n * pow(2, 13) + o * pow(2, 14) + p * pow(2, 15) + q * pow(2, 16) + r * pow(2, 17) + s * pow(2, 18) + t * pow(2, 19) + u * pow(2, 20) + v * pow(2, 21) + w * pow(2, 22) + x * pow(2, 23) + y * pow(2, 24) + z * pow(2, 25);
+    CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value));
 }
 
-void testCallFunctionWithHellaFloatArguments()
+void testSExt32Fold(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt32, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), value)));
 
-    Vector<Value*> args;
-    for (unsigned i = 0; i < 26; ++i)
-        args.append(root->appendNew<ConstFloatValue>(proc, Origin(), i + 1));
-
-    CCallValue* call = root->appendNew<CCallValue>(
-        proc, Float, Origin(),
-        root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaFloatArguments)));
-    call->children().appendVector(args);
-    
-    root->appendNew<ControlValue>(proc, Return, Origin(), call);
-
-    CHECK(compileAndRun<float>(proc) == functionWithHellaFloatArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26));
+    CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value));
 }
 
-void testChillDiv(int num, int den, int res)
+void testTruncZExt32(int32_t value)
 {
-    // Test non-constant.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
             root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                proc, ZExt32, Origin(),
                 root->appendNew<Value>(
                     proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
-
-        CHECK(compileAndRun<int>(proc, num, den) == res);
-    }
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
 
-    // Test constant.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
-                root->appendNew<Const32Value>(proc, Origin(), num),
-                root->appendNew<Const32Value>(proc, Origin(), den)));
-        
-        CHECK(compileAndRun<int>(proc) == res);
-    }
+    CHECK(compileAndRun<int32_t>(proc, value) == value);
 }
 
-void testChillDivTwice(int num1, int den1, int num2, int den2, int res)
+void testTruncSExt32(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))),
+            proc, Trunc, Origin(),
             root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)),
+                proc, SExt32, Origin(),
                 root->appendNew<Value>(
                     proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)))));
-    
-    CHECK(compileAndRun<int>(proc, num1, den1, num2, den2) == res);
-}
-
-void testChillDiv64(int64_t num, int64_t den, int64_t res)
-{
-    if (!is64Bit())
-        return;
-
-    // Test non-constant.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
-        
-        CHECK(compileAndRun<int64_t>(proc, num, den) == res);
-    }
-
-    // Test constant.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
-                root->appendNew<Const64Value>(proc, Origin(), num),
-                root->appendNew<Const64Value>(proc, Origin(), den)));
-        
-        CHECK(compileAndRun<int64_t>(proc) == res);
-    }
-}
-
-void testModArg(int64_t value)
-{
-    if (!value)
-        return;
-
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument, argument);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
 
-    CHECK(!compileAndRun<int64_t>(proc, value));
+    CHECK(compileAndRun<int32_t>(proc, value) == value);
 }
 
-void testModArgs(int64_t numerator, int64_t denominator)
+void testSExt8(int32_t value)
 {
-    if (!denominator)
-        return;
-    if (numerator == std::numeric_limits<int64_t>::min() && denominator == -1)
-        return;
-
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt8, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == numerator % denominator);
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value)));
 }
 
-void testModImms(int64_t numerator, int64_t denominator)
+void testSExt8Fold(int32_t value)
 {
-    if (!denominator)
-        return;
-    if (numerator == std::numeric_limits<int64_t>::min() && denominator == -1)
-        return;
-
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt8, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), value)));
 
-    Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator);
-    Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator);
-    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == numerator % denominator);
+    CHECK(compileAndRun<int32_t>(proc) == static_cast<int32_t>(static_cast<int8_t>(value)));
 }
 
-void testModArg32(int32_t value)
+void testSExt8SExt8(int32_t value)
 {
-    if (!value)
-        return;
-
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt8, Origin(),
+            root->appendNew<Value>(
+                proc, SExt8, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
 
-    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument, argument);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(!compileAndRun<int32_t>(proc, value));
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value)));
 }
 
-void testModArgs32(int32_t numerator, int32_t denominator)
+void testSExt8SExt16(int32_t value)
 {
-    if (!denominator)
-        return;
-    if (numerator == std::numeric_limits<int32_t>::min() && denominator == -1)
-        return;
-
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt8, Origin(),
+            root->appendNew<Value>(
+                proc, SExt16, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
 
-    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == numerator % denominator);
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value)));
 }
 
-void testModImms32(int32_t numerator, int32_t denominator)
+void testSExt8BitAnd(int32_t value, int32_t mask)
 {
-    if (!denominator)
-        return;
-    if (numerator == std::numeric_limits<int32_t>::min() && denominator == -1)
-        return;
-
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt8, Origin(),
+            root->appendNew<Value>(
+                proc, BitAnd, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), mask))));
 
-    Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator);
-    Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator);
-    Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == numerator % denominator);
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value & mask)));
 }
 
-void testChillModArg(int64_t value)
+void testBitAndSExt8(int32_t value, int32_t mask)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitAnd, Origin(),
+            root->appendNew<Value>(
+                proc, SExt8, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+            root->appendNew<Const32Value>(proc, Origin(), mask)));
 
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(!compileAndRun<int64_t>(proc, value));
+    CHECK(compileAndRun<int32_t>(proc, value) == (static_cast<int32_t>(static_cast<int8_t>(value)) & mask));
 }
 
-void testChillModArgs(int64_t numerator, int64_t denominator)
+void testSExt16(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt16, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value)));
 }
 
-void testChillModImms(int64_t numerator, int64_t denominator)
+void testSExt16Fold(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt16, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), value)));
 
-    Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator);
-    Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator);
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
+    CHECK(compileAndRun<int32_t>(proc) == static_cast<int32_t>(static_cast<int16_t>(value)));
 }
 
-void testChillModArg32(int32_t value)
+void testSExt16SExt16(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt16, Origin(),
+            root->appendNew<Value>(
+                proc, SExt16, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
 
-    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(!compileAndRun<int32_t>(proc, value));
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value)));
 }
 
-void testChillModArgs32(int32_t numerator, int32_t denominator)
+void testSExt16SExt8(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt16, Origin(),
+            root->appendNew<Value>(
+                proc, SExt8, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
 
-    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value)));
 }
 
-void testChillModImms32(int32_t numerator, int32_t denominator)
+void testSExt16BitAnd(int32_t value, int32_t mask)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt16, Origin(),
+            root->appendNew<Value>(
+                proc, BitAnd, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), mask))));
 
-    Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator);
-    Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator);
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value & mask)));
 }
 
-void testSwitch(unsigned degree, unsigned gap = 1)
+void testBitAndSExt16(int32_t value, int32_t mask)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-
-    BasicBlock* terminate = proc.addBlock();
-    terminate->appendNew<ControlValue>(
+    root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        terminate->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(
+            proc, BitAnd, Origin(),
+            root->appendNew<Value>(
+                proc, SExt16, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+            root->appendNew<Const32Value>(proc, Origin(), mask)));
 
-    SwitchValue* switchValue = root->appendNew<SwitchValue>(
-        proc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        FrequentedBlock(terminate));
+    CHECK(compileAndRun<int32_t>(proc, value) == (static_cast<int32_t>(static_cast<int16_t>(value)) & mask));
+}
 
-    for (unsigned i = 0; i < degree; ++i) {
-        BasicBlock* newBlock = proc.addBlock();
-        newBlock->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            newBlock->appendNew<ArgumentRegValue>(
-                proc, Origin(), (i & 1) ? GPRInfo::argumentGPR2 : GPRInfo::argumentGPR1));
-        switchValue->appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock)));
-    }
+void testSExt32BitAnd(int32_t value, int32_t mask)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SExt32, Origin(),
+            root->appendNew<Value>(
+                proc, BitAnd, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), mask))));
 
-    auto code = compile(proc);
+    CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value & mask));
+}
 
-    for (unsigned i = 0; i < degree; ++i) {
-        CHECK(invoke<int32_t>(*code, i * gap, 42, 11) == ((i & 1) ? 11 : 42));
-        if (gap > 1) {
-            CHECK(!invoke<int32_t>(*code, i * gap + 1, 42, 11));
-            CHECK(!invoke<int32_t>(*code, i * gap - 1, 42, 11));
-        }
-    }
+void testBitAndSExt32(int32_t value, int64_t mask)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitAnd, Origin(),
+            root->appendNew<Value>(
+                proc, SExt32, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+            root->appendNew<Const64Value>(proc, Origin(), mask)));
 
-    CHECK(!invoke<int32_t>(*code, -1, 42, 11));
-    CHECK(!invoke<int32_t>(*code, degree * gap, 42, 11));
-    CHECK(!invoke<int32_t>(*code, degree * gap + 1, 42, 11));
+    CHECK(compileAndRun<int64_t>(proc, value) == (static_cast<int64_t>(value) & mask));
 }
 
-void testSwitchChillDiv(unsigned degree, unsigned gap = 1)
+void testBasicSelect()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-
-    Value* left = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* right = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-
-    BasicBlock* terminate = proc.addBlock();
-    terminate->appendNew<ControlValue>(
+    root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        terminate->appendNew<Const32Value>(proc, Origin(), 0));
-
-    SwitchValue* switchValue = root->appendNew<SwitchValue>(
-        proc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        FrequentedBlock(terminate));
-
-    for (unsigned i = 0; i < degree; ++i) {
-        BasicBlock* newBlock = proc.addBlock();
-
-        newBlock->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            newBlock->appendNew<Value>(
-                proc, ChillDiv, Origin(), (i & 1) ? right : left, (i & 1) ? left : right));
-        
-        switchValue->appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock)));
-    }
+        root->appendNew<Value>(
+            proc, Select, Origin(),
+            root->appendNew<Value>(
+                proc, Equal, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
 
     auto code = compile(proc);
-
-    for (unsigned i = 0; i < degree; ++i) {
-        CHECK(invoke<int32_t>(*code, i * gap, 42, 11) == ((i & 1) ? 11/42 : 42/11));
-        if (gap > 1) {
-            CHECK(!invoke<int32_t>(*code, i * gap + 1, 42, 11));
-            CHECK(!invoke<int32_t>(*code, i * gap - 1, 42, 11));
-        }
-    }
-
-    CHECK(!invoke<int32_t>(*code, -1, 42, 11));
-    CHECK(!invoke<int32_t>(*code, degree * gap, 42, 11));
-    CHECK(!invoke<int32_t>(*code, degree * gap + 1, 42, 11));
+    CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
+    CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
+    CHECK(invoke<intptr_t>(*code, 43, 1, 2) == 2);
+    CHECK(invoke<intptr_t>(*code, 43, 642462, 32533) == 32533);
 }
 
-void testTruncFold(int64_t value)
+void testSelectTest()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), value)));
+            proc, Select, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
 
-    CHECK(compileAndRun<int>(proc) == static_cast<int>(value));
+    auto code = compile(proc);
+    CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
+    CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
+    CHECK(invoke<intptr_t>(*code, 0, 1, 2) == 2);
+    CHECK(invoke<intptr_t>(*code, 0, 642462, 32533) == 32533);
 }
 
-void testZExt32(int32_t value)
+void testSelectCompareDouble()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, ZExt32, Origin(),
+            proc, Select, Origin(),
             root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
+                proc, LessThan, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    CHECK(compileAndRun<uint64_t>(proc, value) == static_cast<uint64_t>(static_cast<uint32_t>(value)));
+    auto code = compile(proc);
+    CHECK(invoke<intptr_t>(*code, -1.0, 1.0, 1, 2) == 1);
+    CHECK(invoke<intptr_t>(*code, 42.5, 42.51, 642462, 32533) == 642462);
+    CHECK(invoke<intptr_t>(*code, PNaN, 0.0, 1, 2) == 2);
+    CHECK(invoke<intptr_t>(*code, 42.51, 42.5, 642462, 32533) == 32533);
+    CHECK(invoke<intptr_t>(*code, 42.52, 42.52, 524978245, 352) == 352);
 }
 
-void testZExt32Fold(int32_t value)
+template<B3::Opcode opcode>
+void testSelectCompareFloat(float a, float b, bool (*operation)(float, float))
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
+    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, ZExt32, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), value)));
+            proc, Select, Origin(),
+            root->appendNew<Value>(
+                proc, opcode, Origin(),
+                floatValue1,
+                floatValue2),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42, -5), operation(a, b) ? 42 : -5));
+}
 
-    CHECK(compileAndRun<uint64_t>(proc, value) == static_cast<uint64_t>(static_cast<uint32_t>(value)));
+void testSelectCompareFloat(float a, float b)
+{
+    testSelectCompareFloat<Equal>(a, b, [](float a, float b) -> bool { return a == b; });
+    testSelectCompareFloat<NotEqual>(a, b, [](float a, float b) -> bool { return a != b; });
+    testSelectCompareFloat<LessThan>(a, b, [](float a, float b) -> bool { return a < b; });
+    testSelectCompareFloat<GreaterThan>(a, b, [](float a, float b) -> bool { return a > b; });
+    testSelectCompareFloat<LessEqual>(a, b, [](float a, float b) -> bool { return a <= b; });
+    testSelectCompareFloat<GreaterEqual>(a, b, [](float a, float b) -> bool { return a >= b; });
 }
 
-void testSExt32(int32_t value)
+template<B3::Opcode opcode>
+void testSelectCompareFloatToDouble(float a, float b, bool (*operation)(float, float))
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
+    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
+    Value* doubleValue1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* doubleValue2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt32, Origin(),
+            proc, Select, Origin(),
             root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
+                proc, opcode, Origin(),
+                doubleValue1,
+                doubleValue2),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42, -5), operation(a, b) ? 42 : -5));
+}
 
-    CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value));
+void testSelectCompareFloatToDouble(float a, float b)
+{
+    testSelectCompareFloatToDouble<Equal>(a, b, [](float a, float b) -> bool { return a == b; });
+    testSelectCompareFloatToDouble<NotEqual>(a, b, [](float a, float b) -> bool { return a != b; });
+    testSelectCompareFloatToDouble<LessThan>(a, b, [](float a, float b) -> bool { return a < b; });
+    testSelectCompareFloatToDouble<GreaterThan>(a, b, [](float a, float b) -> bool { return a > b; });
+    testSelectCompareFloatToDouble<LessEqual>(a, b, [](float a, float b) -> bool { return a <= b; });
+    testSelectCompareFloatToDouble<GreaterEqual>(a, b, [](float a, float b) -> bool { return a >= b; });
 }
 
-void testSExt32Fold(int32_t value)
+void testSelectDouble()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt32, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), value)));
+            proc, Select, Origin(),
+            root->appendNew<Value>(
+                proc, Equal, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
 
-    CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value));
+    auto code = compile(proc);
+    CHECK(invoke<double>(*code, 42, 1.5, 2.6) == 1.5);
+    CHECK(invoke<double>(*code, 42, 642462.7, 32533.8) == 642462.7);
+    CHECK(invoke<double>(*code, 43, 1.9, 2.0) == 2.0);
+    CHECK(invoke<double>(*code, 43, 642462.1, 32533.2) == 32533.2);
 }
 
-void testTruncZExt32(int32_t value)
+void testSelectDoubleTest()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<Value>(
-                proc, ZExt32, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
+            proc, Select, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == value);
+    auto code = compile(proc);
+    CHECK(invoke<double>(*code, 42, 1.5, 2.6) == 1.5);
+    CHECK(invoke<double>(*code, 42, 642462.7, 32533.8) == 642462.7);
+    CHECK(invoke<double>(*code, 0, 1.9, 2.0) == 2.0);
+    CHECK(invoke<double>(*code, 0, 642462.1, 32533.2) == 32533.2);
 }
 
-void testTruncSExt32(int32_t value)
+void testSelectDoubleCompareDouble()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Trunc, Origin(),
+            proc, Select, Origin(),
             root->appendNew<Value>(
-                proc, SExt32, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
+                proc, LessThan, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == value);
+    auto code = compile(proc);
+    CHECK(invoke<double>(*code, -1.0, 1.0, 1.1, 2.2) == 1.1);
+    CHECK(invoke<double>(*code, 42.5, 42.51, 642462.3, 32533.4) == 642462.3);
+    CHECK(invoke<double>(*code, PNaN, 0.0, 1.5, 2.6) == 2.6);
+    CHECK(invoke<double>(*code, 42.51, 42.5, 642462.7, 32533.8) == 32533.8);
+    CHECK(invoke<double>(*code, 42.52, 42.52, 524978245.9, 352.0) == 352.0);
 }
 
-void testSExt8(int32_t value)
+void testSelectDoubleCompareFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
+    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt8, Origin(),
+            proc, Select, Origin(),
             root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
+                proc, LessThan, Origin(),
+                floatValue1,
+                floatValue2),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value)));
+    CHECK(isIdentical(compileAndRun<double>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42.1, -M_PI), a < b ? 42.1 : -M_PI));
 }
 
-void testSExt8Fold(int32_t value)
+void testSelectFloatCompareFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* argument3int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
+    Value* argument4int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3));
+    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
+    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
+    Value* floatValue3 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument3int32);
+    Value* floatValue4 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument4int32);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt8, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), value)));
+            proc, Select, Origin(),
+            root->appendNew<Value>(
+                proc, LessThan, Origin(),
+                floatValue1,
+                floatValue2),
+            floatValue3,
+            floatValue4));
 
-    CHECK(compileAndRun<int32_t>(proc) == static_cast<int32_t>(static_cast<int8_t>(value)));
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), bitwise_cast<int32_t>(1.1f), bitwise_cast<int32_t>(-42.f)), a < b ? 1.1f : -42.f));
 }
 
-void testSExt8SExt8(int32_t value)
+void testSelectFold(intptr_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt8, Origin(),
+            proc, Select, Origin(),
             root->appendNew<Value>(
-                proc, SExt8, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
+                proc, Equal, Origin(),
+                root->appendNew<ConstPtrValue>(proc, Origin(), value),
+                root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value)));
+    auto code = compile(proc);
+    CHECK(invoke<intptr_t>(*code, 1, 2) == (value == 42 ? 1 : 2));
+    CHECK(invoke<intptr_t>(*code, 642462, 32533) == (value == 42 ? 642462 : 32533));
 }
 
-void testSExt8SExt16(int32_t value)
+void testSelectInvert()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt8, Origin(),
+            proc, Select, Origin(),
             root->appendNew<Value>(
-                proc, SExt16, Origin(),
+                proc, Equal, Origin(),
                 root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
+                    proc, NotEqual, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                    root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
+                root->appendNew<Const32Value>(proc, Origin(), 0)),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value)));
+    auto code = compile(proc);
+    CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
+    CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
+    CHECK(invoke<intptr_t>(*code, 43, 1, 2) == 2);
+    CHECK(invoke<intptr_t>(*code, 43, 642462, 32533) == 32533);
 }
 
-void testSExt8BitAnd(int32_t value, int32_t mask)
+void testCheckSelect()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
+
+    CheckValue* check = root->appendNew<CheckValue>(
+        proc, Check, Origin(),
         root->appendNew<Value>(
-            proc, SExt8, Origin(),
+            proc, Add, Origin(),
             root->appendNew<Value>(
-                proc, BitAnd, Origin(),
+                proc, Select, Origin(),
                 root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-                root->appendNew<Const32Value>(proc, Origin(), mask))));
+                    proc, BitAnd, Origin(),
+                    root->appendNew<Value>(
+                        proc, Trunc, Origin(),
+                        root->appendNew<ArgumentRegValue>(
+                            proc, Origin(), GPRInfo::argumentGPR0)),
+                    root->appendNew<Const32Value>(proc, Origin(), 0xff)),
+                root->appendNew<ConstPtrValue>(proc, Origin(), -42),
+                root->appendNew<ConstPtrValue>(proc, Origin(), 35)),
+            root->appendNew<ConstPtrValue>(proc, Origin(), 42)));
+    unsigned generationCount = 0;
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
 
-    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value & mask)));
+            generationCount++;
+            jit.move(CCallHelpers::TrustedImm32(666), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(generationCount == 1);
+    CHECK(invoke<int>(*code, true) == 0);
+    CHECK(invoke<int>(*code, false) == 666);
 }
 
-void testBitAndSExt8(int32_t value, int32_t mask)
+void testCheckSelectCheckSelect()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
+
+    CheckValue* check = root->appendNew<CheckValue>(
+        proc, Check, Origin(),
         root->appendNew<Value>(
-            proc, BitAnd, Origin(),
+            proc, Add, Origin(),
             root->appendNew<Value>(
-                proc, SExt8, Origin(),
+                proc, Select, Origin(),
                 root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-            root->appendNew<Const32Value>(proc, Origin(), mask)));
+                    proc, BitAnd, Origin(),
+                    root->appendNew<Value>(
+                        proc, Trunc, Origin(),
+                        root->appendNew<ArgumentRegValue>(
+                            proc, Origin(), GPRInfo::argumentGPR0)),
+                    root->appendNew<Const32Value>(proc, Origin(), 0xff)),
+                root->appendNew<ConstPtrValue>(proc, Origin(), -42),
+                root->appendNew<ConstPtrValue>(proc, Origin(), 35)),
+            root->appendNew<ConstPtrValue>(proc, Origin(), 42)));
+
+    unsigned generationCount = 0;
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
 
-    CHECK(compileAndRun<int32_t>(proc, value) == (static_cast<int32_t>(static_cast<int8_t>(value)) & mask));
+            generationCount++;
+            jit.move(CCallHelpers::TrustedImm32(666), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    
+    CheckValue* check2 = root->appendNew<CheckValue>(
+        proc, Check, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<Value>(
+                proc, Select, Origin(),
+                root->appendNew<Value>(
+                    proc, BitAnd, Origin(),
+                    root->appendNew<Value>(
+                        proc, Trunc, Origin(),
+                        root->appendNew<ArgumentRegValue>(
+                            proc, Origin(), GPRInfo::argumentGPR1)),
+                    root->appendNew<Const32Value>(proc, Origin(), 0xff)),
+                root->appendNew<ConstPtrValue>(proc, Origin(), -43),
+                root->appendNew<ConstPtrValue>(proc, Origin(), 36)),
+            root->appendNew<ConstPtrValue>(proc, Origin(), 43)));
+
+    unsigned generationCount2 = 0;
+    check2->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+
+            generationCount2++;
+            jit.move(CCallHelpers::TrustedImm32(667), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(generationCount == 1);
+    CHECK(generationCount2 == 1);
+    CHECK(invoke<int>(*code, true, true) == 0);
+    CHECK(invoke<int>(*code, false, true) == 666);
+    CHECK(invoke<int>(*code, true, false) == 667);
 }
 
-void testSExt16(int32_t value)
+void testPowDoubleByIntegerLoop(double xOperand, int32_t yOperand)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, SExt16, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value)));
+    Value* x = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* y = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    auto result = powDoubleInt32(proc, root, Origin(), x, y);
+    BasicBlock* continuation = result.first;
+    continuation->appendNew<ControlValue>(proc, Return, Origin(), result.second);
+
+    CHECK(isIdentical(compileAndRun<double>(proc, xOperand, yOperand), pow(xOperand, yOperand)));
 }
 
-void testSExt16Fold(int32_t value)
+void testTruncOrHigh()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt16, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), value)));
+            proc, Trunc, Origin(),
+            root->appendNew<Value>(
+                proc, BitOr, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<Const64Value>(proc, Origin(), 0x100000000))));
 
-    CHECK(compileAndRun<int32_t>(proc) == static_cast<int32_t>(static_cast<int16_t>(value)));
+    int64_t value = 0x123456781234;
+    CHECK(compileAndRun<int>(proc, value) == 0x56781234);
 }
 
-void testSExt16SExt16(int32_t value)
+void testTruncOrLow()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt16, Origin(),
+            proc, Trunc, Origin(),
             root->appendNew<Value>(
-                proc, SExt16, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
+                proc, BitOr, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<Const64Value>(proc, Origin(), 0x1000000))));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value)));
+    int64_t value = 0x123456781234;
+    CHECK(compileAndRun<int>(proc, value) == 0x57781234);
 }
 
-void testSExt16SExt8(int32_t value)
+void testBitAndOrHigh()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt16, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Value>(
-                proc, SExt8, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))));
+                proc, BitOr, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<Const64Value>(proc, Origin(), 0x8)),
+            root->appendNew<Const64Value>(proc, Origin(), 0x777777777777)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value)));
+    int64_t value = 0x123456781234;
+    CHECK(compileAndRun<int64_t>(proc, value) == 0x123456701234ll);
 }
 
-void testSExt16BitAnd(int32_t value, int32_t mask)
+void testBitAndOrLow()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SExt16, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Value>(
-                proc, BitAnd, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-                root->appendNew<Const32Value>(proc, Origin(), mask))));
+                proc, BitOr, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<Const64Value>(proc, Origin(), 0x1)),
+            root->appendNew<Const64Value>(proc, Origin(), 0x777777777777)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value & mask)));
+    int64_t value = 0x123456781234;
+    CHECK(compileAndRun<int64_t>(proc, value) == 0x123456701235ll);
 }
 
-void testBitAndSExt16(int32_t value, int32_t mask)
+void testBranch64Equal(int64_t left, int64_t right)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    bool trueResult = true;
+    thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Value>(
-                proc, SExt16, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-            root->appendNew<Const32Value>(proc, Origin(), mask)));
+        thenCase->appendNew<MemoryValue>(
+            proc, Load8Z, Origin(),
+            thenCase->appendNew<ConstPtrValue>(proc, Origin(), &trueResult)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == (static_cast<int32_t>(static_cast<int16_t>(value)) & mask));
+    bool elseResult = false;
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<MemoryValue>(
+            proc, Load8Z, Origin(),
+            elseCase->appendNew<ConstPtrValue>(proc, Origin(), &elseResult)));
+
+    CHECK(compileAndRun<bool>(proc, left, right) == (left == right));
 }
 
-void testSExt32BitAnd(int32_t value, int32_t mask)
+void testBranch64EqualImm(int64_t left, int64_t right)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root->appendNew<ConstPtrValue>(proc, Origin(), right);
     root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    bool trueResult = true;
+    thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, SExt32, Origin(),
-            root->appendNew<Value>(
-                proc, BitAnd, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-                root->appendNew<Const32Value>(proc, Origin(), mask))));
+        thenCase->appendNew<MemoryValue>(
+            proc, Load8Z, Origin(),
+            thenCase->appendNew<ConstPtrValue>(proc, Origin(), &trueResult)));
 
-    CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value & mask));
+    bool elseResult = false;
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<MemoryValue>(
+            proc, Load8Z, Origin(),
+            elseCase->appendNew<ConstPtrValue>(proc, Origin(), &elseResult)));
+
+    CHECK(compileAndRun<bool>(proc, left) == (left == right));
 }
 
-void testBitAndSExt32(int32_t value, int64_t mask)
+void testBranch64EqualMem(int64_t left, int64_t right)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* arg1 = root->appendNew<MemoryValue>(
+        proc, Load, pointerType(), Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    bool trueResult = true;
+    thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Value>(
-                proc, SExt32, Origin(),
-                root->appendNew<Value>(
-                    proc, Trunc, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-            root->appendNew<Const64Value>(proc, Origin(), mask)));
+        thenCase->appendNew<MemoryValue>(
+            proc, Load8Z, Origin(),
+            thenCase->appendNew<ConstPtrValue>(proc, Origin(), &trueResult)));
 
-    CHECK(compileAndRun<int64_t>(proc, value) == (static_cast<int64_t>(value) & mask));
+    bool elseResult = false;
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<MemoryValue>(
+            proc, Load8Z, Origin(),
+            elseCase->appendNew<ConstPtrValue>(proc, Origin(), &elseResult)));
+
+    CHECK(compileAndRun<bool>(proc, &left, right) == (left == right));
 }
 
-void testBasicSelect()
+void testBranch64EqualMemImm(int64_t left, int64_t right)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* arg1 = root->appendNew<MemoryValue>(
+        proc, Load, pointerType(), Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root->appendNew<ConstPtrValue>(proc, Origin(), right);
     root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    bool trueResult = true;
+    thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<Value>(
-                proc, Equal, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+        thenCase->appendNew<MemoryValue>(
+            proc, Load8Z, Origin(),
+            thenCase->appendNew<ConstPtrValue>(proc, Origin(), &trueResult)));
 
-    auto code = compile(proc);
-    CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
-    CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
-    CHECK(invoke<intptr_t>(*code, 43, 1, 2) == 2);
-    CHECK(invoke<intptr_t>(*code, 43, 642462, 32533) == 32533);
+    bool elseResult = false;
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<MemoryValue>(
+            proc, Load8Z, Origin(),
+            elseCase->appendNew<ConstPtrValue>(proc, Origin(), &elseResult)));
+
+    CHECK(compileAndRun<bool>(proc, &left) == (left == right));
 }
 
-void testSelectTest()
+void testStore8Load8Z(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    
+    int8_t byte;
+    Value* ptr = root->appendNew<ConstPtrValue>(proc, Origin(), &byte);
+    
+    root->appendNew<MemoryValue>(
+        proc, Store8, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        ptr);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+        root->appendNew<MemoryValue>(proc, Load8Z, Origin(), ptr));
 
-    auto code = compile(proc);
-    CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
-    CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
-    CHECK(invoke<intptr_t>(*code, 0, 1, 2) == 2);
-    CHECK(invoke<intptr_t>(*code, 0, 642462, 32533) == 32533);
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<uint8_t>(value));
 }
 
-void testSelectCompareDouble()
+void testStore16Load16Z(int32_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    
+    int16_t byte;
+    Value* ptr = root->appendNew<ConstPtrValue>(proc, Origin(), &byte);
+    
+    root->appendNew<MemoryValue>(
+        proc, Store16, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        ptr);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<Value>(
-                proc, LessThan, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        root->appendNew<MemoryValue>(proc, Load16Z, Origin(), ptr));
 
-    auto code = compile(proc);
-    CHECK(invoke<intptr_t>(*code, -1.0, 1.0, 1, 2) == 1);
-    CHECK(invoke<intptr_t>(*code, 42.5, 42.51, 642462, 32533) == 642462);
-    CHECK(invoke<intptr_t>(*code, PNaN, 0.0, 1, 2) == 2);
-    CHECK(invoke<intptr_t>(*code, 42.51, 42.5, 642462, 32533) == 32533);
-    CHECK(invoke<intptr_t>(*code, 42.52, 42.52, 524978245, 352) == 352);
+    CHECK(compileAndRun<int32_t>(proc, value) == static_cast<uint16_t>(value));
 }
 
-template<B3::Opcode opcode>
-void testSelectCompareFloat(float a, float b, bool (*operation)(float, float))
+void testSShrShl32(int32_t value, int32_t sshrAmount, int32_t shlAmount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
-    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
 
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Select, Origin(),
+            proc, SShr, Origin(),
             root->appendNew<Value>(
-                proc, opcode, Origin(),
-                floatValue1,
-                floatValue2),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)));
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42, -5), operation(a, b) ? 42 : -5));
-}
+                proc, Shl, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), shlAmount)),
+            root->appendNew<Const32Value>(proc, Origin(), sshrAmount)));
 
-void testSelectCompareFloat(float a, float b)
-{
-    testSelectCompareFloat<Equal>(a, b, [](float a, float b) -> bool { return a == b; });
-    testSelectCompareFloat<NotEqual>(a, b, [](float a, float b) -> bool { return a != b; });
-    testSelectCompareFloat<LessThan>(a, b, [](float a, float b) -> bool { return a < b; });
-    testSelectCompareFloat<GreaterThan>(a, b, [](float a, float b) -> bool { return a > b; });
-    testSelectCompareFloat<LessEqual>(a, b, [](float a, float b) -> bool { return a <= b; });
-    testSelectCompareFloat<GreaterEqual>(a, b, [](float a, float b) -> bool { return a >= b; });
+    CHECK(
+        compileAndRun<int32_t>(proc, value)
+        == ((value << (shlAmount & 31)) >> (sshrAmount & 31)));
 }
 
-template<B3::Opcode opcode>
-void testSelectCompareFloatToDouble(float a, float b, bool (*operation)(float, float))
+void testSShrShl64(int64_t value, int32_t sshrAmount, int32_t shlAmount)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
-    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
-    Value* doubleValue1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
-    Value* doubleValue2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
 
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Select, Origin(),
+            proc, SShr, Origin(),
             root->appendNew<Value>(
-                proc, opcode, Origin(),
-                doubleValue1,
-                doubleValue2),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)));
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42, -5), operation(a, b) ? 42 : -5));
+                proc, Shl, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+                root->appendNew<Const32Value>(proc, Origin(), shlAmount)),
+            root->appendNew<Const32Value>(proc, Origin(), sshrAmount)));
+
+    CHECK(
+        compileAndRun<int64_t>(proc, value)
+        == ((value << (shlAmount & 63)) >> (sshrAmount & 63)));
 }
 
-void testSelectCompareFloatToDouble(float a, float b)
+template<typename T>
+void testComputeDivisionMagic(T value, T magicMultiplier, unsigned shift)
 {
-    testSelectCompareFloatToDouble<Equal>(a, b, [](float a, float b) -> bool { return a == b; });
-    testSelectCompareFloatToDouble<NotEqual>(a, b, [](float a, float b) -> bool { return a != b; });
-    testSelectCompareFloatToDouble<LessThan>(a, b, [](float a, float b) -> bool { return a < b; });
-    testSelectCompareFloatToDouble<GreaterThan>(a, b, [](float a, float b) -> bool { return a > b; });
-    testSelectCompareFloatToDouble<LessEqual>(a, b, [](float a, float b) -> bool { return a <= b; });
-    testSelectCompareFloatToDouble<GreaterEqual>(a, b, [](float a, float b) -> bool { return a >= b; });
+    DivisionMagic<T> magic = computeDivisionMagic(value);
+    CHECK(magic.magicMultiplier == magicMultiplier);
+    CHECK(magic.shift == shift);
 }
 
-void testSelectDouble()
+void testTrivialInfiniteLoop()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<Value>(
-                proc, Equal, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
+    BasicBlock* loop = proc.addBlock();
+    root->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop));
+    loop->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop));
 
-    auto code = compile(proc);
-    CHECK(invoke<double>(*code, 42, 1.5, 2.6) == 1.5);
-    CHECK(invoke<double>(*code, 42, 642462.7, 32533.8) == 642462.7);
-    CHECK(invoke<double>(*code, 43, 1.9, 2.0) == 2.0);
-    CHECK(invoke<double>(*code, 43, 642462.1, 32533.2) == 32533.2);
+    compile(proc);
 }
 
-void testSelectDoubleTest()
+void testFoldPathEqual()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    BasicBlock* thenBlock = proc.addBlock();
+    BasicBlock* elseBlock = proc.addBlock();
+
+    Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+
     root->appendNew<ControlValue>(
+        proc, Branch, Origin(), arg, FrequentedBlock(thenBlock), FrequentedBlock(elseBlock));
+
+    thenBlock->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
+        thenBlock->appendNew<Value>(
+            proc, Equal, Origin(), arg, thenBlock->appendNew<ConstPtrValue>(proc, Origin(), 0)));
+
+    elseBlock->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseBlock->appendNew<Value>(
+            proc, Equal, Origin(), arg, elseBlock->appendNew<ConstPtrValue>(proc, Origin(), 0)));
 
     auto code = compile(proc);
-    CHECK(invoke<double>(*code, 42, 1.5, 2.6) == 1.5);
-    CHECK(invoke<double>(*code, 42, 642462.7, 32533.8) == 642462.7);
-    CHECK(invoke<double>(*code, 0, 1.9, 2.0) == 2.0);
-    CHECK(invoke<double>(*code, 0, 642462.1, 32533.2) == 32533.2);
+    CHECK(invoke<intptr_t>(*code, 0) == 1);
+    CHECK(invoke<intptr_t>(*code, 1) == 0);
+    CHECK(invoke<intptr_t>(*code, 42) == 0);
 }
 
-void testSelectDoubleCompareDouble()
+void testLShiftSelf32()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* arg = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<Value>(
-                proc, LessThan, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3)));
+        root->appendNew<Value>(proc, Shl, Origin(), arg, arg));
 
     auto code = compile(proc);
-    CHECK(invoke<double>(*code, -1.0, 1.0, 1.1, 2.2) == 1.1);
-    CHECK(invoke<double>(*code, 42.5, 42.51, 642462.3, 32533.4) == 642462.3);
-    CHECK(invoke<double>(*code, PNaN, 0.0, 1.5, 2.6) == 2.6);
-    CHECK(invoke<double>(*code, 42.51, 42.5, 642462.7, 32533.8) == 32533.8);
-    CHECK(invoke<double>(*code, 42.52, 42.52, 524978245.9, 352.0) == 352.0);
+
+    auto check = [&] (int32_t value) {
+        CHECK(invoke<int32_t>(*code, value) == value << (value & 31));
+    };
+
+    check(0);
+    check(1);
+    check(31);
+    check(32);
 }
 
-void testSelectDoubleCompareFloat(float a, float b)
+void testRShiftSelf32()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+    Value* arg = root->appendNew<Value>(
+        proc, Trunc, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
-    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
-
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<Value>(
-                proc, LessThan, Origin(),
-                floatValue1,
-                floatValue2),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)));
+        root->appendNew<Value>(proc, SShr, Origin(), arg, arg));
 
-    CHECK(isIdentical(compileAndRun<double>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42.1, -M_PI), a < b ? 42.1 : -M_PI));
+    auto code = compile(proc);
+
+    auto check = [&] (int32_t value) {
+        CHECK(invoke<int32_t>(*code, value) == value >> (value & 31));
+    };
+
+    check(0);
+    check(1);
+    check(31);
+    check(32);
 }
 
-void testSelectFloatCompareFloat(float a, float b)
+void testURShiftSelf32()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(),
+    Value* arg = root->appendNew<Value>(
+        proc, Trunc, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* argument3int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
-    Value* argument4int32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3));
-    Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32);
-    Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32);
-    Value* floatValue3 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument3int32);
-    Value* floatValue4 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument4int32);
-
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<Value>(
-                proc, LessThan, Origin(),
-                floatValue1,
-                floatValue2),
-            floatValue3,
-            floatValue4));
+        root->appendNew<Value>(proc, ZShr, Origin(), arg, arg));
 
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), bitwise_cast<int32_t>(1.1f), bitwise_cast<int32_t>(-42.f)), a < b ? 1.1f : -42.f));
+    auto code = compile(proc);
+
+    auto check = [&] (uint32_t value) {
+        CHECK(invoke<uint32_t>(*code, value) == value >> (value & 31));
+    };
+
+    check(0);
+    check(1);
+    check(31);
+    check(32);
 }
 
-void testSelectFold(intptr_t value)
+void testLShiftSelf64()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<Value>(
-                proc, Equal, Origin(),
-                root->appendNew<ConstPtrValue>(proc, Origin(), value),
-                root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+            proc, Shl, Origin(), arg, root->appendNew<Value>(proc, Trunc, Origin(), arg)));
 
     auto code = compile(proc);
-    CHECK(invoke<intptr_t>(*code, 1, 2) == (value == 42 ? 1 : 2));
-    CHECK(invoke<intptr_t>(*code, 642462, 32533) == (value == 42 ? 642462 : 32533));
+
+    auto check = [&] (int64_t value) {
+        CHECK(invoke<int64_t>(*code, value) == value << (value & 63));
+    };
+
+    check(0);
+    check(1);
+    check(31);
+    check(32);
+    check(63);
+    check(64);
 }
 
-void testSelectInvert()
+void testRShiftSelf64()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Select, Origin(),
-            root->appendNew<Value>(
-                proc, Equal, Origin(),
-                root->appendNew<Value>(
-                    proc, NotEqual, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                    root->appendNew<ConstPtrValue>(proc, Origin(), 42)),
-                root->appendNew<Const32Value>(proc, Origin(), 0)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+            proc, SShr, Origin(), arg, root->appendNew<Value>(proc, Trunc, Origin(), arg)));
 
     auto code = compile(proc);
-    CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1);
-    CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462);
-    CHECK(invoke<intptr_t>(*code, 43, 1, 2) == 2);
-    CHECK(invoke<intptr_t>(*code, 43, 642462, 32533) == 32533);
+
+    auto check = [&] (int64_t value) {
+        CHECK(invoke<int64_t>(*code, value) == value >> (value & 63));
+    };
+
+    check(0);
+    check(1);
+    check(31);
+    check(32);
+    check(63);
+    check(64);
 }
 
-void testPowDoubleByIntegerLoop(double xOperand, int32_t yOperand)
+void testURShiftSelf64()
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, ZShr, Origin(), arg, root->appendNew<Value>(proc, Trunc, Origin(), arg)));
 
-    Value* x = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* y = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    auto result = powDoubleInt32(proc, root, Origin(), x, y);
-    BasicBlock* continuation = result.first;
-    continuation->appendNew<ControlValue>(proc, Return, Origin(), result.second);
+    auto code = compile(proc);
 
-    CHECK(isIdentical(compileAndRun<double>(proc, xOperand, yOperand), pow(xOperand, yOperand)));
+    auto check = [&] (uint64_t value) {
+        CHECK(invoke<uint64_t>(*code, value) == value >> (value & 63));
+    };
+
+    check(0);
+    check(1);
+    check(31);
+    check(32);
+    check(63);
+    check(64);
 }
 
 // Make sure the compiler does not try to optimize anything out.
@@ -8855,6 +10342,13 @@ void run(const char* filter)
 
     RUN(test42());
     RUN(testLoad42());
+    RUN(testLoadOffsetImm9Max());
+    RUN(testLoadOffsetImm9MaxPlusOne());
+    RUN(testLoadOffsetImm9MaxPlusTwo());
+    RUN(testLoadOffsetImm9Min());
+    RUN(testLoadOffsetImm9MinMinusOne());
+    RUN(testLoadOffsetScaledUnsignedImm12Max());
+    RUN(testLoadOffsetScaledUnsignedOverImm12Max());
     RUN(testArg(43));
     RUN(testReturnConst64(5));
     RUN(testReturnConst64(-42));
@@ -9437,13 +10931,38 @@ void run(const char* filter)
     RUN(testStore8Arg());
     RUN(testStore8Imm());
     RUN(testStorePartial8BitRegisterOnX86());
+    RUN(testStore16Arg());
+    RUN(testStore16Imm());
     RUN(testTrunc((static_cast<int64_t>(1) << 40) + 42));
     RUN(testAdd1(45));
     RUN(testAdd1Ptr(51));
     RUN(testAdd1Ptr(bitwise_cast<intptr_t>(vm)));
     RUN(testNeg32(52));
     RUN(testNegPtr(53));
-    RUN(testStoreAddLoad(46));
+    RUN(testStoreAddLoad32(46));
+    RUN(testStoreAddLoadImm32(46));
+    RUN(testStoreAddLoad64(4600));
+    RUN(testStoreAddLoadImm64(4600));
+    RUN(testStoreAddLoad8(4, Load8Z));
+    RUN(testStoreAddLoadImm8(4, Load8Z));
+    RUN(testStoreAddLoad8(4, Load8S));
+    RUN(testStoreAddLoadImm8(4, Load8S));
+    RUN(testStoreAddLoad16(6, Load16Z));
+    RUN(testStoreAddLoadImm16(6, Load16Z));
+    RUN(testStoreAddLoad16(6, Load16S));
+    RUN(testStoreAddLoadImm16(6, Load16S));
+    RUN(testStoreAddLoad32Index(46));
+    RUN(testStoreAddLoadImm32Index(46));
+    RUN(testStoreAddLoad64Index(4600));
+    RUN(testStoreAddLoadImm64Index(4600));
+    RUN(testStoreAddLoad8Index(4, Load8Z));
+    RUN(testStoreAddLoadImm8Index(4, Load8Z));
+    RUN(testStoreAddLoad8Index(4, Load8S));
+    RUN(testStoreAddLoadImm8Index(4, Load8S));
+    RUN(testStoreAddLoad16Index(6, Load16Z));
+    RUN(testStoreAddLoadImm16Index(6, Load16Z));
+    RUN(testStoreAddLoad16Index(6, Load16S));
+    RUN(testStoreAddLoadImm16Index(6, Load16S));
     RUN(testStoreSubLoad(46));
     RUN(testStoreAddLoadInterference(52));
     RUN(testStoreAddAndLoad(47, 0xffff));
@@ -9461,6 +10980,7 @@ void run(const char* filter)
     RUN(testLoadAddrShift(2));
     RUN(testLoadAddrShift(3));
     RUN(testFramePointer());
+    RUN(testOverrideFramePointer());
     RUN(testStackSlot());
     RUN(testLoadFromFramePointer());
     RUN(testStoreLoadStackSlot(50));
@@ -9502,8 +11022,6 @@ void run(const char* filter)
     RUN(testBranchLoad16Z());
 
     RUN(testComplex(64, 128));
-    RUN(testComplex(64, 256));
-    RUN(testComplex(64, 384));
     RUN(testComplex(4, 128));
     RUN(testComplex(4, 256));
     RUN(testComplex(4, 384));
@@ -9518,6 +11036,8 @@ void run(const char* filter)
     RUN(testPatchpointFixedRegister());
     RUN(testPatchpointAny(ValueRep::WarmAny));
     RUN(testPatchpointAny(ValueRep::ColdAny));
+    RUN(testPatchpointGPScratch());
+    RUN(testPatchpointFPScratch());
     RUN(testPatchpointLotsOfLateAnys());
     RUN(testPatchpointAnyImm(ValueRep::WarmAny));
     RUN(testPatchpointAnyImm(ValueRep::ColdAny));
@@ -9527,6 +11047,8 @@ void run(const char* filter)
     RUN(testPatchpointWithStackArgumentResult());
     RUN(testPatchpointWithAnyResult());
     RUN(testSimpleCheck());
+    RUN(testCheckFalse());
+    RUN(testCheckTrue());
     RUN(testCheckLessThan());
     RUN(testCheckMegaCombo());
     RUN(testCheckTrickyMegaCombo());
@@ -9630,6 +11152,8 @@ void run(const char* filter)
     RUN(testInt32ToDoublePartialRegisterWithoutStall());
 
     RUN(testCallSimple(1, 2));
+    RUN(testCallRare(1, 2));
+    RUN(testCallRareLive(1, 2, 3));
     RUN(testCallSimplePure(1, 2));
     RUN(testCallFunctionWithHellaArguments());
 
@@ -9694,6 +11218,9 @@ void run(const char* filter)
     RUN(testSwitchChillDiv(100, 1));
     RUN(testSwitchChillDiv(100, 100));
 
+    RUN(testSwitchTargettingSameBlock());
+    RUN(testSwitchTargettingSameBlockFoldPathConstant());
+
     RUN(testTrunc(0));
     RUN(testTrunc(1));
     RUN(testTrunc(-1));
@@ -9946,8 +11473,148 @@ void run(const char* filter)
     RUN(testSelectFold(42));
     RUN(testSelectFold(43));
     RUN(testSelectInvert());
+    RUN(testCheckSelect());
+    RUN(testCheckSelectCheckSelect());
     RUN_BINARY(testPowDoubleByIntegerLoop, floatingPointOperands<double>(), int64Operands());
 
+    RUN(testTruncOrHigh());
+    RUN(testTruncOrLow());
+    RUN(testBitAndOrHigh());
+    RUN(testBitAndOrLow());
+
+    RUN(testBranch64Equal(0, 0));
+    RUN(testBranch64Equal(1, 1));
+    RUN(testBranch64Equal(-1, -1));
+    RUN(testBranch64Equal(1, -1));
+    RUN(testBranch64Equal(-1, 1));
+    RUN(testBranch64EqualImm(0, 0));
+    RUN(testBranch64EqualImm(1, 1));
+    RUN(testBranch64EqualImm(-1, -1));
+    RUN(testBranch64EqualImm(1, -1));
+    RUN(testBranch64EqualImm(-1, 1));
+    RUN(testBranch64EqualMem(0, 0));
+    RUN(testBranch64EqualMem(1, 1));
+    RUN(testBranch64EqualMem(-1, -1));
+    RUN(testBranch64EqualMem(1, -1));
+    RUN(testBranch64EqualMem(-1, 1));
+    RUN(testBranch64EqualMemImm(0, 0));
+    RUN(testBranch64EqualMemImm(1, 1));
+    RUN(testBranch64EqualMemImm(-1, -1));
+    RUN(testBranch64EqualMemImm(1, -1));
+    RUN(testBranch64EqualMemImm(-1, 1));
+
+    RUN(testStore8Load8Z(0));
+    RUN(testStore8Load8Z(123));
+    RUN(testStore8Load8Z(12345));
+    RUN(testStore8Load8Z(-123));
+
+    RUN(testStore16Load16Z(0));
+    RUN(testStore16Load16Z(123));
+    RUN(testStore16Load16Z(12345));
+    RUN(testStore16Load16Z(12345678));
+    RUN(testStore16Load16Z(-123));
+
+    RUN(testSShrShl32(42, 24, 24));
+    RUN(testSShrShl32(-42, 24, 24));
+    RUN(testSShrShl32(4200, 24, 24));
+    RUN(testSShrShl32(-4200, 24, 24));
+    RUN(testSShrShl32(4200000, 24, 24));
+    RUN(testSShrShl32(-4200000, 24, 24));
+
+    RUN(testSShrShl32(42, 16, 16));
+    RUN(testSShrShl32(-42, 16, 16));
+    RUN(testSShrShl32(4200, 16, 16));
+    RUN(testSShrShl32(-4200, 16, 16));
+    RUN(testSShrShl32(4200000, 16, 16));
+    RUN(testSShrShl32(-4200000, 16, 16));
+
+    RUN(testSShrShl32(42, 8, 8));
+    RUN(testSShrShl32(-42, 8, 8));
+    RUN(testSShrShl32(4200, 8, 8));
+    RUN(testSShrShl32(-4200, 8, 8));
+    RUN(testSShrShl32(4200000, 8, 8));
+    RUN(testSShrShl32(-4200000, 8, 8));
+    RUN(testSShrShl32(420000000, 8, 8));
+    RUN(testSShrShl32(-420000000, 8, 8));
+
+    RUN(testSShrShl64(42, 56, 56));
+    RUN(testSShrShl64(-42, 56, 56));
+    RUN(testSShrShl64(4200, 56, 56));
+    RUN(testSShrShl64(-4200, 56, 56));
+    RUN(testSShrShl64(4200000, 56, 56));
+    RUN(testSShrShl64(-4200000, 56, 56));
+    RUN(testSShrShl64(420000000, 56, 56));
+    RUN(testSShrShl64(-420000000, 56, 56));
+    RUN(testSShrShl64(42000000000, 56, 56));
+    RUN(testSShrShl64(-42000000000, 56, 56));
+
+    RUN(testSShrShl64(42, 48, 48));
+    RUN(testSShrShl64(-42, 48, 48));
+    RUN(testSShrShl64(4200, 48, 48));
+    RUN(testSShrShl64(-4200, 48, 48));
+    RUN(testSShrShl64(4200000, 48, 48));
+    RUN(testSShrShl64(-4200000, 48, 48));
+    RUN(testSShrShl64(420000000, 48, 48));
+    RUN(testSShrShl64(-420000000, 48, 48));
+    RUN(testSShrShl64(42000000000, 48, 48));
+    RUN(testSShrShl64(-42000000000, 48, 48));
+
+    RUN(testSShrShl64(42, 32, 32));
+    RUN(testSShrShl64(-42, 32, 32));
+    RUN(testSShrShl64(4200, 32, 32));
+    RUN(testSShrShl64(-4200, 32, 32));
+    RUN(testSShrShl64(4200000, 32, 32));
+    RUN(testSShrShl64(-4200000, 32, 32));
+    RUN(testSShrShl64(420000000, 32, 32));
+    RUN(testSShrShl64(-420000000, 32, 32));
+    RUN(testSShrShl64(42000000000, 32, 32));
+    RUN(testSShrShl64(-42000000000, 32, 32));
+
+    RUN(testSShrShl64(42, 24, 24));
+    RUN(testSShrShl64(-42, 24, 24));
+    RUN(testSShrShl64(4200, 24, 24));
+    RUN(testSShrShl64(-4200, 24, 24));
+    RUN(testSShrShl64(4200000, 24, 24));
+    RUN(testSShrShl64(-4200000, 24, 24));
+    RUN(testSShrShl64(420000000, 24, 24));
+    RUN(testSShrShl64(-420000000, 24, 24));
+    RUN(testSShrShl64(42000000000, 24, 24));
+    RUN(testSShrShl64(-42000000000, 24, 24));
+
+    RUN(testSShrShl64(42, 16, 16));
+    RUN(testSShrShl64(-42, 16, 16));
+    RUN(testSShrShl64(4200, 16, 16));
+    RUN(testSShrShl64(-4200, 16, 16));
+    RUN(testSShrShl64(4200000, 16, 16));
+    RUN(testSShrShl64(-4200000, 16, 16));
+    RUN(testSShrShl64(420000000, 16, 16));
+    RUN(testSShrShl64(-420000000, 16, 16));
+    RUN(testSShrShl64(42000000000, 16, 16));
+    RUN(testSShrShl64(-42000000000, 16, 16));
+
+    RUN(testSShrShl64(42, 8, 8));
+    RUN(testSShrShl64(-42, 8, 8));
+    RUN(testSShrShl64(4200, 8, 8));
+    RUN(testSShrShl64(-4200, 8, 8));
+    RUN(testSShrShl64(4200000, 8, 8));
+    RUN(testSShrShl64(-4200000, 8, 8));
+    RUN(testSShrShl64(420000000, 8, 8));
+    RUN(testSShrShl64(-420000000, 8, 8));
+    RUN(testSShrShl64(42000000000, 8, 8));
+    RUN(testSShrShl64(-42000000000, 8, 8));
+
+    RUN(testCheckMul64SShr());
+    RUN(testComputeDivisionMagic<int32_t>(2, -2147483647, 0));
+    RUN(testTrivialInfiniteLoop());
+    RUN(testFoldPathEqual());
+    
+    RUN(testRShiftSelf32());
+    RUN(testURShiftSelf32());
+    RUN(testLShiftSelf32());
+    RUN(testRShiftSelf64());
+    RUN(testURShiftSelf64());
+    RUN(testLShiftSelf64());
+
     if (tasks.isEmpty())
         usage();