MacroAssemblerX86 should be happy with shift(cx, cx)
[WebKit-https.git] / Source / JavaScriptCore / b3 / testb3.cpp
index e8de623..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
 
 #include "config.h"
 
+#include "AllowMacroScratchRegisterUsage.h"
 #include "B3ArgumentRegValue.h"
 #include "B3BasicBlockInlines.h"
 #include "B3CCallValue.h"
 #include "B3Compilation.h"
+#include "B3ComputeDivisionMagic.h"
 #include "B3Const32Value.h"
 #include "B3ConstPtrValue.h"
 #include "B3ControlValue.h"
+#include "B3Effects.h"
+#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"
 #include "B3ValueInlines.h"
@@ -67,8 +73,16 @@ using namespace JSC::B3;
 
 namespace {
 
+StaticLock crashLock;
+
 // Nothing fancy for now; we just use the existing WTF assertion machinery.
-#define CHECK(x) RELEASE_ASSERT(x)
+#define CHECK(x) do {                                                   \
+        if (!!(x))                                                      \
+            break;                                                      \
+        crashLock.lock();                                               \
+        WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
+        CRASH();                                                        \
+    } while (false)
 
 VM* vm;
 
@@ -90,6 +104,16 @@ T compileAndRun(Procedure& procedure, Arguments... arguments)
     return invoke<T>(*compile(procedure), arguments...);
 }
 
+void add32(CCallHelpers& jit, GPRReg src1, GPRReg src2, GPRReg dest)
+{
+    if (src2 == dest)
+        jit.add32(src1, dest);
+    else {
+        jit.move(src1, dest);
+        jit.add32(src2, dest);
+    }
+}
+
 void test42()
 {
     Procedure proc;
@@ -114,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;
@@ -190,6 +285,67 @@ void testAddImmArg(int a, int b)
     CHECK(compileAndRun<int>(proc, b) == a + b);
 }
 
+void testAddArgMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun<int64_t>(proc, a, &inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddMemArg(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(),
+        load,
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int64_t>(proc, &a, b) == a + b);
+}
+
+void testAddImmMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(),
+        root->appendNew<Const64Value>(proc, Origin(), a),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddArg32(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Add, Origin(), value, value));
+
+    CHECK(compileAndRun<int>(proc, a) == a + a);
+}
+
 void testAddArgs32(int a, int b)
 {
     Procedure proc;
@@ -208,6 +364,54 @@ void testAddArgs32(int a, int b)
     CHECK(compileAndRun<int>(proc, a, b) == a + b);
 }
 
+void testAddArgMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), argument, load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun<int32_t>(proc, a, &inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddMemArg32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), load, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, &a, b) == a + b);
+}
+
+void testAddImmMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), a),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
 void testAddLoadTwice()
 {
     auto test = [&] (unsigned optLevel) {
@@ -293,6 +497,141 @@ void testAddImmsDouble(double a, double b)
     CHECK(isIdentical(compileAndRun<double>(proc), a + b));
 }
 
+void testAddArgFloat(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), floatValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a + a)));
+}
+
+void testAddArgsFloat(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);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), floatValue1, floatValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a + b)));
+}
+
+void testAddArgImmFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), floatValue, constValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a + b)));
+}
+
+void testAddImmArgFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), constValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a + b)));
+}
+
+void testAddImmsFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), constValue1, constValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a + b)));
+}
+
+void testAddArgFloatWithUselessDoubleConversion(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argumentInt32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentInt32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), asDouble, asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a + a)));
+}
+
+void testAddArgsFloatWithUselessDoubleConversion(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);
+    Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), asDouble1, asDouble2);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a + b)));
+}
+
+void testAddArgsFloatWithEffectfulDoubleConversion(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);
+    Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), asDouble1, asDouble2);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* doubleAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleAddress);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    double effect = 0;
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), &effect), bitwise_cast<int32_t>(a + b)));
+    CHECK(isIdentical(effect, static_cast<double>(a) + static_cast<double>(b)));
+}
+
 void testMulArg(int a)
 {
     Procedure proc;
@@ -496,6 +835,141 @@ void testMulImmsDouble(double a, double b)
     CHECK(isIdentical(compileAndRun<double>(proc), a * b));
 }
 
+void testMulArgFloat(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Mul, Origin(), floatValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a * a)));
+}
+
+void testMulArgsFloat(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);
+    Value* result = root->appendNew<Value>(proc, Mul, Origin(), floatValue1, floatValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a * b)));
+}
+
+void testMulArgImmFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Mul, Origin(), floatValue, constValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a * b)));
+}
+
+void testMulImmArgFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Mul, Origin(), constValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a * b)));
+}
+
+void testMulImmsFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Mul, Origin(), constValue1, constValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a * b)));
+}
+
+void testMulArgFloatWithUselessDoubleConversion(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argumentInt32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentInt32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Mul, Origin(), asDouble, asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a * a)));
+}
+
+void testMulArgsFloatWithUselessDoubleConversion(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);
+    Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+    Value* result = root->appendNew<Value>(proc, Mul, Origin(), asDouble1, asDouble2);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a * b)));
+}
+
+void testMulArgsFloatWithEffectfulDoubleConversion(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);
+    Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+    Value* result = root->appendNew<Value>(proc, Mul, Origin(), asDouble1, asDouble2);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* doubleMulress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleMulress);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    double effect = 0;
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), &effect), bitwise_cast<int32_t>(a * b)));
+    CHECK(isIdentical(effect, static_cast<double>(a) * static_cast<double>(b)));
+}
+
 void testDivArgDouble(double a)
 {
     Procedure proc;
@@ -560,644 +1034,760 @@ void testDivImmsDouble(double a, double b)
     CHECK(isIdentical(compileAndRun<double>(proc), a / b));
 }
 
-void testSubArg(int a)
+void testDivArgFloat(float a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), value, value));
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Div, Origin(), floatValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(!compileAndRun<int>(proc, a));
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a / a)));
 }
 
-void testSubArgs(int a, int b)
+void testDivArgsFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+    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* result = root->appendNew<Value>(proc, Div, Origin(), floatValue1, floatValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, a, b) == a - b);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a / b)));
 }
 
-void testSubArgImm(int64_t a, int64_t b)
+void testDivArgImmFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Div, Origin(), floatValue, constValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int64_t>(proc, a) == a - b);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a / b)));
 }
 
-void testSubImmArg(int a, int b)
+void testDivImmArgFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Div, Origin(), constValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, b) == a - b);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a / b)));
 }
 
-void testSubArgs32(int a, int b)
+void testDivImmsFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, 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))));
+    Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Div, Origin(), constValue1, constValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, a, b) == a - b);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a / b)));
 }
 
-void testSubArgImm32(int a, int b)
+void testModArgDouble(double a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+        root->appendNew<Value>(proc, Mod, Origin(), value, value));
 
-    CHECK(compileAndRun<int>(proc, a) == a - b);
+    CHECK(isIdentical(compileAndRun<double>(proc, a), fmod(a, a)));
 }
 
-void testSubImmArg32(int a, int b)
+void testModArgsDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
+        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
 
-    CHECK(compileAndRun<int>(proc, b) == a - b);
+    CHECK(isIdentical(compileAndRun<double>(proc, a, b), fmod(a, b)));
 }
 
-void testSubArgDouble(double a)
+void testModArgImmDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), value, value));
+        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
 
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a - a));
+    CHECK(isIdentical(compileAndRun<double>(proc, a), fmod(a, b)));
 }
 
-void testSubArgsDouble(double a, double b)
+void testModImmArgDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
+        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
 
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), a - b));
+    CHECK(isIdentical(compileAndRun<double>(proc, b), fmod(a, b)));
 }
 
-void testSubArgImmDouble(double a, double b)
+void testModImmsDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
     Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
+        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
 
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a - b));
+    CHECK(isIdentical(compileAndRun<double>(proc), fmod(a, b)));
 }
 
-void testSubImmArgDouble(double a, double b)
+void testModArgFloat(float a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), floatValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(isIdentical(compileAndRun<double>(proc, b), a - b));
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, a)))));
 }
 
-void testSubImmsDouble(double a, double b)
+void testModArgsFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
-    
-    CHECK(isIdentical(compileAndRun<double>(proc), a - b));
+    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* result = root->appendNew<Value>(proc, Mod, Origin(), floatValue1, floatValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
 }
 
-void testBitAndArgs(int64_t a, int64_t b)
+void testModArgImmFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), floatValue, constValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int64_t>(proc, a, b) == (a & b));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
 }
 
-void testBitAndSameArg(int64_t a)
+void testModImmArgFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), constValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
+}
+
+void testModImmsFloat(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Mod, Origin(), constValue1, constValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
+}
+
+void testDivArgFloatWithUselessDoubleConversion(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argumentInt32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentInt32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Div, Origin(), asDouble, asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a / a)));
+}
+
+void testDivArgsFloatWithUselessDoubleConversion(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);
+    Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+    Value* result = root->appendNew<Value>(proc, Div, Origin(), asDouble1, asDouble2);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a / b)));
+}
+
+void testDivArgsFloatWithEffectfulDoubleConversion(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);
+    Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+    Value* result = root->appendNew<Value>(proc, Div, Origin(), asDouble1, asDouble2);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* doubleDivress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleDivress);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    double effect = 0;
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), &effect), bitwise_cast<int32_t>(a / b)));
+    CHECK(isIdentical(effect, static_cast<double>(a) / static_cast<double>(b)));
+}
+
+void testSubArg(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            argument,
-            argument));
+        root->appendNew<Value>(proc, Sub, Origin(), value, value));
 
-    CHECK(compileAndRun<int64_t>(proc, a) == a);
+    CHECK(!compileAndRun<int>(proc, a));
 }
 
-void testBitAndImms(int64_t a, int64_t b)
+void testSubArgs(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
+            proc, Sub, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    CHECK(compileAndRun<int64_t>(proc) == (a & b));
+    CHECK(compileAndRun<int>(proc, a, b) == a - b);
 }
 
-void testBitAndArgImm(int64_t a, int64_t b)
+void testSubArgImm(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitAnd, Origin(),
+            proc, Sub, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
             root->appendNew<Const64Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int64_t>(proc, a) == (a & b));
+    CHECK(compileAndRun<int64_t>(proc, a) == a - b);
 }
 
-void testBitAndImmArg(int64_t a, int64_t b)
+void testNegValueSubOne(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* negArgument = root->appendNew<Value>(proc, Sub, Origin(),
+        root->appendNew<Const64Value>(proc, Origin(), 0),
+        argument);
+    Value* negArgumentMinusOne = root->appendNew<Value>(proc, Sub, Origin(),
+        negArgument,
+        root->appendNew<Const64Value>(proc, Origin(), 1));
+    root->appendNew<ControlValue>(proc, Return, Origin(), negArgumentMinusOne);
+    CHECK(compileAndRun<int>(proc, a) == -a - 1);
+}
+
+void testSubImmArg(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitAnd, Origin(),
+            proc, Sub, Origin(),
             root->appendNew<Const64Value>(proc, Origin(), a),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
 
-    CHECK(compileAndRun<int64_t>(proc, b) == (a & b));
+    CHECK(compileAndRun<int>(proc, b) == a - b);
 }
 
-void testBitAndBitAndArgImmImm(int64_t a, int64_t b, int64_t c)
+void testSubArgMem(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitAnd = root->appendNew<Value>(
-        proc, BitAnd, Origin(),
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        root->appendNew<Const64Value>(proc, Origin(), b));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            innerBitAnd,
-            root->appendNew<Const64Value>(proc, Origin(), c)));
+        load);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int64_t>(proc, a) == ((a & b) & c));
+    CHECK(compileAndRun<int64_t>(proc, a, &b) == a - b);
 }
 
-void testBitAndImmBitAndArgImm(int64_t a, int64_t b, int64_t c)
+void testSubMemArg(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitAnd = root->appendNew<Value>(
-        proc, BitAnd, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        root->appendNew<Const64Value>(proc, Origin(), c));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            innerBitAnd));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        load,
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int64_t>(proc, b) == (a & (b & c)));
+    int64_t inputOutput = a;
+    CHECK(!compileAndRun<int64_t>(proc, &inputOutput, b));
+    CHECK(inputOutput == a - b);
 }
 
-void testBitAndArgs32(int a, int b)
+void testSubImmMem(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, 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))));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        root->appendNew<Const64Value>(proc, Origin(), a),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, a, b) == (a & b));
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a - b);
 }
 
-void testBitAndSameArg32(int a)
+void testSubMemImm(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            argument,
-            argument));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        load,
+        root->appendNew<Const64Value>(proc, Origin(), b));
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, a) == a);
+    int64_t inputOutput = a;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a - b);
 }
 
-void testBitAndImms32(int a, int b)
+
+void testSubArgs32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+            proc, Sub, 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) == (a & b));
+    CHECK(compileAndRun<int>(proc, a, b) == a - b);
 }
 
-void testBitAndArgImm32(int a, int b)
+void testSubArgImm32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitAnd, Origin(),
+            proc, Sub, Origin(),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
             root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int>(proc, a) == (a & b));
+    CHECK(compileAndRun<int>(proc, a) == a - b);
 }
 
-void testBitAndImmArg32(int a, int b)
+void testSubImmArg32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitAnd, Origin(),
+            proc, Sub, Origin(),
             root->appendNew<Const32Value>(proc, Origin(), a),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    CHECK(compileAndRun<int>(proc, b) == (a & b));
+    CHECK(compileAndRun<int>(proc, b) == a - b);
 }
 
-void testBitAndBitAndArgImmImm32(int a, int b, int c)
+void testSubMemArg32(int32_t a, int32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitAnd = root->appendNew<Value>(
-        proc, BitAnd, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        root->appendNew<Const32Value>(proc, Origin(), b));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            innerBitAnd,
-            root->appendNew<Const32Value>(proc, Origin(), c)));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), load, argument);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, a) == ((a & b) & c));
+    int32_t inputOutput = a;
+    CHECK(!compileAndRun<int32_t>(proc, &inputOutput, b));
+    CHECK(inputOutput == a - b);
 }
 
-void testBitAndImmBitAndArgImm32(int a, int b, int c)
+void testSubArgMem32(int32_t a, int32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitAnd = root->appendNew<Value>(
-        proc, BitAnd, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        root->appendNew<Const32Value>(proc, Origin(), c));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            innerBitAnd));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), argument, load);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int>(proc, b) == (a & (b & c)));
+    CHECK(compileAndRun<int32_t>(proc, a, &b) == a - b);
 }
 
-void testBitOrArgs(int64_t a, int64_t b)
+void testSubImmMem32(int32_t a, int32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), a),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int64_t>(proc, a, b) == (a | b));
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a - b);
 }
 
-void testBitOrSameArg(int64_t a)
+void testSubMemImm32(int32_t a, int32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            argument,
-            argument));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        load,
+        root->appendNew<Const32Value>(proc, Origin(), b));
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int64_t>(proc, a) == a);
+    int32_t inputOutput = a;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a - b);
 }
 
-void testBitOrImms(int64_t a, int64_t b)
+void testNegValueSubOne32(int a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc) == (a | b));
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* negArgument = root->appendNew<Value>(proc, Sub, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0),
+        argument);
+    Value* negArgumentMinusOne = root->appendNew<Value>(proc, Sub, Origin(),
+        negArgument,
+        root->appendNew<Const32Value>(proc, Origin(), 1));
+    root->appendNew<ControlValue>(proc, Return, Origin(), negArgumentMinusOne);
+    CHECK(compileAndRun<int>(proc, a) == -a - 1);
 }
 
-void testBitOrArgImm(int64_t a, int64_t b)
+void testSubArgDouble(double a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
+        root->appendNew<Value>(proc, Sub, Origin(), value, value));
 
-    CHECK(compileAndRun<int64_t>(proc, a) == (a | b));
+    CHECK(isIdentical(compileAndRun<double>(proc, a), a - a));
 }
 
-void testBitOrImmArg(int64_t a, int64_t b)
+void testSubArgsDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
 
-    CHECK(compileAndRun<int64_t>(proc, b) == (a | b));
+    CHECK(isIdentical(compileAndRun<double>(proc, a, b), a - b));
 }
 
-void testBitOrBitOrArgImmImm(int64_t a, int64_t b, int64_t c)
+void testSubArgImmDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitOr = root->appendNew<Value>(
-        proc, BitOr, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        root->appendNew<Const64Value>(proc, Origin(), b));
+    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            innerBitOr,
-            root->appendNew<Const64Value>(proc, Origin(), c)));
+        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
 
-    CHECK(compileAndRun<int64_t>(proc, a) == ((a | b) | c));
+    CHECK(isIdentical(compileAndRun<double>(proc, a), a - b));
 }
 
-void testBitOrImmBitOrArgImm(int64_t a, int64_t b, int64_t c)
+void testSubImmArgDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitOr = root->appendNew<Value>(
-        proc, BitOr, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        root->appendNew<Const64Value>(proc, Origin(), c));
+    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            innerBitOr));
+        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
 
-    CHECK(compileAndRun<int64_t>(proc, b) == (a | (b | c)));
+    CHECK(isIdentical(compileAndRun<double>(proc, b), a - b));
 }
 
-void testBitOrArgs32(int a, int b)
+void testSubImmsDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, 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, Sub, Origin(), valueA, valueB));
+    
+    CHECK(isIdentical(compileAndRun<double>(proc), a - b));
+}
 
-    CHECK(compileAndRun<int>(proc, a, b) == (a | b));
+void testSubArgFloat(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), floatValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a - a)));
 }
 
-void testBitOrSameArg32(int a)
+void testSubArgsFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            argument,
-            argument));
+    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* result = root->appendNew<Value>(proc, Sub, Origin(), floatValue1, floatValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, a) == a);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a - b)));
 }
 
-void testBitOrImms32(int a, int b)
+void testSubArgImmFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), floatValue, constValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc) == (a | b));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a - b)));
 }
 
-void testBitOrArgImm32(int a, int b)
+void testSubImmArgFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), constValue, floatValue);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, a) == (a | b));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a - b)));
 }
 
-void testBitOrImmArg32(int a, int b)
+void testSubImmsFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
+    Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), constValue1, constValue2);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, b) == (a | b));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a - b)));
 }
 
-void testBitOrBitOrArgImmImm32(int a, int b, int c)
+void testSubArgFloatWithUselessDoubleConversion(float a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitOr = root->appendNew<Value>(
-        proc, BitOr, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        root->appendNew<Const32Value>(proc, Origin(), b));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            innerBitOr,
-            root->appendNew<Const32Value>(proc, Origin(), c)));
+    Value* argumentInt32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentInt32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), asDouble, asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, a) == ((a | b) | c));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a - a)));
 }
 
-void testBitOrImmBitOrArgImm32(int a, int b, int c)
+void testSubArgsFloatWithUselessDoubleConversion(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitOr = root->appendNew<Value>(
-        proc, BitOr, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        root->appendNew<Const32Value>(proc, Origin(), c));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            innerBitOr));
+    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* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), asDouble1, asDouble2);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, b) == (a | (b | c)));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a - b)));
 }
 
-void testBitXorArgs(int64_t a, int64_t b)
+void testSubArgsFloatWithEffectfulDoubleConversion(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);
+    Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1);
+    Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), asDouble1, asDouble2);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* doubleSubress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleSubress);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+    double effect = 0;
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), &effect), bitwise_cast<int32_t>(a - b)));
+    CHECK(isIdentical(effect, static_cast<double>(a) - static_cast<double>(b)));
+}
+
+void testBitAndArgs(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    CHECK(compileAndRun<int64_t>(proc, a, b) == (a ^ b));
+    CHECK(compileAndRun<int64_t>(proc, a, b) == (a & b));
 }
 
-void testBitXorSameArg(int64_t a)
+void testBitAndSameArg(int64_t a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
@@ -1205,99 +1795,99 @@ void testBitXorSameArg(int64_t a)
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             argument,
             argument));
 
-    CHECK(!compileAndRun<int64_t>(proc, a));
+    CHECK(compileAndRun<int64_t>(proc, a) == a);
 }
 
-void testBitXorImms(int64_t a, int64_t b)
+void testBitAndImms(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Const64Value>(proc, Origin(), a),
             root->appendNew<Const64Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int64_t>(proc) == (a ^ b));
+    CHECK(compileAndRun<int64_t>(proc) == (a & b));
 }
 
-void testBitXorArgImm(int64_t a, int64_t b)
+void testBitAndArgImm(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
             root->appendNew<Const64Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int64_t>(proc, a) == (a ^ b));
+    CHECK(compileAndRun<int64_t>(proc, a) == (a & b));
 }
 
-void testBitXorImmArg(int64_t a, int64_t b)
+void testBitAndImmArg(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Const64Value>(proc, Origin(), a),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
 
-    CHECK(compileAndRun<int64_t>(proc, b) == (a ^ b));
+    CHECK(compileAndRun<int64_t>(proc, b) == (a & b));
 }
 
-void testBitXorBitXorArgImmImm(int64_t a, int64_t b, int64_t c)
+void testBitAndBitAndArgImmImm(int64_t a, int64_t b, int64_t c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitXor = root->appendNew<Value>(
-        proc, BitXor, Origin(),
+    Value* innerBitAnd = root->appendNew<Value>(
+        proc, BitAnd, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
         root->appendNew<Const64Value>(proc, Origin(), b));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            innerBitXor,
+            proc, BitAnd, Origin(),
+            innerBitAnd,
             root->appendNew<Const64Value>(proc, Origin(), c)));
 
-    CHECK(compileAndRun<int64_t>(proc, a) == ((a ^ b) ^ c));
+    CHECK(compileAndRun<int64_t>(proc, a) == ((a & b) & c));
 }
 
-void testBitXorImmBitXorArgImm(int64_t a, int64_t b, int64_t c)
+void testBitAndImmBitAndArgImm(int64_t a, int64_t b, int64_t c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitXor = root->appendNew<Value>(
-        proc, BitXor, Origin(),
+    Value* innerBitAnd = root->appendNew<Value>(
+        proc, BitAnd, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
         root->appendNew<Const64Value>(proc, Origin(), c));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Const64Value>(proc, Origin(), a),
-            innerBitXor));
+            innerBitAnd));
 
-    CHECK(compileAndRun<int64_t>(proc, b) == (a ^ (b ^ c)));
+    CHECK(compileAndRun<int64_t>(proc, b) == (a & (b & c)));
 }
 
-void testBitXorArgs32(int a, int b)
+void testBitAndArgs32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
@@ -1305,78 +1895,77 @@ void testBitXorArgs32(int a, int b)
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
 
-    CHECK(compileAndRun<int>(proc, a, b) == (a ^ b));
+    CHECK(compileAndRun<int>(proc, a, b) == (a & b));
 }
 
-void testBitXorSameArg32(int a)
+void testBitAndSameArg32(int a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* argument = 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));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             argument,
             argument));
 
-    CHECK(!compileAndRun<int>(proc, a));
+    CHECK(compileAndRun<int>(proc, a) == a);
 }
 
-void testBitXorImms32(int a, int b)
+void testBitAndImms32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Const32Value>(proc, Origin(), a),
             root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int>(proc) == (a ^ b));
+    CHECK(compileAndRun<int>(proc) == (a & b));
 }
 
-void testBitXorArgImm32(int a, int b)
+void testBitAndArgImm32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
             root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int>(proc, a) == (a ^ b));
+    CHECK(compileAndRun<int>(proc, a) == (a & b));
 }
 
-void testBitXorImmArg32(int a, int b)
+void testBitAndImmArg32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Const32Value>(proc, Origin(), a),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    CHECK(compileAndRun<int>(proc, b) == (a ^ b));
+    CHECK(compileAndRun<int>(proc, b) == (a & b));
 }
 
-void testBitXorBitXorArgImmImm32(int a, int b, int c)
+void testBitAndBitAndArgImmImm32(int a, int b, int c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitXor = root->appendNew<Value>(
-        proc, BitXor, Origin(),
+    Value* innerBitAnd = root->appendNew<Value>(
+        proc, BitAnd, Origin(),
         root->appendNew<Value>(
             proc, Trunc, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
@@ -1384,19 +1973,19 @@ void testBitXorBitXorArgImmImm32(int a, int b, int c)
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            innerBitXor,
+            proc, BitAnd, Origin(),
+            innerBitAnd,
             root->appendNew<Const32Value>(proc, Origin(), c)));
 
-    CHECK(compileAndRun<int>(proc, a) == ((a ^ b) ^ c));
+    CHECK(compileAndRun<int>(proc, a) == ((a & b) & c));
 }
 
-void testBitXorImmBitXorArgImm32(int a, int b, int c)
+void testBitAndImmBitAndArgImm32(int a, int b, int c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* innerBitXor = root->appendNew<Value>(
-        proc, BitXor, Origin(),
+    Value* innerBitAnd = root->appendNew<Value>(
+        proc, BitAnd, Origin(),
         root->appendNew<Value>(
             proc, Trunc, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
@@ -1404,291 +1993,285 @@ void testBitXorImmBitXorArgImm32(int a, int b, int c)
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, BitXor, Origin(),
+            proc, BitAnd, Origin(),
             root->appendNew<Const32Value>(proc, Origin(), a),
-            innerBitXor));
+            innerBitAnd));
 
-    CHECK(compileAndRun<int>(proc, b) == (a ^ (b ^ c)));
+    CHECK(compileAndRun<int>(proc, b) == (a & (b & c)));
 }
 
-void testShlArgs(int64_t a, int64_t b)
+void testBitAndWithMaskReturnsBooleans(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+    Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* equal = root->appendNew<Value>(proc, Equal, Origin(), arg0, arg1);
+    Value* maskedEqual = root->appendNew<Value>(proc, BitAnd, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0x5),
+        equal);
+    Value* inverted = root->appendNew<Value>(proc, BitXor, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0x1),
+        maskedEqual);
+    Value* select = root->appendNew<Value>(proc, Select, Origin(), inverted,
+        root->appendNew<Const64Value>(proc, Origin(), 42),
+        root->appendNew<Const64Value>(proc, Origin(), -5));
 
-    CHECK(compileAndRun<int64_t>(proc, a, b) == (a << b));
+    root->appendNew<ControlValue>(proc, Return, Origin(), select);
+
+    int64_t expected = (a == b) ? -5 : 42;
+    CHECK(compileAndRun<int64_t>(proc, a, b) == expected);
 }
 
-void testShlImms(int64_t a, int64_t b)
+double bitAndDouble(double a, double b)
 {
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc) == (a << b));
+    return bitwise_cast<double>(bitwise_cast<uint64_t>(a) & bitwise_cast<uint64_t>(b));
 }
 
-void testShlArgImm(int64_t a, int64_t b)
+void testBitAndArgDouble(double a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int64_t>(proc, a) == (a << b));
+    CHECK(isIdentical(compileAndRun<double>(proc, a), bitAndDouble(a, a)));
 }
 
-void testShlArg32(int32_t a)
+void testBitAndArgsDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Shl, Origin(), value, value));
+    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int32_t>(proc, a) == (a << a));
+    CHECK(isIdentical(compileAndRun<double>(proc, a, b), bitAndDouble(a, b)));
 }
 
-void testShlArgs32(int32_t a, int32_t b)
+void testBitAndArgImmDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, 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))));
+    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int32_t>(proc, a, b) == (a << b));
+    CHECK(isIdentical(compileAndRun<double>(proc, a, b), bitAndDouble(a, b)));
 }
 
-void testShlImms32(int32_t a, int32_t b)
+void testBitAndImmsDouble(double a, double b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+    Value* argumentA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int32_t>(proc) == (a << b));
+    CHECK(isIdentical(compileAndRun<double>(proc), bitAndDouble(a, b)));
 }
 
-void testShlArgImm32(int32_t a, int32_t b)
+float bitAndFloat(float a, float b)
+{
+    return bitwise_cast<float>(bitwise_cast<uint32_t>(a) & bitwise_cast<uint32_t>(b));
+}
+
+void testBitAndArgFloat(float a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+        root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argument, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int32_t>(proc, a) == (a << b));
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), bitAndFloat(a, a)));
 }
 
-void testSShrArgs(int64_t a, int64_t b)
+void testBitAndArgsFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, SShr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+    Value* argumentA = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+        root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+    Value* argumentB = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+        root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int64_t>(proc, a, b) == (a >> b));
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitAndFloat(a, b)));
 }
 
-void testSShrImms(int64_t a, int64_t b)
+void testBitAndArgImmFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, SShr, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+    Value* argumentA = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+        root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+    Value* argumentB = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int64_t>(proc) == (a >> b));
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitAndFloat(a, b)));
 }
 
-void testSShrArgImm(int64_t a, int64_t b)
+void testBitAndImmsFloat(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, SShr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+    Value* argumentA = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* argumentB = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
 
-    CHECK(compileAndRun<int64_t>(proc, a) == (a >> b));
+    CHECK(isIdentical(compileAndRun<float>(proc), bitAndFloat(a, b)));
 }
 
-void testSShrArg32(int32_t a)
+void testBitAndArgsFloatWithUselessDoubleConversion(float a, float b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, SShr, Origin(), value, value));
+    Value* argumentA = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+        root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+    Value* argumentB = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+        root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+    Value* argumentAasDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argumentA);
+    Value* argumentBasDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argumentB);
+    Value* doubleResult = root->appendNew<Value>(proc, BitAnd, Origin(), argumentAasDouble, argumentBasDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), doubleResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), floatResult);
 
-    CHECK(compileAndRun<int32_t>(proc, a) == (a >> (a & 31)));
+    double doubleA = a;
+    double doubleB = b;
+    float expected = static_cast<float>(bitAndDouble(doubleA, doubleB));
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), expected));
 }
 
-void testSShrArgs32(int32_t a, int32_t b)
+void testBitOrArgs(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SShr, 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, BitOr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    CHECK(compileAndRun<int32_t>(proc, a, b) == (a >> b));
+    CHECK(compileAndRun<int64_t>(proc, a, b) == (a | b));
 }
 
-void testSShrImms32(int32_t a, int32_t b)
+void testBitOrSameArg(int64_t a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SShr, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+            proc, BitOr, Origin(),
+            argument,
+            argument));
 
-    CHECK(compileAndRun<int32_t>(proc) == (a >> b));
+    CHECK(compileAndRun<int64_t>(proc, a) == a);
 }
 
-void testSShrArgImm32(int32_t a, int32_t b)
+void testBitOrImms(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, SShr, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+            proc, BitOr, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<Const64Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int32_t>(proc, a) == (a >> b));
+    CHECK(compileAndRun<int64_t>(proc) == (a | b));
 }
 
-void testZShrArgs(uint64_t a, uint64_t b)
+void testBitOrArgImm(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, ZShr, Origin(),
+            proc, BitOr, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+            root->appendNew<Const64Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<uint64_t>(proc, a, b) == (a >> b));
+    CHECK(compileAndRun<int64_t>(proc, a) == (a | b));
 }
 
-void testZShrImms(uint64_t a, uint64_t b)
+void testBitOrImmArg(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, ZShr, Origin(),
+            proc, BitOr, Origin(),
             root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
 
-    CHECK(compileAndRun<uint64_t>(proc) == (a >> b));
+    CHECK(compileAndRun<int64_t>(proc, b) == (a | b));
 }
 
-void testZShrArgImm(uint64_t a, uint64_t b)
+void testBitOrBitOrArgImmImm(int64_t a, int64_t b, int64_t c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* innerBitOr = root->appendNew<Value>(
+        proc, BitOr, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        root->appendNew<Const64Value>(proc, Origin(), b));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, ZShr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
+            proc, BitOr, Origin(),
+            innerBitOr,
+            root->appendNew<Const64Value>(proc, Origin(), c)));
 
-    CHECK(compileAndRun<uint64_t>(proc, a) == (a >> b));
+    CHECK(compileAndRun<int64_t>(proc, a) == ((a | b) | c));
 }
 
-void testZShrArg32(uint32_t a)
+void testBitOrImmBitOrArgImm(int64_t a, int64_t b, int64_t c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* innerBitOr = root->appendNew<Value>(
+        proc, BitOr, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        root->appendNew<Const64Value>(proc, Origin(), c));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, ZShr, Origin(), value, value));
+        root->appendNew<Value>(
+            proc, BitOr, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            innerBitOr));
 
-    CHECK(compileAndRun<uint32_t>(proc, a) == (a >> (a & 31)));
+    CHECK(compileAndRun<int64_t>(proc, b) == (a | (b | c)));
 }
 
-void testZShrArgs32(uint32_t a, uint32_t b)
+void testBitOrArgs32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, ZShr, Origin(),
+            proc, BitOr, Origin(),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
@@ -1696,2352 +2279,5779 @@ void testZShrArgs32(uint32_t a, uint32_t b)
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
 
-    CHECK(compileAndRun<uint32_t>(proc, a, b) == (a >> b));
+    CHECK(compileAndRun<int>(proc, a, b) == (a | b));
 }
 
-void testZShrImms32(uint32_t a, uint32_t b)
+void testBitOrSameArg32(int a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
+    Value* argument = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, ZShr, Origin(),
+            proc, BitOr, Origin(),
+            argument,
+            argument));
+
+    CHECK(compileAndRun<int>(proc, a) == a);
+}
+
+void testBitOrImms32(int a, int b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitOr, Origin(),
             root->appendNew<Const32Value>(proc, Origin(), a),
             root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<uint32_t>(proc) == (a >> b));
+    CHECK(compileAndRun<int>(proc) == (a | b));
 }
 
-void testZShrArgImm32(uint32_t a, uint32_t b)
+void testBitOrArgImm32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, ZShr, Origin(),
+            proc, BitOr, Origin(),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
             root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<uint32_t>(proc, a) == (a >> b));
+    CHECK(compileAndRun<int>(proc, a) == (a | b));
 }
 
-void testStore(int value)
+void testBitOrImmArg32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int slot = 0xbaadbeef;
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitOr, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
+
+    CHECK(compileAndRun<int>(proc, b) == (a | b));
+}
+
+void testBitOrBitOrArgImmImm32(int a, int b, int c)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* innerBitOr = root->appendNew<Value>(
+        proc, BitOr, Origin(),
         root->appendNew<Value>(
             proc, Trunc, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+        root->appendNew<Const32Value>(proc, Origin(), b));
     root->appendNew<ControlValue>(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitOr, Origin(),
+            innerBitOr,
+            root->appendNew<Const32Value>(proc, Origin(), c)));
 
-    CHECK(!compileAndRun<int>(proc, value));
-    CHECK(slot == value);
+    CHECK(compileAndRun<int>(proc, a) == ((a | b) | c));
 }
 
-void testStoreConstant(int value)
+void testBitOrImmBitOrArgImm32(int a, int b, int c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int slot = 0xbaadbeef;
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), value),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+    Value* innerBitOr = root->appendNew<Value>(
+        proc, BitOr, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        root->appendNew<Const32Value>(proc, Origin(), c));
     root->appendNew<ControlValue>(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitOr, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            innerBitOr));
 
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == value);
+    CHECK(compileAndRun<int>(proc, b) == (a | (b | c)));
 }
 
-void testStoreConstantPtr(intptr_t value)
+void testBitXorArgs(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    intptr_t slot;
-    if (is64Bit())
-        slot = (static_cast<intptr_t>(0xbaadbeef) << 32) + static_cast<intptr_t>(0xbaadbeef);
-    else
-        slot = 0xbaadbeef;
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
-        root->appendNew<ConstPtrValue>(proc, Origin(), value),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     root->appendNew<ControlValue>(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitXor, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
 
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == value);
+    CHECK(compileAndRun<int64_t>(proc, a, b) == (a ^ b));
 }
 
-void testTrunc(int64_t value)
+void testBitXorSameArg(int64_t a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+            proc, BitXor, Origin(),
+            argument,
+            argument));
 
-    CHECK(compileAndRun<int>(proc, value) == static_cast<int>(value));
+    CHECK(!compileAndRun<int64_t>(proc, a));
 }
 
-void testAdd1(int value)
+void testBitXorImms(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), 1)));
+            proc, BitXor, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<Const64Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int>(proc, value) == value + 1);
+    CHECK(compileAndRun<int64_t>(proc) == (a ^ b));
 }
 
-void testAdd1Ptr(intptr_t value)
+void testBitXorArgImm(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Add, Origin(),
+            proc, BitXor, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ConstPtrValue>(proc, Origin(), 1)));
+            root->appendNew<Const64Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<intptr_t>(proc, value) == value + 1);
+    CHECK(compileAndRun<int64_t>(proc, a) == (a ^ b));
 }
 
-void testNeg32(int32_t value)
+void testBitXorImmArg(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), 0),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
+            proc, BitXor, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
 
-    CHECK(compileAndRun<int32_t>(proc, value) == -value);
+    CHECK(compileAndRun<int64_t>(proc, b) == (a ^ b));
 }
 
-void testNegPtr(intptr_t value)
+void testBitXorBitXorArgImmImm(int64_t a, int64_t b, int64_t c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* innerBitXor = root->appendNew<Value>(
+        proc, BitXor, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        root->appendNew<Const64Value>(proc, Origin(), b));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), 0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+            proc, BitXor, Origin(),
+            innerBitXor,
+            root->appendNew<Const64Value>(proc, Origin(), c)));
 
-    CHECK(compileAndRun<intptr_t>(proc, value) == -value);
+    CHECK(compileAndRun<int64_t>(proc, a) == ((a ^ b) ^ c));
 }
 
-void testStoreAddLoad(int amount)
+void testBitXorImmBitXorArgImm(int64_t a, int64_t b, int64_t c)
 {
     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, Add, Origin(),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
-            root->appendNew<Const32Value>(proc, Origin(), amount)),
-        slotPtr);
+    Value* innerBitXor = root->appendNew<Value>(
+        proc, BitXor, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        root->appendNew<Const64Value>(proc, Origin(), c));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(
+            proc, BitXor, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            innerBitXor));
 
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == 37 + amount);
+    CHECK(compileAndRun<int64_t>(proc, b) == (a ^ (b ^ c)));
 }
 
-void testStoreSubLoad(int amount)
+void testBitXorArgs32(int a, int b)
 {
     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<ControlValue>(
+        proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
+            proc, BitXor, Origin(),
             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));
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
 
-    CHECK(!compileAndRun<int>(proc, amount));
-    CHECK(slot == startValue - amount);
+    CHECK(compileAndRun<int>(proc, a, b) == (a ^ b));
 }
 
-void testStoreAddLoadInterference(int amount)
+void testBitXorSameArg32(int a)
 {
     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);
+    Value* argument = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(
+            proc, BitXor, Origin(),
+            argument,
+            argument));
 
-    CHECK(!compileAndRun<int>(proc, &slot));
-    CHECK(slot == 37 + amount);
+    CHECK(!compileAndRun<int>(proc, a));
 }
 
-void testStoreAddAndLoad(int amount, int mask)
+void testBitXorImms32(int a, int b)
 {
     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, 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<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(
+            proc, BitXor, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == ((37 + amount) & mask));
+    CHECK(compileAndRun<int>(proc) == (a ^ b));
 }
 
-void testStoreNegLoad32(int32_t value)
+void testBitXorArgImm32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-
-    int32_t slot = value;
-
-    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
-    
-    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);
-    
     root->appendNew<ControlValue>(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitXor, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    CHECK(!compileAndRun<int32_t>(proc));
-    CHECK(slot == -value);
+    CHECK(compileAndRun<int>(proc, a) == (a ^ b));
 }
 
-void testStoreNegLoadPtr(intptr_t value)
+void testBitXorImmArg32(int a, int b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-
-    intptr_t slot = value;
-
-    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));
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitXor, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    CHECK(!compileAndRun<int32_t>(proc));
-    CHECK(slot == -value);
+    CHECK(compileAndRun<int>(proc, b) == (a ^ b));
 }
 
-void testAdd1Uncommuted(int value)
+void testBitXorBitXorArgImmImm32(int a, int b, int c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    Value* innerBitXor = root->appendNew<Value>(
+        proc, BitXor, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        root->appendNew<Const32Value>(proc, Origin(), b));
     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))));
+            proc, BitXor, Origin(),
+            innerBitXor,
+            root->appendNew<Const32Value>(proc, Origin(), c)));
 
-    CHECK(compileAndRun<int>(proc, value) == value + 1);
+    CHECK(compileAndRun<int>(proc, a) == ((a ^ b) ^ c));
 }
 
-void testLoadOffset()
+void testBitXorImmBitXorArgImm32(int a, int b, int c)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    int array[] = { 1, 2 };
-    ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array);
+    Value* innerBitXor = root->appendNew<Value>(
+        proc, BitXor, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        root->appendNew<Const32Value>(proc, Origin(), c));
     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))));
+            proc, BitXor, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            innerBitXor));
 
-    CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
+    CHECK(compileAndRun<int>(proc, b) == (a ^ (b ^ c)));
 }
 
-void testLoadOffsetNotConstant()
+void testBitNotArg(int64_t a)
 {
     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))));
+            proc, BitXor, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), -1),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
 
-    CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
+    CHECK(isIdentical(compileAndRun<int64_t>(proc, a), static_cast<int64_t>((static_cast<uint64_t>(a) ^ 0xffffffffffffffff))));
 }
 
-void testLoadOffsetUsingAdd()
+void testBitNotImm(int64_t a)
 {
     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]);
+            proc, BitXor, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), -1),
+            root->appendNew<Const64Value>(proc, Origin(), a)));
+
+    CHECK(isIdentical(compileAndRun<int64_t>(proc, a), static_cast<int64_t>((static_cast<uint64_t>(a) ^ 0xffffffffffffffff))));
 }
 
-void testLoadOffsetUsingAddInterference()
+void testBitNotMem(int64_t a)
 {
     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));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* notLoad = root->appendNew<Value>(proc, BitXor, Origin(),
+        root->appendNew<Const64Value>(proc, Origin(), -1),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), notLoad, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int64_t input = a;
+    compileAndRun<int32_t>(proc, &input);
+    CHECK(isIdentical(input, static_cast<int64_t>((static_cast<uint64_t>(a) ^ 0xffffffffffffffff))));
+}
+
+void testBitNotArg32(int32_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     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<Value>(proc, BitXor, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), -1),
+            argument));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, a), static_cast<int32_t>((static_cast<uint32_t>(a) ^ 0xffffffff))));
 }
 
-void testLoadOffsetUsingAddNotConstant()
+void testBitNotImm32(int32_t a)
 {
     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]);
+            proc, BitXor, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), -1),
+            root->appendNew<Const32Value>(proc, Origin(), a)));
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, a), static_cast<int32_t>((static_cast<uint32_t>(a) ^ 0xffffffff))));
 }
 
-void testLoadAddrShift(unsigned shift)
+void testBitNotMem32(int32_t a)
 {
     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))));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* notLoad = root->appendNew<Value>(proc, BitXor, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), -1),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), notLoad, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    CHECK(compileAndRun<int>(proc, arg) == 8675309);
+    int32_t input = a;
+    compileAndRun<int32_t>(proc, &input);
+    CHECK(isIdentical(input, static_cast<int32_t>((static_cast<uint32_t>(a) ^ 0xffffffff))));
 }
 
-void testFramePointer()
+void testBitNotOnBooleanAndBranch32(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = 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));
+    Value* argsAreEqual = root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2);
+    Value* argsAreNotEqual = root->appendNew<Value>(proc, BitXor, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), -1),
+        argsAreEqual);
+
     root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        argsAreNotEqual,
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, FramePointer, Origin()));
+        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
 
-    void* fp = compileAndRun<void*>(proc);
-    CHECK(fp < &proc);
-    CHECK(fp >= bitwise_cast<char*>(&proc) - 10000);
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), -42));
+
+    int32_t expectedValue = (a != b) ? 42 : -42;
+    CHECK(compileAndRun<int32_t>(proc, a, b) == expectedValue);
 }
 
-void testStackSlot()
+void testShlArgs(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<StackSlotValue>(proc, Origin(), 1, StackSlotKind::Anonymous));
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
 
-    void* stackSlot = compileAndRun<void*>(proc);
-    CHECK(stackSlot < &proc);
-    CHECK(stackSlot >= bitwise_cast<char*>(&proc) - 10000);
+    CHECK(compileAndRun<int64_t>(proc, a, b) == (a << b));
 }
 
-void testLoadFromFramePointer()
+void testShlImms(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load, pointerType(), Origin(),
-            root->appendNew<Value>(proc, FramePointer, Origin())));
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    void* fp = compileAndRun<void*>(proc);
-    void* myFP = __builtin_frame_address(0);
-    CHECK(fp <= myFP);
-    CHECK(fp >= bitwise_cast<char*>(myFP) - 10000);
+    CHECK(compileAndRun<int64_t>(proc) == (a << b));
 }
 
-void testStoreLoadStackSlot(int value)
+void testShlArgImm(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-
-    StackSlotValue* stack = root->appendNew<StackSlotValue>(
-        proc, Origin(), sizeof(int), StackSlotKind::Anonymous);
-
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        stack);
-    
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), stack));
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    CHECK(compileAndRun<int>(proc, value) == value);
+    CHECK(compileAndRun<int64_t>(proc, a) == (a << b));
 }
 
-template<typename T>
-int32_t modelLoad(int32_t value)
+void testShlArg32(int32_t a)
 {
-    union {
-        int32_t original;
-        T loaded;
-    } u;
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Shl, Origin(), value, value));
 
-    u.original = value;
-    if (std::is_signed<T>::value)
-        return static_cast<int32_t>(u.loaded);
-    return static_cast<int32_t>(static_cast<uint32_t>(u.loaded));
+    CHECK(compileAndRun<int32_t>(proc, a) == (a << a));
 }
 
-template<typename T>
-void testLoad(B3::Opcode opcode, int32_t value)
+void testShlArgs32(int32_t a, int32_t b)
 {
-    // Simple load from an absolute address.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, opcode, Int32, Origin(),
-                root->appendNew<ConstPtrValue>(proc, Origin(), &value)));
-
-        CHECK(compileAndRun<int32_t>(proc) == modelLoad<T>(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, Int32, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-        CHECK(compileAndRun<int32_t>(proc, &value) == modelLoad<T>(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, Int32, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                sizeof(int32_t)));
-
-        CHECK(compileAndRun<int32_t>(proc, &value - 1) == modelLoad<T>(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, Int32, 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(compileAndRun<int32_t>(proc, &value - 2, (sizeof(int32_t) * 2) >> logScale) == modelLoad<T>(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, Int32, 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))));
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, 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<int32_t>(proc, &value - 2, (sizeof(int32_t) * 2) >> logScale) == modelLoad<T>(value));
-    }
+    CHECK(compileAndRun<int32_t>(proc, a, b) == (a << b));
 }
 
-void testSpillGP()
+void testShlImms32(int32_t a, int32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    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<int32_t>(proc) == (a << b));
 }
 
-void testSpillFP()
+void testShlArgImm32(int32_t a, int32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    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<int32_t>(proc, a) == (a << b));
 }
 
-void testBranch()
+void testSShrArgs(int64_t a, int64_t b)
 {
     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<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(compileAndRun<int64_t>(proc, a, b) == (a >> b));
 }
 
-void testBranchPtr()
+void testSShrImms(int64_t a, int64_t b)
 {
     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<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, static_cast<intptr_t>(42)) == 1);
-    CHECK(invoke<int>(*code, static_cast<intptr_t>(0)) == 0);
+    CHECK(compileAndRun<int64_t>(proc) == (a >> b));
 }
 
-void testDiamond()
+void testSShrArgImm(int64_t a, int64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* done = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
+        proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>(
-        proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-    thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+            proc, SShr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(
-        proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-    elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+    CHECK(compileAndRun<int64_t>(proc, a) == (a >> b));
+}
 
-    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
-    thenResult->setPhi(phi);
-    elseResult->setPhi(phi);
-    done->appendNew<ControlValue>(proc, Return, Origin(), phi);
+void testSShrArg32(int32_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, SShr, Origin(), value, value));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(compileAndRun<int32_t>(proc, a) == (a >> (a & 31)));
 }
 
-void testBranchNotEqual()
+void testSShrArgs32(int32_t a, int32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
+        proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, NotEqual, Origin(),
+            proc, SShr, Origin(),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), 0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+    CHECK(compileAndRun<int32_t>(proc, a, b) == (a >> b));
+}
 
-    elseCase->appendNew<ControlValue>(
+void testSShrImms32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(compileAndRun<int32_t>(proc) == (a >> b));
 }
 
-void testBranchNotEqualCommute()
+void testSShrArgImm32(int32_t a, int32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
+        proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, NotEqual, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), 0),
+            proc, SShr, 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<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(compileAndRun<int32_t>(proc, a) == (a >> b));
 }
 
-void testBranchNotEqualNotEqual()
+void testZShrArgs(uint64_t a, uint64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
+        proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, NotEqual, Origin(),
+            proc, ZShr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
             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));
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+    CHECK(compileAndRun<uint64_t>(proc, a, b) == (a >> b));
+}
 
-    elseCase->appendNew<ControlValue>(
+void testZShrImms(uint64_t a, uint64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(
+            proc, ZShr, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(compileAndRun<uint64_t>(proc) == (a >> b));
 }
 
-void testBranchEqual()
+void testZShrArgImm(uint64_t a, uint64_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
+        proc, Return, 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));
+            proc, ZShr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+    CHECK(compileAndRun<uint64_t>(proc, a) == (a >> b));
+}
 
-    elseCase->appendNew<ControlValue>(
+void testZShrArg32(uint32_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+        root->appendNew<Value>(proc, ZShr, Origin(), value, value));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(compileAndRun<uint32_t>(proc, a) == (a >> (a & 31)));
 }
 
-void testBranchEqualEqual()
+void testZShrArgs32(uint32_t a, uint32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
+        proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Equal, Origin(),
+            proc, ZShr, 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));
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+    CHECK(compileAndRun<uint32_t>(proc, a, b) == (a >> b));
+}
 
-    elseCase->appendNew<ControlValue>(
+void testZShrImms32(uint32_t a, uint32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(
+            proc, ZShr, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(compileAndRun<uint32_t>(proc) == (a >> b));
 }
 
-void testBranchEqualCommute()
+void testZShrArgImm32(uint32_t a, uint32_t b)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
+        proc, Return, Origin(),
         root->appendNew<Value>(
-            proc, Equal, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), 0),
+            proc, ZShr, Origin(),
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+    CHECK(compileAndRun<uint32_t>(proc, a) == (a >> b));
+}
 
-    elseCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+template<typename IntegerType>
+static unsigned countLeadingZero(IntegerType value)
+{
+    unsigned bitCount = sizeof(IntegerType) * 8;
+    if (!value)
+        return bitCount;
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    unsigned counter = 0;
+    while (!(static_cast<uint64_t>(value) & (1l << (bitCount - 1)))) {
+        value <<= 1;
+        ++counter;
+    }
+    return counter;
 }
 
-void testBranchEqualEqual1()
+void testClzArg64(int64_t a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* clzValue = root->appendNew<Value>(proc, Clz, Origin(), argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), clzValue);
+    CHECK(compileAndRun<unsigned>(proc, a) == countLeadingZero(a));
+}
 
-    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));
+void testClzMem64(int64_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* value = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* clzValue = root->appendNew<Value>(proc, Clz, Origin(), value);
+    root->appendNew<ControlValue>(proc, Return, Origin(), clzValue);
+    CHECK(compileAndRun<unsigned>(proc, &a) == countLeadingZero(a));
+}
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+void testClzArg32(int32_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* clzValue = root->appendNew<Value>(proc, Clz, Origin(), argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), clzValue);
+    CHECK(compileAndRun<unsigned>(proc, a) == countLeadingZero(a));
+}
 
-    elseCase->appendNew<ControlValue>(
+void testClzMem32(int32_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* value = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* clzValue = root->appendNew<Value>(proc, Clz, Origin(), value);
+    root->appendNew<ControlValue>(proc, Return, Origin(), clzValue);
+    CHECK(compileAndRun<unsigned>(proc, &a) == countLeadingZero(a));
+}
+
+void testAbsArg(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+        root->appendNew<Value>(
+            proc, Abs, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
 
-    auto code = compile(proc);
-    CHECK(invoke<int>(*code, 42) == 1);
-    CHECK(invoke<int>(*code, 0) == 0);
+    CHECK(isIdentical(compileAndRun<double>(proc, a), fabs(a)));
 }
 
-void testBranchFold(int value)
+void testAbsImm(double a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
+    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
     root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), value),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNew<ControlValue>(
         proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+        root->appendNew<Value>(proc, Abs, Origin(), argument));
 
-    elseCase->appendNew<ControlValue>(
+    CHECK(isIdentical(compileAndRun<double>(proc), fabs(a)));
+}
+
+void testAbsMem(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
+    root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(proc, Abs, Origin(), loadDouble));
 
-    CHECK(compileAndRun<int>(proc) == !!value);
+    CHECK(isIdentical(compileAndRun<double>(proc, &a), fabs(a)));
 }
 
-void testDiamondFold(int value)
+void testAbsAbsArg(double a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* done = proc.addBlock();
+    Value* firstAbs = root->appendNew<Value>(proc, Abs, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
+    Value* secondAbs = root->appendNew<Value>(proc, Abs, Origin(), firstAbs);
+    root->appendNew<ControlValue>(proc, Return, Origin(), secondAbs);
 
-    root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), value),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+    CHECK(isIdentical(compileAndRun<double>(proc, a), fabs(a)));
+}
 
-    UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>(
-        proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-    thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+void testAbsBitwiseCastArg(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argumentAsInt64 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* argumentAsDouble = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentAsInt64);
+    Value* absValue = root->appendNew<Value>(proc, Abs, Origin(), argumentAsDouble);
+    root->appendNew<ControlValue>(proc, Return, Origin(), absValue);
 
-    UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(
-        proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-    elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+    CHECK(isIdentical(compileAndRun<double>(proc, bitwise_cast<int64_t>(a)), fabs(a)));
+}
 
-    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
-    thenResult->setPhi(phi);
-    elseResult->setPhi(phi);
-    done->appendNew<ControlValue>(proc, Return, Origin(), phi);
+void testBitwiseCastAbsBitwiseCastArg(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argumentAsInt64 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* argumentAsDouble = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentAsInt64);
+    Value* absValue = root->appendNew<Value>(proc, Abs, Origin(), argumentAsDouble);
+    Value* resultAsInt64 = root->appendNew<Value>(proc, BitwiseCast, Origin(), absValue);
 
-    CHECK(compileAndRun<int>(proc) == !!value);
+    root->appendNew<ControlValue>(proc, Return, Origin(), resultAsInt64);
+
+    int64_t expectedResult = bitwise_cast<int64_t>(fabs(a));
+    CHECK(isIdentical(compileAndRun<int64_t>(proc, bitwise_cast<int64_t>(a)), expectedResult));
 }
 
-void testBranchNotEqualFoldPtr(intptr_t value)
+void testAbsArg(float a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
-    root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, NotEqual, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), value),
-            root->appendNew<ConstPtrValue>(proc, Origin(), 0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Abs, Origin(), argument);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
+}
 
-    elseCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+void testAbsImm(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Abs, Origin(), argument);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc) == !!value);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
 }
 
-void testBranchEqualFoldPtr(intptr_t value)
+void testAbsMem(float a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadFloat = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Abs, Origin(), loadFloat);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    root->appendNew<ControlValue>(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, Equal, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), value),
-            root->appendNew<ConstPtrValue>(proc, Origin(), 0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
+}
 
-    thenCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+void testAbsAbsArg(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* firstAbs = root->appendNew<Value>(proc, Abs, Origin(), argument);
+    Value* secondAbs = root->appendNew<Value>(proc, Abs, Origin(), firstAbs);
+    root->appendNew<ControlValue>(proc, Return, Origin(), secondAbs);
 
-    elseCase->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), static_cast<float>(fabs(a))));
+}
 
-    CHECK(compileAndRun<int>(proc) == !value);
+void testAbsBitwiseCastArg(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argumentAsInt32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argumentAsfloat = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentAsInt32);
+    Value* absValue = root->appendNew<Value>(proc, Abs, Origin(), argumentAsfloat);
+    root->appendNew<ControlValue>(proc, Return, Origin(), absValue);
+
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), static_cast<float>(fabs(a))));
 }
 
-void testComplex(unsigned numVars, unsigned numConstructs)
+void testBitwiseCastAbsBitwiseCastArg(float a)
 {
-    double before = monotonicallyIncreasingTimeMS();
-    
     Procedure proc;
-    BasicBlock* current = proc.addBlock();
+    BasicBlock* root = proc.addBlock();
+    Value* argumentAsInt32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argumentAsfloat = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentAsInt32);
+    Value* absValue = root->appendNew<Value>(proc, Abs, Origin(), argumentAsfloat);
+    Value* resultAsInt64 = root->appendNew<Value>(proc, BitwiseCast, Origin(), absValue);
 
-    Const32Value* one = current->appendNew<Const32Value>(proc, Origin(), 1);
+    root->appendNew<ControlValue>(proc, Return, Origin(), resultAsInt64);
 
-    Vector<int32_t> varSlots;
-    for (unsigned i = numVars; i--;)
-        varSlots.append(i);
+    int32_t expectedResult = bitwise_cast<int32_t>(static_cast<float>(fabs(a)));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), expectedResult));
+}
 
-    Vector<Value*> vars;
-    for (int32_t& varSlot : varSlots) {
-        Value* varSlotPtr = current->appendNew<ConstPtrValue>(proc, Origin(), &varSlot);
-        vars.append(current->appendNew<MemoryValue>(proc, Load, Int32, Origin(), varSlotPtr));
-    }
+void testAbsArgWithUselessDoubleConversion(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Abs, Origin(), asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    for (unsigned i = 0; i < numConstructs; ++i) {
-        if (i & 1) {
-            // Control flow diamond.
-            unsigned predicateVarIndex = ((i >> 1) + 2) % numVars;
-            unsigned thenIncVarIndex = ((i >> 1) + 0) % numVars;
-            unsigned elseIncVarIndex = ((i >> 1) + 1) % numVars;
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
+}
 
-            BasicBlock* thenBlock = proc.addBlock();
-            BasicBlock* elseBlock = proc.addBlock();
-            BasicBlock* continuation = proc.addBlock();
+void testAbsArgWithEffectfulDoubleConversion(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Abs, Origin(), asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    Value* doubleAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleAddress);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-            current->appendNew<ControlValue>(
-                proc, Branch, Origin(), vars[predicateVarIndex],
-                FrequentedBlock(thenBlock), FrequentedBlock(elseBlock));
+    double effect = 0;
+    int32_t resultValue = compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), &effect);
+    CHECK(isIdentical(resultValue, bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
+    CHECK(isIdentical(effect, fabs(a)));
+}
 
-            UpsilonValue* thenThenResult = thenBlock->appendNew<UpsilonValue>(
-                proc, Origin(),
-                thenBlock->appendNew<Value>(proc, Add, Origin(), vars[thenIncVarIndex], one));
-            UpsilonValue* thenElseResult = thenBlock->appendNew<UpsilonValue>(
-                proc, Origin(), vars[elseIncVarIndex]);
-            thenBlock->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation));
+void testCeilArg(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Ceil, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
 
-            UpsilonValue* elseElseResult = elseBlock->appendNew<UpsilonValue>(
-                proc, Origin(),
-                elseBlock->appendNew<Value>(proc, Add, Origin(), vars[elseIncVarIndex], one));
-            UpsilonValue* elseThenResult = elseBlock->appendNew<UpsilonValue>(
-                proc, Origin(), vars[thenIncVarIndex]);
-            elseBlock->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation));
+    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(a)));
+}
 
-            Value* thenPhi = continuation->appendNew<Value>(proc, Phi, Int32, Origin());
-            thenThenResult->setPhi(thenPhi);
-            elseThenResult->setPhi(thenPhi);
-            vars[thenIncVarIndex] = thenPhi;
-            
-            Value* elsePhi = continuation->appendNew<Value>(proc, Phi, Int32, Origin());
-            thenElseResult->setPhi(elsePhi);
-            elseElseResult->setPhi(elsePhi);
-            vars[elseIncVarIndex] = thenPhi;
-            
-            current = continuation;
-        } else {
-            // Loop.
+void testCeilImm(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Ceil, Origin(), argument));
 
-            BasicBlock* loopEntry = proc.addBlock();
-            BasicBlock* loopReentry = proc.addBlock();
-            BasicBlock* loopBody = proc.addBlock();
-            BasicBlock* loopExit = proc.addBlock();
-            BasicBlock* loopSkip = proc.addBlock();
-            BasicBlock* continuation = proc.addBlock();
-            
-            Value* startIndex = vars[((i >> 1) + 1) % numVars];
-            Value* startSum = current->appendNew<Const32Value>(proc, Origin(), 0);
-            current->appendNew<ControlValue>(
-                proc, Branch, Origin(), startIndex,
-                FrequentedBlock(loopEntry), FrequentedBlock(loopSkip));
+    CHECK(isIdentical(compileAndRun<double>(proc), ceil(a)));
+}
 
-            UpsilonValue* startIndexForBody = loopEntry->appendNew<UpsilonValue>(
-                proc, Origin(), startIndex);
-            UpsilonValue* startSumForBody = loopEntry->appendNew<UpsilonValue>(
-                proc, Origin(), startSum);
-            loopEntry->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loopBody));
+void testCeilMem(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Ceil, Origin(), loadDouble));
 
-            Value* bodyIndex = loopBody->appendNew<Value>(proc, Phi, Int32, Origin());
-            startIndexForBody->setPhi(bodyIndex);
-            Value* bodySum = loopBody->appendNew<Value>(proc, Phi, Int32, Origin());
-            startSumForBody->setPhi(bodySum);
-            Value* newBodyIndex = loopBody->appendNew<Value>(proc, Sub, Origin(), bodyIndex, one);
-            Value* newBodySum = loopBody->appendNew<Value>(
-                proc, Add, Origin(),
-                bodySum,
-                loopBody->appendNew<MemoryValue>(
-                    proc, Load, Int32, Origin(),
-                    loopBody->appendNew<Value>(
-                        proc, Add, Origin(),
-                        loopBody->appendNew<ConstPtrValue>(proc, Origin(), varSlots.data()),
-                        loopBody->appendNew<Value>(
-                            proc, Shl, Origin(),
-                            loopBody->appendNew<Value>(
-                                proc, ZExt32, Origin(),
-                                loopBody->appendNew<Value>(
-                                    proc, BitAnd, Origin(),
-                                    newBodyIndex,
-                                    loopBody->appendNew<Const32Value>(
-                                        proc, Origin(), numVars - 1))),
-                            loopBody->appendNew<Const32Value>(proc, Origin(), 2)))));
-            loopBody->appendNew<ControlValue>(
-                proc, Branch, Origin(), newBodyIndex,
-                FrequentedBlock(loopReentry), FrequentedBlock(loopExit));
+    CHECK(isIdentical(compileAndRun<double>(proc, &a), ceil(a)));
+}
 
-            loopReentry->appendNew<UpsilonValue>(proc, Origin(), newBodyIndex, bodyIndex);
-            loopReentry->appendNew<UpsilonValue>(proc, Origin(), newBodySum, bodySum);
-            loopReentry->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loopBody));
+void testCeilCeilArg(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* firstCeil = root->appendNew<Value>(proc, Ceil, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
+    Value* secondCeil = root->appendNew<Value>(proc, Ceil, Origin(), firstCeil);
+    root->appendNew<ControlValue>(proc, Return, Origin(), secondCeil);
 
-            UpsilonValue* exitSum = loopExit->appendNew<UpsilonValue>(proc, Origin(), newBodySum);
-            loopExit->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation));
+    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(a)));
+}
 
-            UpsilonValue* skipSum = loopSkip->appendNew<UpsilonValue>(proc, Origin(), startSum);
-            loopSkip->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation));
+void testCeilIToD64(int64_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* argumentAsDouble = root->appendNew<Value>(proc, IToD, Origin(), argument);
 
-            Value* finalSum = continuation->appendNew<Value>(proc, Phi, Int32, Origin());
-            exitSum->setPhi(finalSum);
-            skipSum->setPhi(finalSum);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Ceil, Origin(), argumentAsDouble));
 
-            current = continuation;
-            vars[((i >> 1) + 0) % numVars] = finalSum;
-        }
-    }
+    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(static_cast<double>(a))));
+}
 
-    current->appendNew<ControlValue>(proc, Return, Origin(), vars[0]);
+void testCeilIToD32(int64_t a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argumentAsDouble = root->appendNew<Value>(proc, IToD, Origin(), argument);
 
-    compile(proc);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Ceil, Origin(), argumentAsDouble));
 
-    double after = monotonicallyIncreasingTimeMS();
-    dataLog(toCString("    That took ", after - before, " ms.\n"));
+    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(static_cast<double>(a))));
 }
 
-void testSimplePatchpoint()
+void testCeilArg(float a)
 {
     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(ConstrainedValue(arg1, ValueRep::SomeRegister));
-    patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            CHECK(params.reps[2].isGPR());
-            jit.move(params.reps[1].gpr(), params.reps[0].gpr());
-            jit.add32(params.reps[2].gpr(), params.reps[0].gpr());
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Ceil, Origin(), argument);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
 }
 
-void testSimplePatchpointWithoutOuputClobbersGPArgs()
+void testCeilImm(float a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 42);
-    Value* const2 = root->appendNew<Const64Value>(proc, Origin(), 13);
+    Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Ceil, Origin(), argument);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
-    patchpoint->clobber(RegisterSet(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1));
-    patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister));
-    patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), params.reps[0].gpr());
-            jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), params.reps[1].gpr());
-            jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), GPRInfo::argumentGPR0);
-            jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), GPRInfo::argumentGPR1);
-        });
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
+}
 
-    Value* result = root->appendNew<Value>(proc, Add, Origin(), arg1, arg2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+void testCeilMem(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadFloat = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Ceil, Origin(), loadFloat);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(ceilf(a))));
 }
 
-void testSimplePatchpointWithOuputClobbersGPArgs()
+void testCeilCeilArg(float a)
 {
-    // We can't predict where the output will be but we want to be sure it is not
-    // one of the clobbered registers which is a bit hard to test.
-    //
-    // What we do is force the hand of our register allocator by clobbering absolutely
-    // everything but 1. The only valid allocation is to give it to the result and
-    // spill everything else.
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* firstCeil = root->appendNew<Value>(proc, Ceil, Origin(), argument);
+    Value* secondCeil = root->appendNew<Value>(proc, Ceil, Origin(), firstCeil);
+    root->appendNew<ControlValue>(proc, Return, Origin(), secondCeil);
+
+    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), ceilf(a)));
+}
 
+void testCeilArgWithUselessDoubleConversion(float a)
+{
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 42);
-    Value* const2 = root->appendNew<Const64Value>(proc, Origin(), 13);
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Ceil, Origin(), asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int64, Origin());
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
+}
 
-    RegisterSet clobberAll = RegisterSet::allGPRs();
-    clobberAll.exclude(RegisterSet::stackRegisters());
-    clobberAll.exclude(RegisterSet::reservedHardwareRegisters());
-    clobberAll.clear(GPRInfo::argumentGPR2);
-    patchpoint->clobber(clobberAll);
+void testCeilArgWithEffectfulDoubleConversion(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Ceil, Origin(), asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    Value* doubleAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleAddress);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister));
-    patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister));
+    double effect = 0;
+    int32_t resultValue = compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), &effect);
+    CHECK(isIdentical(resultValue, bitwise_cast<int32_t>(ceilf(a))));
+    CHECK(isIdentical(effect, ceilf(a)));
+}
 
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            CHECK(params.reps[2].isGPR());
-            jit.move(params.reps[1].gpr(), params.reps[0].gpr());
-            jit.add64(params.reps[2].gpr(), params.reps[0].gpr());
+void testSqrtArg(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Sqrt, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
 
-            clobberAll.forEach([&] (Reg reg) {
-                jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), reg.gpr());
-            });
-        });
+    CHECK(isIdentical(compileAndRun<double>(proc, a), sqrt(a)));
+}
 
-    Value* result = root->appendNew<Value>(proc, Add, Origin(), patchpoint,
-        root->appendNew<Value>(proc, Add, Origin(), arg1, arg2));
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+void testSqrtImm(double a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Sqrt, Origin(), argument));
 
-    CHECK(compileAndRun<int>(proc, 1, 2) == 58);
+    CHECK(isIdentical(compileAndRun<double>(proc), sqrt(a)));
 }
 
-void testSimplePatchpointWithoutOuputClobbersFPArgs()
+void testSqrtMem(double a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
-    Value* const1 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5);
-    Value* const2 = root->appendNew<ConstDoubleValue>(proc, Origin(), 13.1);
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Sqrt, Origin(), loadDouble));
 
-    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
-    patchpoint->clobber(RegisterSet(FPRInfo::argumentFPR0, FPRInfo::argumentFPR1));
-    patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister));
-    patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isFPR());
-            CHECK(params.reps[1].isFPR());
-            jit.moveZeroToDouble(params.reps[0].fpr());
-            jit.moveZeroToDouble(params.reps[1].fpr());
-            jit.moveZeroToDouble(FPRInfo::argumentFPR0);
-            jit.moveZeroToDouble(FPRInfo::argumentFPR1);
-        });
+    CHECK(isIdentical(compileAndRun<double>(proc, &a), sqrt(a)));
+}
 
-    Value* result = root->appendNew<Value>(proc, Add, Origin(), arg1, arg2);
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+void testSqrtArg(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* result = root->appendNew<Value>(proc, Sqrt, Origin(), argument);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<double>(proc, 1.5, 2.5) == 4);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(sqrt(a)))));
 }
 
-void testSimplePatchpointWithOuputClobbersFPArgs()
+void testSqrtImm(float a)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
-    Value* const1 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5);
-    Value* const2 = root->appendNew<ConstDoubleValue>(proc, Origin(), 13.1);
+    Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* result = root->appendNew<Value>(proc, Sqrt, Origin(), argument);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Double, Origin());
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(sqrt(a)))));
+}
 
-    RegisterSet clobberAll = RegisterSet::allFPRs();
-    clobberAll.exclude(RegisterSet::stackRegisters());
-    clobberAll.exclude(RegisterSet::reservedHardwareRegisters());
-    clobberAll.clear(FPRInfo::argumentFPR2);
-    patchpoint->clobber(clobberAll);
+void testSqrtMem(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadFloat = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sqrt, Origin(), loadFloat);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister));
-    patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister));
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(static_cast<float>(sqrt(a)))));
+}
 
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[0].isFPR());
-            CHECK(params.reps[1].isFPR());
-            CHECK(params.reps[2].isFPR());
-            jit.addDouble(params.reps[1].fpr(), params.reps[2].fpr(), params.reps[0].fpr());
+void testSqrtArgWithUselessDoubleConversion(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Sqrt, Origin(), asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-            clobberAll.forEach([&] (Reg reg) {
-                jit.moveZeroToDouble(reg.fpr());
-            });
-        });
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(sqrt(a)))));
+}
 
-    Value* result = root->appendNew<Value>(proc, Add, Origin(), patchpoint,
-        root->appendNew<Value>(proc, Add, Origin(), arg1, arg2));
-    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+void testSqrtArgWithEffectfulDoubleConversion(float a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    Value* result = root->appendNew<Value>(proc, Sqrt, Origin(), asDouble);
+    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+    Value* doubleAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleAddress);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
 
-    CHECK(compileAndRun<double>(proc, 1.5, 2.5) == 59.6);
+    double effect = 0;
+    int32_t resultValue = compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), &effect);
+    CHECK(isIdentical(resultValue, bitwise_cast<int32_t>(static_cast<float>(sqrt(a)))));
+    CHECK(isIdentical(effect, sqrt(a)));
 }
 
-void testPatchpointCallArg()
+void testDoubleArgToInt64BitwiseCast(double value)
 {
     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(ConstrainedValue(arg1, ValueRep::stackArgument(0)));
-    patchpoint->append(ConstrainedValue(arg2, ValueRep::stackArgument(8)));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isStack());
-            CHECK(params.reps[2].isStack());
-            jit.load32(
-                CCallHelpers::Address(GPRInfo::callFrameRegister, params.reps[1].offsetFromFP()),
-                params.reps[0].gpr());
-            jit.add32(
-                CCallHelpers::Address(GPRInfo::callFrameRegister, params.reps[2].offsetFromFP()),
-                params.reps[0].gpr());
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
 
-    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitwiseCast, Origin(), argument));
+
+    CHECK(isIdentical(compileAndRun<int64_t>(proc, value), bitwise_cast<int64_t>(value)));
 }
 
-void testPatchpointFixedRegister()
+void testDoubleImmToInt64BitwiseCast(double value)
 {
     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(ConstrainedValue(arg1, ValueRep(GPRInfo::regT0)));
-    patchpoint->append(ConstrainedValue(arg2, ValueRep(GPRInfo::regT1)));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1] == ValueRep(GPRInfo::regT0));
-            CHECK(params.reps[2] == ValueRep(GPRInfo::regT1));
-            GPRReg result = params.reps[0].gpr();
-
-            if (result == GPRInfo::regT1) {
-                jit.move(GPRInfo::regT1, result);
-                jit.add32(GPRInfo::regT0, result);
-            } else {
-                jit.move(GPRInfo::regT0, result);
-                jit.add32(GPRInfo::regT1, result);
-            }
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), value);
 
-    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitwiseCast, Origin(), argument));
+
+    CHECK(isIdentical(compileAndRun<int64_t>(proc), bitwise_cast<int64_t>(value)));
 }
 
-void testPatchpointAny()
+void testTwoBitwiseCastOnDouble(double value)
 {
     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(ConstrainedValue(arg1, ValueRep::Any));
-    patchpoint->append(ConstrainedValue(arg2, ValueRep::Any));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            // We shouldn't have spilled the inputs, so we assert that they're in registers.
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            CHECK(params.reps[2].isGPR());
-            jit.move(params.reps[1].gpr(), params.reps[0].gpr());
-            jit.add32(params.reps[2].gpr(), params.reps[0].gpr());
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* first = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument);
+    Value* second = root->appendNew<Value>(proc, BitwiseCast, Origin(), first);
+    root->appendNew<ControlValue>(proc, Return, Origin(), second);
 
-    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+    CHECK(isIdentical(compileAndRun<double>(proc, value), value));
 }
 
-void testPatchpointAnyImm()
+void testBitwiseCastOnDoubleInMemory(double value)
 {
     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);
-    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
-    patchpoint->append(ConstrainedValue(arg1, ValueRep::Any));
-    patchpoint->append(ConstrainedValue(arg2, ValueRep::Any));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            CHECK(params.reps[2].isConstant());
-            CHECK(params.reps[2].value() == 42);
-            jit.add32(
-                CCallHelpers::TrustedImm32(static_cast<int32_t>(params.reps[2].value())),
-                params.reps[1].gpr(), params.reps[0].gpr());
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
+    Value* cast = root->appendNew<Value>(proc, BitwiseCast, Origin(), loadDouble);
+    root->appendNew<ControlValue>(proc, Return, Origin(), cast);
 
-    CHECK(compileAndRun<int>(proc, 1) == 43);
+    CHECK(isIdentical(compileAndRun<int64_t>(proc, &value), bitwise_cast<int64_t>(value)));
 }
 
-void testPatchpointManyImms()
+void testBitwiseCastOnDoubleInMemoryIndexed(double value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), 42);
-    Value* arg2 = root->appendNew<Const64Value>(proc, Origin(), 43);
-    Value* arg3 = root->appendNew<Const64Value>(proc, Origin(), 43000000000000ll);
-    Value* arg4 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5);
-    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
-    patchpoint->append(ConstrainedValue(arg1, ValueRep::Any));
-    patchpoint->append(ConstrainedValue(arg2, ValueRep::Any));
-    patchpoint->append(ConstrainedValue(arg3, ValueRep::Any));
-    patchpoint->append(ConstrainedValue(arg4, ValueRep::Any));
-    patchpoint->setGenerator(
-        [&] (CCallHelpers&, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[0] == ValueRep::constant(42));
-            CHECK(params.reps[1] == ValueRep::constant(43));
-            CHECK(params.reps[2] == ValueRep::constant(43000000000000ll));
-            CHECK(params.reps[3] == ValueRep::constant(bitwise_cast<int64_t>(42.5)));
-        });
+    Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* scaledOffset = root->appendNew<Value>(proc, Shl, Origin(),
+        offset,
+        root->appendNew<Const32Value>(proc, Origin(), 3));
+    Value* address = root->appendNew<Value>(proc, Add, Origin(), base, scaledOffset);
+    MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
+    Value* cast = root->appendNew<Value>(proc, BitwiseCast, Origin(), loadDouble);
+    root->appendNew<ControlValue>(proc, Return, Origin(), cast);
+
+    CHECK(isIdentical(compileAndRun<int64_t>(proc, &value, 0), bitwise_cast<int64_t>(value)));
+}
+
+void testInt64BArgToDoubleBitwiseCast(int64_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
+        root->appendNew<Value>(
+            proc, BitwiseCast, Origin(), argument));
 
-    CHECK(!compileAndRun<int>(proc));
+    CHECK(isIdentical(compileAndRun<double>(proc, value), bitwise_cast<double>(value)));
 }
 
-void testSimpleCheck()
+void testInt64BImmToDoubleBitwiseCast(int64_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    CheckValue* check = root->appendNew<CheckValue>(proc, Check, Origin(), arg);
-    check->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 1);
+    Value* argument = root->appendNew<Const64Value>(proc, Origin(), value);
 
-            // 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));
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitwiseCast, Origin(), argument));
 
-    auto code = compile(proc);
-    
-    CHECK(invoke<int>(*code, 0) == 0);
-    CHECK(invoke<int>(*code, 1) == 42);
+    CHECK(isIdentical(compileAndRun<double>(proc), bitwise_cast<double>(value)));
 }
 
-void testCheckLessThan()
+void testTwoBitwiseCastOnInt64(int64_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    CheckValue* check = root->appendNew<CheckValue>(
-        proc, Check, Origin(),
-        root->appendNew<Value>(
-            proc, LessThan, Origin(), arg,
-            root->appendNew<Const32Value>(proc, Origin(), 42)));
-    check->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 1);
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* first = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument);
+    Value* second = root->appendNew<Value>(proc, BitwiseCast, Origin(), first);
+    root->appendNew<ControlValue>(proc, Return, Origin(), second);
 
-            // 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));
+    CHECK(isIdentical(compileAndRun<int64_t>(proc, value), value));
+}
 
-    auto code = compile(proc);
-    
-    CHECK(invoke<int>(*code, 42) == 0);
-    CHECK(invoke<int>(*code, 1000) == 0);
-    CHECK(invoke<int>(*code, 41) == 42);
-    CHECK(invoke<int>(*code, 0) == 42);
-    CHECK(invoke<int>(*code, -1) == 42);
+void testBitwiseCastOnInt64InMemory(int64_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* cast = root->appendNew<Value>(proc, BitwiseCast, Origin(), loadDouble);
+    root->appendNew<ControlValue>(proc, Return, Origin(), cast);
+
+    CHECK(isIdentical(compileAndRun<double>(proc, &value), bitwise_cast<double>(value)));
 }
 
-void testCheckMegaCombo()
+void testBitwiseCastOnInt64InMemoryIndexed(int64_t value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
     Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* index = root->appendNew<Value>(
-        proc, ZExt32, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+    Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* scaledOffset = root->appendNew<Value>(proc, Shl, Origin(),
+        offset,
+        root->appendNew<Const32Value>(proc, Origin(), 3));
+    Value* address = root->appendNew<Value>(proc, Add, Origin(), base, scaledOffset);
+    MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* cast = root->appendNew<Value>(proc, BitwiseCast, Origin(), loadDouble);
+    root->appendNew<ControlValue>(proc, Return, Origin(), cast);
 
-    Value* ptr = root->appendNew<Value>(
-        proc, Add, Origin(), base,
-        root->appendNew<Value>(
-            proc, Shl, Origin(), index,
-            root->appendNew<Const32Value>(proc, Origin(), 1)));
-    
-    CheckValue* check = root->appendNew<CheckValue>(
-        proc, Check, Origin(),
-        root->appendNew<Value>(
-            proc, LessThan, Origin(),
-            root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr),
-            root->appendNew<Const32Value>(proc, Origin(), 42)));
-    check->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 1);
-
-            // 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);
-
-    int8_t value;
-    value = 42;
-    CHECK(invoke<int>(*code, &value - 2, 1) == 0);
-    value = 127;
-    CHECK(invoke<int>(*code, &value - 2, 1) == 0);
-    value = 41;
-    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
-    value = 0;
-    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
-    value = -1;
-    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
+    CHECK(isIdentical(compileAndRun<double>(proc, &value, 0), bitwise_cast<double>(value)));
 }
 
-void testCheckAddImm()
+void testFloatImmToInt32BitwiseCast(float value)
 {
     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* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
-    checkAdd->append(arg1);
-    checkAdd->append(arg2);
-    checkAdd->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isConstant());
-            CHECK(params.reps[3].value() == 42);
-            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1);
-            jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
+    Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), value);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkAdd));
+        root->appendNew<Value>(
+            proc, BitwiseCast, Origin(), argument));
 
-    auto code = compile(proc);
+    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(value)));
+}
 
-    CHECK(invoke<double>(*code, 0) == 42.0);
-    CHECK(invoke<double>(*code, 1) == 43.0);
-    CHECK(invoke<double>(*code, 42) == 84.0);
-    CHECK(invoke<double>(*code, 2147483647) == 2147483689.0);
+void testBitwiseCastOnFloatInMemory(float value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadFloat = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), address);
+    Value* cast = root->appendNew<Value>(proc, BitwiseCast, Origin(), loadFloat);
+    root->appendNew<ControlValue>(proc, Return, Origin(), cast);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, &value), bitwise_cast<int32_t>(value)));
 }
 
-void testCheckAddImmCommute()
+void testInt32BArgToFloatBitwiseCast(int32_t value)
 {
     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* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg2, arg1);
-    checkAdd->append(arg1);
-    checkAdd->append(arg2);
-    checkAdd->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isConstant());
-            CHECK(params.reps[3].value() == 42);
-            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1);
-            jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkAdd));
-
-    auto code = compile(proc);
+        root->appendNew<Value>(
+            proc, BitwiseCast, Origin(), argument));
 
-    CHECK(invoke<double>(*code, 0) == 42.0);
-    CHECK(invoke<double>(*code, 1) == 43.0);
-    CHECK(invoke<double>(*code, 42) == 84.0);
-    CHECK(invoke<double>(*code, 2147483647) == 2147483689.0);
+    CHECK(isIdentical(compileAndRun<float>(proc, value), bitwise_cast<float>(value)));
 }
 
-void testCheckAddImmSomeRegister()
+void testInt32BImmToFloatBitwiseCast(int32_t value)
 {
     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* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
-    checkAdd->appendSomeRegister(arg1);
-    checkAdd->appendSomeRegister(arg2);
-    checkAdd->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isGPR());
-            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
-            jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
+    Value* argument = root->appendNew<Const64Value>(proc, Origin(), value);
+
     root->appendNew<ControlValue>(
         proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkAdd));
+        root->appendNew<Value>(
+            proc, BitwiseCast, Origin(), argument));
 
-    auto code = compile(proc);
+    CHECK(isIdentical(compileAndRun<float>(proc), bitwise_cast<float>(value)));
+}
 
-    CHECK(invoke<double>(*code, 0) == 42.0);
-    CHECK(invoke<double>(*code, 1) == 43.0);
-    CHECK(invoke<double>(*code, 42) == 84.0);
-    CHECK(invoke<double>(*code, 2147483647) == 2147483689.0);
+void testTwoBitwiseCastOnInt32(int32_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* first = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument);
+    Value* second = root->appendNew<Value>(proc, BitwiseCast, Origin(), first);
+    root->appendNew<ControlValue>(proc, Return, Origin(), second);
+
+    CHECK(isIdentical(compileAndRun<int32_t>(proc, value), value));
 }
 
-void testCheckAdd()
+void testBitwiseCastOnInt32InMemory(int32_t value)
 {
     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* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
-    checkAdd->appendSomeRegister(arg1);
-    checkAdd->appendSomeRegister(arg2);
-    checkAdd->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isGPR());
-            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
-            jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkAdd));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadFloat = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* cast = root->appendNew<Value>(proc, BitwiseCast, Origin(), loadFloat);
+    root->appendNew<ControlValue>(proc, Return, Origin(), cast);
 
-    auto code = compile(proc);
+    CHECK(isIdentical(compileAndRun<float>(proc, &value), bitwise_cast<float>(value)));
+}
 
-    CHECK(invoke<double>(*code, 0, 42) == 42.0);
-    CHECK(invoke<double>(*code, 1, 42) == 43.0);
-    CHECK(invoke<double>(*code, 42, 42) == 84.0);
-    CHECK(invoke<double>(*code, 2147483647, 42) == 2147483689.0);
+void testConvertDoubleToFloatArg(double value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* asFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asFloat);
+
+    CHECK(isIdentical(compileAndRun<float>(proc, value), static_cast<float>(value)));
 }
 
-void testCheckAdd64()
+void testConvertDoubleToFloatImm(double value)
 {
     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* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
-    checkAdd->appendSomeRegister(arg1);
-    checkAdd->appendSomeRegister(arg2);
-    checkAdd->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isGPR());
-            jit.convertInt64ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt64ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
-            jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkAdd));
+    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), value);
+    Value* asFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asFloat);
 
-    auto code = compile(proc);
+    CHECK(isIdentical(compileAndRun<float>(proc), static_cast<float>(value)));
+}
 
-    CHECK(invoke<double>(*code, 0ll, 42ll) == 42.0);
-    CHECK(invoke<double>(*code, 1ll, 42ll) == 43.0);
-    CHECK(invoke<double>(*code, 42ll, 42ll) == 84.0);
-    CHECK(invoke<double>(*code, 9223372036854775807ll, 42ll) == static_cast<double>(9223372036854775807ll) + 42.0);
+void testConvertDoubleToFloatMem(double value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadedDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
+    Value* asFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), loadedDouble);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asFloat);
+
+    CHECK(isIdentical(compileAndRun<float>(proc, &value), static_cast<float>(value)));
 }
 
-void testCheckAddFold(int a, int b)
+void testConvertFloatToDoubleArg(float value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a);
-    Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b);
-    CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
-    checkAdd->setGenerator(
-        [&] (CCallHelpers&, const StackmapGenerationParams&) {
-            CHECK(!"Should have been folded");
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd);
+    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asDouble);
 
-    auto code = compile(proc);
+    CHECK(isIdentical(compileAndRun<double>(proc, bitwise_cast<int32_t>(value)), static_cast<double>(value)));
+}
 
-    CHECK(invoke<int>(*code) == a + b);
+void testConvertFloatToDoubleImm(float value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), value);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asDouble);
+
+    CHECK(isIdentical(compileAndRun<double>(proc), static_cast<double>(value)));
 }
 
-void testCheckAddFoldFail(int a, int b)
+void testConvertFloatToDoubleMem(float value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a);
-    Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b);
-    CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
-    checkAdd->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
-            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd);
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadedFloat = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), address);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), loadedFloat);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asDouble);
 
-    auto code = compile(proc);
+    CHECK(isIdentical(compileAndRun<double>(proc, &value), static_cast<double>(value)));
+}
 
-    CHECK(invoke<int>(*code) == 42);
+void testConvertDoubleToFloatToDoubleToFloat(double value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* asFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), asFloat);
+    Value* asFloatAgain = root->appendNew<Value>(proc, DoubleToFloat, Origin(), asDouble);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asFloatAgain);
+
+    CHECK(isIdentical(compileAndRun<float>(proc, value), static_cast<float>(value)));
 }
 
-void testCheckSubImm()
+void testLoadFloatConvertDoubleConvertFloatStoreFloat(float value)
 {
     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) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isConstant());
-            CHECK(params.reps[3].value() == 42);
-            jit.convertInt32ToDouble(params.reps[2].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));
+    Value* src = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* dst = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* loadedFloat = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), src);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), loadedFloat);
+    Value* asFloatAgain = root->appendNew<Value>(proc, DoubleToFloat, Origin(), asDouble);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), asFloatAgain, dst);
 
-    auto code = compile(proc);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    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);
+    float input = value;
+    float output = 0.;
+    CHECK(!compileAndRun<int64_t>(proc, &input, &output));
+    CHECK(isIdentical(input, output));
 }
 
-void testCheckSubBadImm()
+void testFroundArg(double value)
 {
     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) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isConstant());
-            CHECK(params.reps[3].value() == badImm);
-            jit.convertInt32ToDouble(params.reps[2].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);
+    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* asFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), asFloat);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asDouble);
 
-    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(isIdentical(compileAndRun<double>(proc, value), static_cast<double>(static_cast<float>(value))));
 }
 
-void testCheckSub()
+void testFroundMem(double value)
 {
     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) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isGPR());
-            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params.reps[3].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));
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* loadedDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
+    Value* asFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), loadedDouble);
+    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), asFloat);
+    root->appendNew<ControlValue>(proc, Return, Origin(), asDouble);
 
-    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);
+    CHECK(isIdentical(compileAndRun<double>(proc, &value), static_cast<double>(static_cast<float>(value))));
 }
 
-NEVER_INLINE double doubleSub(double a, double b)
+void testStore32(int value)
 {
-    return a - b;
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int slot = 0xbaadbeef;
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc, value));
+    CHECK(slot == value);
 }
 
-void testCheckSub64()
+void testStoreConstant(int value)
 {
     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) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isGPR());
-            jit.convertInt64ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt64ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
-            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
+    int slot = 0xbaadbeef;
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), value),
+        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkSub));
-
-    auto code = compile(proc);
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    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));
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == value);
 }
 
-void testCheckSubFold(int a, int b)
+void testStoreConstantPtr(intptr_t 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&, const StackmapGenerationParams&) {
-            CHECK(!"Should have been folded");
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkSub);
+    intptr_t slot;
+    if (is64Bit())
+        slot = (static_cast<intptr_t>(0xbaadbeef) << 32) + static_cast<intptr_t>(0xbaadbeef);
+    else
+        slot = 0xbaadbeef;
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<ConstPtrValue>(proc, Origin(), value),
+        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
-    auto code = compile(proc);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == value);
+}
 
-    CHECK(invoke<int>(*code) == a - b);
+void testStore8Arg()
+{
+    { // 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, Store8, Origin(), value, address);
+        root->appendNew<ControlValue>(proc, Return, Origin(), value);
+
+        int8_t storage = 0;
+        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, Store8, Origin(), value, address);
+        root->appendNew<ControlValue>(proc, Return, Origin(), value);
+
+        int8_t storage = 0;
+        CHECK(compileAndRun<int64_t>(proc, 42, &storage, 1) == 42);
+        CHECK(storage == 42);
+    }
 }
 
-void testCheckSubFoldFail(int a, int b)
+void testStore8Imm()
 {
-    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&) {
-            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkSub);
+    { // Direct addressing.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
 
-    auto code = compile(proc);
+        Value* value = root->appendNew<Const32Value>(proc, Origin(), 42);
+        Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
 
-    CHECK(invoke<int>(*code) == 42);
+        root->appendNew<MemoryValue>(proc, Store8, Origin(), value, address);
+        root->appendNew<ControlValue>(proc, Return, Origin(), value);
+
+        int8_t storage = 0;
+        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, Store8, Origin(), value, address);
+        root->appendNew<ControlValue>(proc, Return, Origin(), value);
+
+        int8_t storage = 0;
+        CHECK(compileAndRun<int64_t>(proc, &storage, 1) == 42);
+        CHECK(storage == 42);
+    }
 }
 
-void testCheckNeg()
+void testStorePartial8BitRegisterOnX86()
 {
     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(
+
+    // We want to have this in ECX.
+    Value* returnValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+
+    // We want this suck in EDX.
+    Value* whereToStore = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+
+    // The patch point is there to help us force the hand of the compiler.
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
+
+    // For the value above to be materialized and give the allocator
+    // a stronger insentive to name those register the way we need.
+    patchpoint->append(ConstrainedValue(returnValue, ValueRep(GPRInfo::regT3)));
+    patchpoint->append(ConstrainedValue(whereToStore, ValueRep(GPRInfo::regT2)));
+
+    // We'll produce EDI.
+    patchpoint->resultConstraint = ValueRep::reg(GPRInfo::regT6);
+
+    // Give the allocator a good reason not to use any other register.
+    RegisterSet clobberSet = RegisterSet::allGPRs();
+    clobberSet.exclude(RegisterSet::stackRegisters());
+    clobberSet.exclude(RegisterSet::reservedHardwareRegisters());
+    clobberSet.clear(GPRInfo::regT3);
+    clobberSet.clear(GPRInfo::regT2);
+    clobberSet.clear(GPRInfo::regT6);
+    patchpoint->clobberLate(clobberSet);
+
+    // Set EDI.
+    patchpoint->setGenerator(
         [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[2].isGPR());
-            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT1);
-            jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            jit.xor64(params[0].gpr(), params[0].gpr());
         });
-    root->appendNew<ControlValue>(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, IToD, Origin(), checkNeg));
 
-    auto code = compile(proc);
+    // If everything went well, we should have the big number in eax,
+    // patchpoint == EDI and whereToStore = EDX.
+    // Since EDI == 5, and AH = 5 on 8 bit store, this would go wrong
+    // if we use X86 partial registers.
+    root->appendNew<MemoryValue>(proc, Store8, Origin(), patchpoint, whereToStore);
 
-    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);
+    root->appendNew<ControlValue>(proc, Return, Origin(), returnValue);
+
+    int8_t storage = 0xff;
+    CHECK(compileAndRun<int64_t>(proc, 0x12345678abcdef12, &storage) == 0x12345678abcdef12);
+    CHECK(!storage);
 }
 
-void testCheckNeg64()
+void testStore16Arg()
 {
-    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) {
-            CHECK(params.reps.size() == 3);
-            CHECK(params.reps[2].isGPR());
-            jit.convertInt64ToDouble(params.reps[2].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));
+    { // Direct addressing.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
 
-    auto code = compile(proc);
+        Value* value = root->appendNew<Value>(proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
 
-    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);
+        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 testCheckMul()
+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;
     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) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isGPR());
-            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params.reps[3].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);
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
 
-    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);
+    CHECK(compileAndRun<int>(proc, value) == static_cast<int>(value));
 }
 
-void testCheckMulMemory()
+void testAdd1(int value)
 {
     Procedure proc;
     BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), 1)));
 
-    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) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isGPR());
-            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
-            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
+    CHECK(compileAndRun<int>(proc, value) == value + 1);
+}
+
+void testAdd1Ptr(intptr_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
     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);
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<ConstPtrValue>(proc, Origin(), 1)));
 
-    left = 2147483647;
-    right = 42;
-    CHECK(invoke<double>(*code) == 2147483647.0 * 42.0);
+    CHECK(compileAndRun<intptr_t>(proc, value) == value + 1);
 }
 
-void testCheckMul2()
+void testNeg32(int32_t value)
 {
     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) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isConstant());
-            CHECK(params.reps[3].value() == 2);
-            jit.convertInt32ToDouble(params.reps[2].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);
+        root->appendNew<Value>(
+            proc, Sub, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), 0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
 
-    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);
+    CHECK(compileAndRun<int32_t>(proc, value) == -value);
 }
 
-void testCheckMul64()
+void testNegPtr(intptr_t value)
 {
     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) {
-            CHECK(params.reps.size() == 4);
-            CHECK(params.reps[2].isGPR());
-            CHECK(params.reps[3].isGPR());
-            jit.convertInt64ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt64ToDouble(params.reps[3].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);
+        root->appendNew<Value>(
+            proc, Sub, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), 0),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
 
-    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);
+    CHECK(compileAndRun<intptr_t>(proc, value) == -value);
 }
 
-void testCheckMulFold(int a, int b)
+void testStoreAddLoad32(int amount)
 {
     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);
+    int slot = 37;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    root->appendNew<MemoryValue>(
+        proc, Store, Origin(),
+        root->appendNew<Value>(
+            proc, Add, 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<Const32Value>(proc, Origin(), 0));
 
-    CHECK(invoke<int>(*code) == a * b);
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37 + amount);
 }
 
-void testCheckMulFoldFail(int a, int b)
+void testStoreAddLoadImm32(int amount)
 {
     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&) {
-            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
-            jit.emitFunctionEpilogue();
-            jit.ret();
-        });
-    root->appendNew<ControlValue>(proc, Return, Origin(), checkMul);
-
-    auto code = compile(proc);
+    int slot = 37;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    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(invoke<int>(*code) == 42);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
 }
 
-template<typename LeftFunctor, typename RightFunctor>
-void genericTestCompare(
-    B3::Opcode opcode, const LeftFunctor& leftFunctor, const RightFunctor& rightFunctor,
-    int left, int right, int result)
+void testStoreAddLoad8(int amount, B3::Opcode loadOpcode)
 {
-    // Using a compare.
-    {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-
-        Value* leftValue = leftFunctor(root, proc);
-        Value* rightValue = rightFunctor(root, proc);
-        
-        root->appendNew<ControlValue>(
-            proc, Return, Origin(),
+    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, NotEqual, Origin(),
-                root->appendNew<Value>(proc, opcode, Origin(), leftValue, rightValue),
-                root->appendNew<Const32Value>(proc, Origin(), 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();
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-        Value* leftValue = leftFunctor(root, proc);
-        Value* rightValue = rightFunctor(root, proc);
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37 + amount);
+}
 
-        root->appendNew<ControlValue>(
-            proc, Branch, Origin(),
-            root->appendNew<Value>(proc, opcode, Origin(), leftValue, rightValue),
-            FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+void testStoreAddLoadImm8(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<Const32Value>(proc, Origin(), amount)),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-        // 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) {
-                CHECK(params.reps.size() == 1);
-                CHECK(params.reps[0].isGPR());
-                jit.move(CCallHelpers::TrustedImm32(1), params.reps[0].gpr());
-            });
-        thenCase->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
+}
 
-        elseCase->appendNew<ControlValue>(
-            proc, Return, Origin(),
-            elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+void testStoreAddLoad16(int amount, B3::Opcode loadOpcode)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int16_t slot = 37;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    root->appendNew<MemoryValue>(
+        proc, Store16, 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))),
+        slotPtr);
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
 
-        CHECK(compileAndRun<int>(proc, left, right) == result);
-    }
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37 + amount);
 }
 
-int modelCompare(B3::Opcode opcode, int left, int right)
+void testStoreAddLoadImm16(int amount, B3::Opcode loadOpcode)
 {
-    switch (opcode) {
-    case Equal:
-        return left == right;
-    case NotEqual:
-        return left != right;
-    case LessThan:
-        return left < right;
-    case GreaterThan:
-        return left > right;
-    case LessEqual:
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int16_t slot = 37;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    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<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
+}
+
+void testStoreAddLoad64(int amount)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    int64_t slot = 37000000000ll;
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    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<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37000000000ll + amount);
+}
+
+void testStoreAddLoadImm64(int64_t amount)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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<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));
+    CHECK(slot == 370000000000ll + amount);
+}
+
+void testStoreAddLoad32Index(int amount)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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<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 testStoreAddLoadImm32Index(int amount)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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));
+    CHECK(slot == 37 + amount);
+}
+
+void testStoreAddLoad8Index(int amount, B3::Opcode loadOpcode)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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, 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 testStoreAddLoadImm8Index(int amount, B3::Opcode loadOpcode)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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, 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));
+    CHECK(slot == 37 + amount);
+}
+
+void testStoreAddLoad16Index(int amount, B3::Opcode loadOpcode)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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<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 testStoreAddLoadImm16Index(int amount, B3::Opcode loadOpcode)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    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<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 37 + amount);
+}
+
+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<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == 37000000000ll + amount);
+}
+
+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<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == 370000000000ll + amount);
+}
+
+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<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc, amount));
+    CHECK(slot == startValue - amount);
+}
+
+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));
+
+    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, 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<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc));
+    CHECK(slot == ((37 + amount) & mask));
+}
+
+void testStoreNegLoad32(int32_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    int32_t slot = value;
+
+    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
+    
+    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);
+    
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int32_t>(proc));
+    CHECK(slot == -value);
+}
+
+void testStoreNegLoadPtr(intptr_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    intptr_t slot = value;
+
+    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));
+
+    CHECK(!compileAndRun<int32_t>(proc));
+    CHECK(slot == -value);
+}
+
+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))));
+
+    CHECK(compileAndRun<int>(proc, value) == value + 1);
+}
+
+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))));
+
+    CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
+}
+
+void testLoadOffsetNotConstant()
+{
+    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))));
+
+    CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
+}
+
+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]);
+}
+
+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);
+}
+
+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]);
+}
+
+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 testFramePointer()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, FramePointer, Origin()));
+
+    void* fp = compileAndRun<void*>(proc);
+    CHECK(fp < &proc);
+    CHECK(fp >= bitwise_cast<char*>(&proc) - 10000);
+}
+
+void testOverrideFramePointer()
+{
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        // Add a stack slot to make the frame non trivial.
+        root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(8));
+
+        // 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);
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        CHECK(compileAndRun<int64_t>(proc, 1));
+    }
+    {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(8));
+
+        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 testStackSlot()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(1)));
+
+    void* stackSlot = compileAndRun<void*>(proc);
+    CHECK(stackSlot < &proc);
+    CHECK(stackSlot >= bitwise_cast<char*>(&proc) - 10000);
+}
+
+void testLoadFromFramePointer()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), Origin(),
+            root->appendNew<Value>(proc, FramePointer, Origin())));
+
+    void* fp = compileAndRun<void*>(proc);
+    void* myFP = __builtin_frame_address(0);
+    CHECK(fp <= myFP);
+    CHECK(fp >= bitwise_cast<char*>(myFP) - 10000);
+}
+
+void testStoreLoadStackSlot(int value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    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)),
+        stack);
+    
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), stack));
+
+    CHECK(compileAndRun<int>(proc, value) == value);
+}
+
+template<typename LoadedType, typename EffectiveType>
+EffectiveType modelLoad(EffectiveType 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; }
+
+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)));
+
+        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)));
+
+        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)));
+
+        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);
+}
+
+template<B3::Type type, typename T>
+void testLoad(T value)
+{
+    return testLoad<type, T>(Load, value);
+}
+
+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);
+
+        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);
+
+        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 - 1, 1));
+        CHECK(isIdentical(static_cast<float>(input), output));
+    }
+}
+
+void testSpillGP()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    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, 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));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(*code, 42) == 1);
+    CHECK(invoke<int>(*code, 0) == 0);
+}
+
+void testBranchPtr()
+{
+    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));
+
+    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 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, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    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));
+
+    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 testBranchNotEqual()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    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));
+
+    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 testBranchNotEqualCommute()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    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));
+
+    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 testBranchNotEqualNotEqual()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    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>(
+        proc, Equal, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0),
+        equalOrUnordered);
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        notEqualAndOrdered,
+        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(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));
+    Value* equalOrUnordered = root->appendNew<Value>(
+        proc, EqualOrUnordered, Origin(),
+        argumentA,
+        argumentB);
+    Value* notEqualAndOrdered = root->appendNew<Value>(
+        proc, Equal, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0),
+        equalOrUnordered);
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        notEqualAndOrdered,
+        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 testBranchEqualOrUnorderedDoubleArgImm(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<ConstDoubleValue>(proc, Origin(), b);
+    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) == expected);
+}
+
+void testBranchEqualOrUnorderedFloatArgImm(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<ConstFloatValue>(proc, Origin(), b);
+
+    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) == expected);
+}
+
+void testBranchEqualOrUnorderedDoubleImms(double a, double b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* argumentA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+    Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
+    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) == expected);
+}
+
+void testBranchEqualOrUnorderedFloatImms(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* argumentA = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+    Value* argumentB = root->appendNew<ConstFloatValue>(proc, Origin(), b);
+
+    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) == expected);
+}
+
+void testBranchEqualOrUnorderedFloatWithUselessDoubleConversion(float a, float b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    Value* argument1 = root->appendNew<MemoryValue>(proc, Load, Float, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argument2 = root->appendNew<MemoryValue>(proc, Load, Float, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* argument1AsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argument1);
+    Value* argument2AsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argument2);
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, EqualOrUnordered, Origin(),
+            argument1AsDouble,
+            argument2AsDouble),
+        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 testBranchFold(int value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), value),
+        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));
+
+    CHECK(compileAndRun<int>(proc) == !!value);
+}
+
+void testDiamondFold(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(),
+        root->appendNew<Const32Value>(proc, Origin(), value),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    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));
+
+    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
+    thenResult->setPhi(phi);
+    elseResult->setPhi(phi);
+    done->appendNew<ControlValue>(proc, Return, Origin(), phi);
+
+    CHECK(compileAndRun<int>(proc) == !!value);
+}
+
+void testBranchNotEqualFoldPtr(intptr_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, NotEqual, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), value),
+            root->appendNew<ConstPtrValue>(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));
+
+    CHECK(compileAndRun<int>(proc) == !!value);
+}
+
+void testBranchEqualFoldPtr(intptr_t value)
+{
+    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<ConstPtrValue>(proc, Origin(), value),
+            root->appendNew<ConstPtrValue>(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));
+
+    CHECK(compileAndRun<int>(proc) == !value);
+}
+
+void testBranchLoadPtr()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, pointerType(), 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));
+
+    auto code = compile(proc);
+    intptr_t cond;
+    cond = 42;
+    CHECK(invoke<int>(*code, &cond) == 1);
+    cond = 0;
+    CHECK(invoke<int>(*code, &cond) == 0);
+}
+
+void testBranchLoad32()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load, Int32, 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));
+
+    auto code = compile(proc);
+    int32_t cond;
+    cond = 42;
+    CHECK(invoke<int>(*code, &cond) == 1);
+    cond = 0;
+    CHECK(invoke<int>(*code, &cond) == 0);
+}
+
+void testBranchLoad8S()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load8S, 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));
+
+    auto code = compile(proc);
+    int8_t cond;
+    cond = -1;
+    CHECK(invoke<int>(*code, &cond) == 1);
+    cond = 0;
+    CHECK(invoke<int>(*code, &cond) == 0);
+}
+
+void testBranchLoad8Z()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load8Z, 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));
+
+    auto code = compile(proc);
+    uint8_t cond;
+    cond = 1;
+    CHECK(invoke<int>(*code, &cond) == 1);
+    cond = 0;
+    CHECK(invoke<int>(*code, &cond) == 0);
+}
+
+void testBranchLoad16S()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load16S, 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));
+
+    auto code = compile(proc);
+    int16_t cond;
+    cond = -1;
+    CHECK(invoke<int>(*code, &cond) == 1);
+    cond = 0;
+    CHECK(invoke<int>(*code, &cond) == 0);
+}
+
+void testBranchLoad16Z()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<MemoryValue>(
+            proc, Load16Z, 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));
+
+    auto code = compile(proc);
+    uint16_t cond;
+    cond = 1;
+    CHECK(invoke<int>(*code, &cond) == 1);
+    cond = 0;
+    CHECK(invoke<int>(*code, &cond) == 0);
+}
+
+void testComplex(unsigned numVars, unsigned numConstructs)
+{
+    double before = monotonicallyIncreasingTimeMS();
+    
+    Procedure proc;
+    BasicBlock* current = proc.addBlock();
+
+    Const32Value* one = current->appendNew<Const32Value>(proc, Origin(), 1);
+
+    Vector<int32_t> varSlots;
+    for (unsigned i = numVars; i--;)
+        varSlots.append(i);
+
+    Vector<Value*> vars;
+    for (int32_t& varSlot : varSlots) {
+        Value* varSlotPtr = current->appendNew<ConstPtrValue>(proc, Origin(), &varSlot);
+        vars.append(current->appendNew<MemoryValue>(proc, Load, Int32, Origin(), varSlotPtr));
+    }
+
+    for (unsigned i = 0; i < numConstructs; ++i) {
+        if (i & 1) {
+            // Control flow diamond.
+            unsigned predicateVarIndex = ((i >> 1) + 2) % numVars;
+            unsigned thenIncVarIndex = ((i >> 1) + 0) % numVars;
+            unsigned elseIncVarIndex = ((i >> 1) + 1) % numVars;
+
+            BasicBlock* thenBlock = proc.addBlock();
+            BasicBlock* elseBlock = proc.addBlock();
+            BasicBlock* continuation = proc.addBlock();
+
+            current->appendNew<ControlValue>(
+                proc, Branch, Origin(), vars[predicateVarIndex],
+                FrequentedBlock(thenBlock), FrequentedBlock(elseBlock));
+
+            UpsilonValue* thenThenResult = thenBlock->appendNew<UpsilonValue>(
+                proc, Origin(),
+                thenBlock->appendNew<Value>(proc, Add, Origin(), vars[thenIncVarIndex], one));
+            UpsilonValue* thenElseResult = thenBlock->appendNew<UpsilonValue>(
+                proc, Origin(), vars[elseIncVarIndex]);
+            thenBlock->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation));
+
+            UpsilonValue* elseElseResult = elseBlock->appendNew<UpsilonValue>(
+                proc, Origin(),
+                elseBlock->appendNew<Value>(proc, Add, Origin(), vars[elseIncVarIndex], one));
+            UpsilonValue* elseThenResult = elseBlock->appendNew<UpsilonValue>(
+                proc, Origin(), vars[thenIncVarIndex]);
+            elseBlock->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation));
+
+            Value* thenPhi = continuation->appendNew<Value>(proc, Phi, Int32, Origin());
+            thenThenResult->setPhi(thenPhi);
+            elseThenResult->setPhi(thenPhi);
+            vars[thenIncVarIndex] = thenPhi;
+            
+            Value* elsePhi = continuation->appendNew<Value>(proc, Phi, Int32, Origin());
+            thenElseResult->setPhi(elsePhi);
+            elseElseResult->setPhi(elsePhi);
+            vars[elseIncVarIndex] = thenPhi;
+            
+            current = continuation;
+        } else {
+            // Loop.
+
+            BasicBlock* loopEntry = proc.addBlock();
+            BasicBlock* loopReentry = proc.addBlock();
+            BasicBlock* loopBody = proc.addBlock();
+            BasicBlock* loopExit = proc.addBlock();
+            BasicBlock* loopSkip = proc.addBlock();
+            BasicBlock* continuation = proc.addBlock();
+            
+            Value* startIndex = vars[((i >> 1) + 1) % numVars];
+            Value* startSum = current->appendNew<Const32Value>(proc, Origin(), 0);
+            current->appendNew<ControlValue>(
+                proc, Branch, Origin(), startIndex,
+                FrequentedBlock(loopEntry), FrequentedBlock(loopSkip));
+
+            UpsilonValue* startIndexForBody = loopEntry->appendNew<UpsilonValue>(
+                proc, Origin(), startIndex);
+            UpsilonValue* startSumForBody = loopEntry->appendNew<UpsilonValue>(
+                proc, Origin(), startSum);
+            loopEntry->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loopBody));
+
+            Value* bodyIndex = loopBody->appendNew<Value>(proc, Phi, Int32, Origin());
+            startIndexForBody->setPhi(bodyIndex);
+            Value* bodySum = loopBody->appendNew<Value>(proc, Phi, Int32, Origin());
+            startSumForBody->setPhi(bodySum);
+            Value* newBodyIndex = loopBody->appendNew<Value>(proc, Sub, Origin(), bodyIndex, one);
+            Value* newBodySum = loopBody->appendNew<Value>(
+                proc, Add, Origin(),
+                bodySum,
+                loopBody->appendNew<MemoryValue>(
+                    proc, Load, Int32, Origin(),
+                    loopBody->appendNew<Value>(
+                        proc, Add, Origin(),
+                        loopBody->appendNew<ConstPtrValue>(proc, Origin(), varSlots.data()),
+                        loopBody->appendNew<Value>(
+                            proc, Shl, Origin(),
+                            loopBody->appendNew<Value>(
+                                proc, ZExt32, Origin(),
+                                loopBody->appendNew<Value>(
+                                    proc, BitAnd, Origin(),
+                                    newBodyIndex,
+                                    loopBody->appendNew<Const32Value>(
+                                        proc, Origin(), numVars - 1))),
+                            loopBody->appendNew<Const32Value>(proc, Origin(), 2)))));
+            loopBody->appendNew<ControlValue>(
+                proc, Branch, Origin(), newBodyIndex,
+                FrequentedBlock(loopReentry), FrequentedBlock(loopExit));
+
+            loopReentry->appendNew<UpsilonValue>(proc, Origin(), newBodyIndex, bodyIndex);
+            loopReentry->appendNew<UpsilonValue>(proc, Origin(), newBodySum, bodySum);
+            loopReentry->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loopBody));
+
+            UpsilonValue* exitSum = loopExit->appendNew<UpsilonValue>(proc, Origin(), newBodySum);
+            loopExit->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation));
+
+            UpsilonValue* skipSum = loopSkip->appendNew<UpsilonValue>(proc, Origin(), startSum);
+            loopSkip->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation));
+
+            Value* finalSum = continuation->appendNew<Value>(proc, Phi, Int32, Origin());
+            exitSum->setPhi(finalSum);
+            skipSum->setPhi(finalSum);
+
+            current = continuation;
+            vars[((i >> 1) + 0) % numVars] = finalSum;
+        }
+    }
+
+    current->appendNew<ControlValue>(proc, Return, Origin(), vars[0]);
+
+    compile(proc);
+
+    double after = monotonicallyIncreasingTimeMS();
+    dataLog(toCString("    That took ", after - before, " ms.\n"));
+}
+
+void testSimplePatchpoint()
+{
+    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(ConstrainedValue(arg1, ValueRep::SomeRegister));
+    patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            CHECK(params[2].isGPR());
+            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 testSimplePatchpointWithoutOuputClobbersGPArgs()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 42);
+    Value* const2 = root->appendNew<Const64Value>(proc, Origin(), 13);
+
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
+    patchpoint->clobberLate(RegisterSet(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1));
+    patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister));
+    patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), params[0].gpr());
+            jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), params[1].gpr());
+            jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), GPRInfo::argumentGPR0);
+            jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), GPRInfo::argumentGPR1);
+        });
+
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), arg1, arg2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
+void testSimplePatchpointWithOuputClobbersGPArgs()
+{
+    // We can't predict where the output will be but we want to be sure it is not
+    // one of the clobbered registers which is a bit hard to test.
+    //
+    // What we do is force the hand of our register allocator by clobbering absolutely
+    // everything but 1. The only valid allocation is to give it to the result and
+    // spill everything else.
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 42);
+    Value* const2 = root->appendNew<Const64Value>(proc, Origin(), 13);
+
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int64, Origin());
+
+    RegisterSet clobberAll = RegisterSet::allGPRs();
+    clobberAll.exclude(RegisterSet::stackRegisters());
+    clobberAll.exclude(RegisterSet::reservedHardwareRegisters());
+    clobberAll.clear(GPRInfo::argumentGPR2);
+    patchpoint->clobberLate(clobberAll);
+
+    patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister));
+    patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister));
+
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            CHECK(params[2].isGPR());
+            jit.move(params[1].gpr(), params[0].gpr());
+            jit.add64(params[2].gpr(), params[0].gpr());
+
+            clobberAll.forEach([&] (Reg reg) {
+                jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), reg.gpr());
+            });
+        });
+
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), patchpoint,
+        root->appendNew<Value>(proc, Add, Origin(), arg1, arg2));
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int>(proc, 1, 2) == 58);
+}
+
+void testSimplePatchpointWithoutOuputClobbersFPArgs()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+    Value* const1 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5);
+    Value* const2 = root->appendNew<ConstDoubleValue>(proc, Origin(), 13.1);
+
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
+    patchpoint->clobberLate(RegisterSet(FPRInfo::argumentFPR0, FPRInfo::argumentFPR1));
+    patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister));
+    patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 2);
+            CHECK(params[0].isFPR());
+            CHECK(params[1].isFPR());
+            jit.moveZeroToDouble(params[0].fpr());
+            jit.moveZeroToDouble(params[1].fpr());
+            jit.moveZeroToDouble(FPRInfo::argumentFPR0);
+            jit.moveZeroToDouble(FPRInfo::argumentFPR1);
+        });
+
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), arg1, arg2);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<double>(proc, 1.5, 2.5) == 4);
+}
+
+void testSimplePatchpointWithOuputClobbersFPArgs()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+    Value* const1 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5);
+    Value* const2 = root->appendNew<ConstDoubleValue>(proc, Origin(), 13.1);
+
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Double, Origin());
+
+    RegisterSet clobberAll = RegisterSet::allFPRs();
+    clobberAll.exclude(RegisterSet::stackRegisters());
+    clobberAll.exclude(RegisterSet::reservedHardwareRegisters());
+    clobberAll.clear(FPRInfo::argumentFPR2);
+    patchpoint->clobberLate(clobberAll);
+
+    patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister));
+    patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister));
+
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0].isFPR());
+            CHECK(params[1].isFPR());
+            CHECK(params[2].isFPR());
+            jit.addDouble(params[1].fpr(), params[2].fpr(), params[0].fpr());
+
+            clobberAll.forEach([&] (Reg reg) {
+                jit.moveZeroToDouble(reg.fpr());
+            });
+        });
+
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), patchpoint,
+        root->appendNew<Value>(proc, Add, Origin(), arg1, arg2));
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<double>(proc, 1.5, 2.5) == 59.6);
+}
+
+void testPatchpointWithEarlyClobber()
+{
+    auto test = [] (GPRReg registerToClobber, bool arg1InArgGPR, bool arg2InArgGPR) {
+        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(ConstrainedValue(arg1, ValueRep::SomeRegister));
+        patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        patchpoint->clobberEarly(RegisterSet(registerToClobber));
+        patchpoint->setGenerator(
+            [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                CHECK((params[1].gpr() == GPRInfo::argumentGPR0) == arg1InArgGPR);
+                CHECK((params[2].gpr() == GPRInfo::argumentGPR1) == arg2InArgGPR);
+                
+                add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr());
+            });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+        CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+    };
+
+    test(GPRInfo::nonArgGPR0, true, true);
+    test(GPRInfo::argumentGPR0, false, true);
+    test(GPRInfo::argumentGPR1, true, false);
+}
+
+void testPatchpointCallArg()
+{
+    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(ConstrainedValue(arg1, ValueRep::stackArgument(0)));
+    patchpoint->append(ConstrainedValue(arg2, ValueRep::stackArgument(8)));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isStack());
+            CHECK(params[2].isStack());
+            jit.load32(
+                CCallHelpers::Address(GPRInfo::callFrameRegister, params[1].offsetFromFP()),
+                params[0].gpr());
+            jit.add32(
+                CCallHelpers::Address(GPRInfo::callFrameRegister, params[2].offsetFromFP()),
+                params[0].gpr());
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
+void testPatchpointFixedRegister()
+{
+    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(ConstrainedValue(arg1, ValueRep(GPRInfo::regT0)));
+    patchpoint->append(ConstrainedValue(arg2, ValueRep(GPRInfo::regT1)));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0].isGPR());
+            CHECK(params[1] == ValueRep(GPRInfo::regT0));
+            CHECK(params[2] == ValueRep(GPRInfo::regT1));
+            add32(jit, GPRInfo::regT0, GPRInfo::regT1, params[0].gpr());
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
+void testPatchpointAny(ValueRep rep)
+{
+    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(ConstrainedValue(arg1, rep));
+    patchpoint->append(ConstrainedValue(arg2, rep));
+    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());
+            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 testPatchpointGPScratch()
+{
+    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->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() == 3);
+            CHECK(params[0].isGPR());
+            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);
+
+    CHECK(compileAndRun<int>(proc) == (things.size() * (things.size() - 1)) / 2);
+}
+
+void testPatchpointAnyImm(ValueRep rep)
+{
+    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);
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
+    patchpoint->append(ConstrainedValue(arg1, rep));
+    patchpoint->append(ConstrainedValue(arg2, rep));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0].isGPR());
+            CHECK(params[1].isGPR());
+            CHECK(params[2].isConstant());
+            CHECK(params[2].value() == 42);
+            jit.add32(
+                CCallHelpers::TrustedImm32(static_cast<int32_t>(params[2].value())),
+                params[1].gpr(), params[0].gpr());
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun<int>(proc, 1) == 43);
+}
+
+void testPatchpointManyImms()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), 42);
+    Value* arg2 = root->appendNew<Const64Value>(proc, Origin(), 43);
+    Value* arg3 = root->appendNew<Const64Value>(proc, Origin(), 43000000000000ll);
+    Value* arg4 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5);
+    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
+    patchpoint->append(ConstrainedValue(arg1, ValueRep::WarmAny));
+    patchpoint->append(ConstrainedValue(arg2, ValueRep::WarmAny));
+    patchpoint->append(ConstrainedValue(arg3, ValueRep::WarmAny));
+    patchpoint->append(ConstrainedValue(arg4, ValueRep::WarmAny));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers&, const StackmapGenerationParams& params) {
+            CHECK(params.size() == 4);
+            CHECK(params[0] == ValueRep::constant(42));
+            CHECK(params[1] == ValueRep::constant(43));
+            CHECK(params[2] == ValueRep::constant(43000000000000ll));
+            CHECK(params[3] == ValueRep::constant(bitwise_cast<int64_t>(42.5)));
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(!compileAndRun<int>(proc));
+}
+
+void testPatchpointWithRegisterResult()
+{
+    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(ConstrainedValue(arg1, ValueRep::SomeRegister));
+    patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+    patchpoint->resultConstraint = ValueRep::reg(GPRInfo::nonArgGPR0);
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0] == ValueRep::reg(GPRInfo::nonArgGPR0));
+            CHECK(params[1].isGPR());
+            CHECK(params[2].isGPR());
+            add32(jit, params[1].gpr(), params[2].gpr(), GPRInfo::nonArgGPR0);
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
+void testPatchpointWithStackArgumentResult()
+{
+    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(ConstrainedValue(arg1, ValueRep::SomeRegister));
+    patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+    patchpoint->resultConstraint = ValueRep::stackArgument(0);
+    patchpoint->clobber(RegisterSet::macroScratchRegisters());
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0] == ValueRep::stack(-static_cast<intptr_t>(proc.frameSize())));
+            CHECK(params[1].isGPR());
+            CHECK(params[2].isGPR());
+            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);
+
+    CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
+void testPatchpointWithAnyResult()
+{
+    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, Double, Origin());
+    patchpoint->append(ConstrainedValue(arg1, ValueRep::SomeRegister));
+    patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+    patchpoint->resultConstraint = ValueRep::WarmAny;
+    patchpoint->clobberLate(RegisterSet::allFPRs());
+    patchpoint->clobber(RegisterSet::macroScratchRegisters());
+    patchpoint->clobber(RegisterSet(GPRInfo::regT0));
+    patchpoint->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.size() == 3);
+            CHECK(params[0].isStack());
+            CHECK(params[1].isGPR());
+            CHECK(params[2].isGPR());
+            add32(jit, params[1].gpr(), params[2].gpr(), GPRInfo::regT0);
+            jit.convertInt32ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
+            jit.storeDouble(FPRInfo::fpRegT0, CCallHelpers::Address(GPRInfo::callFrameRegister, params[0].offsetFromFP()));
+        });
+    root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun<double>(proc, 1, 2) == 3);
+}
+
+void testSimpleCheck()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    CheckValue* check = root->appendNew<CheckValue>(proc, Check, Origin(), arg);
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            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, 0) == 0);
+    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;
+    BasicBlock* root = proc.addBlock();
+    Value* arg = root->appendNew<Value>(
+        proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    CheckValue* check = root->appendNew<CheckValue>(
+        proc, Check, Origin(),
+        root->appendNew<Value>(
+            proc, LessThan, Origin(), arg,
+            root->appendNew<Const32Value>(proc, Origin(), 42)));
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            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) == 0);
+    CHECK(invoke<int>(*code, 1000) == 0);
+    CHECK(invoke<int>(*code, 41) == 42);
+    CHECK(invoke<int>(*code, 0) == 42);
+    CHECK(invoke<int>(*code, -1) == 42);
+}
+
+void testCheckMegaCombo()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* index = root->appendNew<Value>(
+        proc, ZExt32, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+
+    Value* ptr = root->appendNew<Value>(
+        proc, Add, Origin(), base,
+        root->appendNew<Value>(
+            proc, Shl, Origin(), index,
+            root->appendNew<Const32Value>(proc, Origin(), 1)));
+    
+    CheckValue* check = root->appendNew<CheckValue>(
+        proc, Check, Origin(),
+        root->appendNew<Value>(
+            proc, LessThan, Origin(),
+            root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr),
+            root->appendNew<Const32Value>(proc, Origin(), 42)));
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            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);
+
+    int8_t value;
+    value = 42;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 0);
+    value = 127;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 0);
+    value = 41;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
+    value = 0;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
+    value = -1;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
+}
+
+void testCheckTrickyMegaCombo()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* index = root->appendNew<Value>(
+        proc, ZExt32, Origin(),
+        root->appendNew<Value>(
+            proc, Add, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)),
+            root->appendNew<Const32Value>(proc, Origin(), 1)));
+
+    Value* ptr = root->appendNew<Value>(
+        proc, Add, Origin(), base,
+        root->appendNew<Value>(
+            proc, Shl, Origin(), index,
+            root->appendNew<Const32Value>(proc, Origin(), 1)));
+    
+    CheckValue* check = root->appendNew<CheckValue>(
+        proc, Check, Origin(),
+        root->appendNew<Value>(
+            proc, LessThan, Origin(),
+            root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr),
+            root->appendNew<Const32Value>(proc, Origin(), 42)));
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            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);
+
+    int8_t value;
+    value = 42;
+    CHECK(invoke<int>(*code, &value - 2, 0) == 0);
+    value = 127;
+    CHECK(invoke<int>(*code, &value - 2, 0) == 0);
+    value = 41;
+    CHECK(invoke<int>(*code, &value - 2, 0) == 42);
+    value = 0;
+    CHECK(invoke<int>(*code, &value - 2, 0) == 42);
+    value = -1;
+    CHECK(invoke<int>(*code, &value - 2, 0) == 42);
+}
+
+void testCheckTwoMegaCombos()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* index = root->appendNew<Value>(
+        proc, ZExt32, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+
+    Value* ptr = root->appendNew<Value>(
+        proc, Add, Origin(), base,
+        root->appendNew<Value>(
+            proc, Shl, Origin(), index,
+            root->appendNew<Const32Value>(proc, Origin(), 1)));
+
+    Value* predicate = root->appendNew<Value>(
+        proc, LessThan, Origin(),
+        root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr),
+        root->appendNew<Const32Value>(proc, Origin(), 42));
+    
+    CheckValue* check = root->appendNew<CheckValue>(proc, Check, Origin(), predicate);
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            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();
+        });
+    CheckValue* check2 = root->appendNew<CheckValue>(proc, Check, Origin(), predicate);
+    check2->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(!params.size());
+
+            // This should always work because a function this simple should never have callee
+            // saves.
+            jit.move(CCallHelpers::TrustedImm32(43), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+
+    int8_t value;
+    value = 42;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 0);
+    value = 127;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 0);
+    value = 41;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
+    value = 0;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
+    value = -1;
+    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
+}
+
+void testCheckTwoNonRedundantMegaCombos()
+{
+    Procedure proc;
+    
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+    
+    Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* index = root->appendNew<Value>(
+        proc, ZExt32, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+    Value* branchPredicate = root->appendNew<Value>(
+        proc, BitAnd, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)),
+        root->appendNew<Const32Value>(proc, Origin(), 0xff));
+
+    Value* ptr = root->appendNew<Value>(
+        proc, Add, Origin(), base,
+        root->appendNew<Value>(
+            proc, Shl, Origin(), index,
+            root->appendNew<Const32Value>(proc, Origin(), 1)));
+
+    Value* checkPredicate = root->appendNew<Value>(
+        proc, LessThan, Origin(),
+        root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr),
+        root->appendNew<Const32Value>(proc, Origin(), 42));
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(), branchPredicate,
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+    
+    CheckValue* check = thenCase->appendNew<CheckValue>(proc, Check, Origin(), checkPredicate);
+    check->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            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();
+        });
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 43));
+
+    CheckValue* check2 = elseCase->appendNew<CheckValue>(proc, Check, Origin(), checkPredicate);
+    check2->setGenerator(
+        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(!params.size());
+
+            // This should always work because a function this simple should never have callee
+            // saves.
+            jit.move(CCallHelpers::TrustedImm32(44), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 45));
+
+    auto code = compile(proc);
+
+    int8_t value;
+
+    value = 42;
+    CHECK(invoke<int>(*code, &value - 2, 1, true) == 43);
+    value = 127;
+    CHECK(invoke<int>(*code, &value - 2, 1, true) == 43);
+    value = 41;
+    CHECK(invoke<int>(*code, &value - 2, 1, true) == 42);
+    value = 0;
+    CHECK(invoke<int>(*code, &value - 2, 1, true) == 42);
+    value = -1;
+    CHECK(invoke<int>(*code, &value - 2, 1, true) == 42);
+
+    value = 42;
+    CHECK(invoke<int>(*code, &value - 2, 1, false) == 45);
+    value = 127;
+    CHECK(invoke<int>(*code, &value - 2, 1, false) == 45);
+    value = 41;
+    CHECK(invoke<int>(*code, &value - 2, 1, false) == 44);
+    value = 0;
+    CHECK(invoke<int>(*code, &value - 2, 1, false) == 44);
+    value = -1;
+    CHECK(invoke<int>(*code, &value - 2, 1, false) == 44);
+}
+
+void testCheckAddImm()
+{
+    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* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
+    checkAdd->append(arg1);
+    checkAdd->append(arg2);
+    checkAdd->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.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+  &nb