Split testb3 into multiple files
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Aug 2019 01:01:53 +0000 (01:01 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Aug 2019 01:01:53 +0000 (01:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=200326

Reviewed by Keith Miller.

* JavaScriptCore.xcodeproj/project.pbxproj:
* b3/testb3.cpp: Removed.
* b3/testb3.h: Added.
(hiddenTruthBecauseNoReturnIsStupid):
(usage):
(shouldBeVerbose):
(compileProc):
(invoke):
(compileAndRun):
(lowerToAirForTesting):
(checkDisassembly):
(checkUsesInstruction):
(checkDoesNotUseInstruction):
(populateWithInterestingValues):
(floatingPointOperands):
(int64Operands):
(int32Operands):
(add32):
(modelLoad):
(float>):
(double>):
* b3/testb3_1.cpp: Added.
(zero):
(negativeZero):
(shouldRun):
(testRotR):
(testRotL):
(testRotRWithImmShift):
(testRotLWithImmShift):
(testComputeDivisionMagic):
(run):
(main):
(dllLauncherEntryPoint):
* b3/testb3_2.cpp: Added.
(test42):
(testLoad42):
(testLoadAcq42):
(testLoadWithOffsetImpl):
(testLoadOffsetImm9Max):
(testLoadOffsetImm9MaxPlusOne):
(testLoadOffsetImm9MaxPlusTwo):
(testLoadOffsetImm9Min):
(testLoadOffsetImm9MinMinusOne):
(testLoadOffsetScaledUnsignedImm12Max):
(testLoadOffsetScaledUnsignedOverImm12Max):
(testBitXorTreeArgs):
(testBitXorTreeArgsEven):
(testBitXorTreeArgImm):
(testAddTreeArg32):
(testMulTreeArg32):
(testBitAndTreeArg32):
(testBitOrTreeArg32):
(testArg):
(testReturnConst64):
(testReturnVoid):
(testAddArg):
(testAddArgs):
(testAddArgImm):
(testAddImmArg):
(testAddArgMem):
(testAddMemArg):
(testAddImmMem):
(testAddArg32):
(testAddArgs32):
(testAddArgMem32):
(testAddMemArg32):
(testAddImmMem32):
(testAddNeg1):
(testAddNeg2):
(testAddArgZeroImmZDef):
(testAddLoadTwice):
(testAddArgDouble):
(testAddArgsDouble):
(testAddArgImmDouble):
(testAddImmArgDouble):
(testAddImmsDouble):
(testAddArgFloat):
(testAddArgsFloat):
(testAddFPRArgsFloat):
(testAddArgImmFloat):
(testAddImmArgFloat):
(testAddImmsFloat):
(testAddArgFloatWithUselessDoubleConversion):
(testAddArgsFloatWithUselessDoubleConversion):
(testAddArgsFloatWithEffectfulDoubleConversion):
(testAddMulMulArgs):
(testMulArg):
(testMulArgStore):
(testMulAddArg):
(testMulArgs):
(testMulArgNegArg):
(testMulNegArgArg):
(testMulArgImm):
(testMulImmArg):
(testMulArgs32):
(testMulArgs32SignExtend):
(testMulImm32SignExtend):
(testMulLoadTwice):
(testMulAddArgsLeft):
(testMulAddArgsRight):
(testMulAddArgsLeft32):
(testMulAddArgsRight32):
(testMulSubArgsLeft):
(testMulSubArgsRight):
(testMulSubArgsLeft32):
(testMulSubArgsRight32):
(testMulNegArgs):
(testMulNegArgs32):
(testMulArgDouble):
(testMulArgsDouble):
(testMulArgImmDouble):
(testMulImmArgDouble):
(testMulImmsDouble):
(testMulArgFloat):
(testMulArgsFloat):
(testMulArgImmFloat):
(testMulImmArgFloat):
(testMulImmsFloat):
(testMulArgFloatWithUselessDoubleConversion):
(testMulArgsFloatWithUselessDoubleConversion):
(testMulArgsFloatWithEffectfulDoubleConversion):
(testDivArgDouble):
(testDivArgsDouble):
(testDivArgImmDouble):
(testDivImmArgDouble):
(testDivImmsDouble):
(testDivArgFloat):
(testDivArgsFloat):
(testDivArgImmFloat):
(testDivImmArgFloat):
(testDivImmsFloat):
(testModArgDouble):
(testModArgsDouble):
(testModArgImmDouble):
(testModImmArgDouble):
(testModImmsDouble):
(testModArgFloat):
(testModArgsFloat):
(testModArgImmFloat):
(testModImmArgFloat):
(testModImmsFloat):
(testDivArgFloatWithUselessDoubleConversion):
(testDivArgsFloatWithUselessDoubleConversion):
(testDivArgsFloatWithEffectfulDoubleConversion):
(testUDivArgsInt32):
(testUDivArgsInt64):
(testUModArgsInt32):
(testUModArgsInt64):
(testSubArg):
(testSubArgs):
(testSubArgImm):
(testSubNeg):
(testNegSub):
(testNegValueSubOne):
(testSubSub):
(testSubSub2):
(testSubAdd):
(testSubFirstNeg):
(testSubImmArg):
(testSubArgMem):
(testSubMemArg):
(testSubImmMem):
(testSubMemImm):
(testSubArgs32):
(testSubArgImm32):
(testSubImmArg32):
(testSubMemArg32):
(testSubArgMem32):
(testSubImmMem32):
(testSubMemImm32):
(testNegValueSubOne32):
(testNegMulArgImm):
(testSubMulMulArgs):
(testSubArgDouble):
(testSubArgsDouble):
(testSubArgImmDouble):
(testSubImmArgDouble):
(testSubImmsDouble):
(testSubArgFloat):
(testSubArgsFloat):
(testSubArgImmFloat):
(testSubImmArgFloat):
(testSubImmsFloat):
(testSubArgFloatWithUselessDoubleConversion):
(testSubArgsFloatWithUselessDoubleConversion):
(testSubArgsFloatWithEffectfulDoubleConversion):
(testTernarySubInstructionSelection):
(testNegDouble):
(testNegFloat):
(testNegFloatWithUselessDoubleConversion):
(testBitAndArgs):
(testBitAndSameArg):
(testBitAndNotNot):
(testBitAndNotImm):
(testBitAndImms):
(testBitAndArgImm):
(testBitAndImmArg):
(testBitAndBitAndArgImmImm):
(testBitAndImmBitAndArgImm):
(testBitAndArgs32):
(testBitAndSameArg32):
(testBitAndImms32):
(testBitAndArgImm32):
(testBitAndImmArg32):
(testBitAndBitAndArgImmImm32):
(testBitAndImmBitAndArgImm32):
(testBitAndWithMaskReturnsBooleans):
(bitAndDouble):
(testBitAndArgDouble):
(testBitAndArgsDouble):
(testBitAndArgImmDouble):
(testBitAndImmsDouble):
(bitAndFloat):
(testBitAndArgFloat):
(testBitAndArgsFloat):
(testBitAndArgImmFloat):
(testBitAndImmsFloat):
(testBitAndArgsFloatWithUselessDoubleConversion):
(testBitOrArgs):
(testBitOrSameArg):
(testBitOrAndAndArgs):
(testBitOrAndSameArgs):
(testBitOrNotNot):
(testBitOrNotImm):
(testBitOrImms):
(testBitOrArgImm):
(testBitOrImmArg):
(testBitOrBitOrArgImmImm):
(testBitOrImmBitOrArgImm):
(testBitOrArgs32):
(testBitOrSameArg32):
(testBitOrImms32):
(testBitOrArgImm32):
(testBitOrImmArg32):
* b3/testb3_3.cpp: Added.
(testBitOrBitOrArgImmImm32):
(testBitOrImmBitOrArgImm32):
(bitOrDouble):
(testBitOrArgDouble):
(testBitOrArgsDouble):
(testBitOrArgImmDouble):
(testBitOrImmsDouble):
(bitOrFloat):
(testBitOrArgFloat):
(testBitOrArgsFloat):
(testBitOrArgImmFloat):
(testBitOrImmsFloat):
(testBitOrArgsFloatWithUselessDoubleConversion):
(testBitXorArgs):
(testBitXorSameArg):
(testBitXorAndAndArgs):
(testBitXorAndSameArgs):
(testBitXorImms):
(testBitXorArgImm):
(testBitXorImmArg):
(testBitXorBitXorArgImmImm):
(testBitXorImmBitXorArgImm):
(testBitXorArgs32):
(testBitXorSameArg32):
(testBitXorImms32):
(testBitXorArgImm32):
(testBitXorImmArg32):
(testBitXorBitXorArgImmImm32):
(testBitXorImmBitXorArgImm32):
(testBitNotArg):
(testBitNotImm):
(testBitNotMem):
(testBitNotArg32):
(testBitNotImm32):
(testBitNotMem32):
(testNotOnBooleanAndBranch32):
(testBitNotOnBooleanAndBranch32):
(testShlArgs):
(testShlImms):
(testShlArgImm):
(testShlSShrArgImm):
(testShlArg32):
(testShlArgs32):
(testShlImms32):
(testShlArgImm32):
(testShlZShrArgImm32):
(testSShrArgs):
(testSShrImms):
(testSShrArgImm):
(testSShrArg32):
(testSShrArgs32):
(testSShrImms32):
(testSShrArgImm32):
(testZShrArgs):
(testZShrImms):
(testZShrArgImm):
(testZShrArg32):
(testZShrArgs32):
(testZShrImms32):
(testZShrArgImm32):
(countLeadingZero):
(testClzArg64):
(testClzMem64):
(testClzArg32):
(testClzMem32):
(testAbsArg):
(testAbsImm):
(testAbsMem):
(testAbsAbsArg):
(testAbsNegArg):
(testAbsBitwiseCastArg):
(testBitwiseCastAbsBitwiseCastArg):
(testAbsArgWithUselessDoubleConversion):
(testAbsArgWithEffectfulDoubleConversion):
(testCeilArg):
(testCeilImm):
(testCeilMem):
(testCeilCeilArg):
(testFloorCeilArg):
(testCeilIToD64):
(testCeilIToD32):
(testCeilArgWithUselessDoubleConversion):
(testCeilArgWithEffectfulDoubleConversion):
(testFloorArg):
(testFloorImm):
(testFloorMem):
(testFloorFloorArg):
(testCeilFloorArg):
(testFloorIToD64):
(testFloorIToD32):
(testFloorArgWithUselessDoubleConversion):
(testFloorArgWithEffectfulDoubleConversion):
(correctSqrt):
(testSqrtArg):
(testSqrtImm):
(testSqrtMem):
(testSqrtArgWithUselessDoubleConversion):
(testSqrtArgWithEffectfulDoubleConversion):
(testCompareTwoFloatToDouble):
(testCompareOneFloatToDouble):
(testCompareFloatToDoubleThroughPhi):
(testDoubleToFloatThroughPhi):
(testReduceFloatToDoubleValidates):
(testDoubleProducerPhiToFloatConversion):
(testDoubleProducerPhiToFloatConversionWithDoubleConsumer):
(testDoubleProducerPhiWithNonFloatConst):
(testDoubleArgToInt64BitwiseCast):
(testDoubleImmToInt64BitwiseCast):
(testTwoBitwiseCastOnDouble):
(testBitwiseCastOnDoubleInMemory):
(testBitwiseCastOnDoubleInMemoryIndexed):
(testInt64BArgToDoubleBitwiseCast):
(testInt64BImmToDoubleBitwiseCast):
(testTwoBitwiseCastOnInt64):
(testBitwiseCastOnInt64InMemory):
(testBitwiseCastOnInt64InMemoryIndexed):
(testFloatImmToInt32BitwiseCast):
(testBitwiseCastOnFloatInMemory):
(testInt32BArgToFloatBitwiseCast):
(testInt32BImmToFloatBitwiseCast):
(testTwoBitwiseCastOnInt32):
(testBitwiseCastOnInt32InMemory):
(testConvertDoubleToFloatArg):
(testConvertDoubleToFloatImm):
(testConvertDoubleToFloatMem):
(testConvertFloatToDoubleArg):
(testConvertFloatToDoubleImm):
(testConvertFloatToDoubleMem):
(testConvertDoubleToFloatToDoubleToFloat):
(testLoadFloatConvertDoubleConvertFloatStoreFloat):
(testFroundArg):
(testFroundMem):
(testIToD64Arg):
(testIToF64Arg):
(testIToD32Arg):
(testIToF32Arg):
(testIToD64Mem):
(testIToF64Mem):
(testIToD32Mem):
(testIToF32Mem):
(testIToD64Imm):
(testIToF64Imm):
(testIToD32Imm):
(testIToF32Imm):
(testIToDReducedToIToF64Arg):
(testIToDReducedToIToF32Arg):
(testStore32):
(testStoreConstant):
(testStoreConstantPtr):
(testStore8Arg):
(testStore8Imm):
(testStorePartial8BitRegisterOnX86):
(testStore16Arg):
(testStore16Imm):
(testTrunc):
(testAdd1):
(testAdd1Ptr):
(testNeg32):
(testNegPtr):
(testStoreAddLoad32):
* b3/testb3_4.cpp: Added.
(testStoreRelAddLoadAcq32):
(testStoreAddLoadImm32):
(testStoreAddLoad8):
(testStoreRelAddLoadAcq8):
(testStoreRelAddFenceLoadAcq8):
(testStoreAddLoadImm8):
(testStoreAddLoad16):
(testStoreRelAddLoadAcq16):
(testStoreAddLoadImm16):
(testStoreAddLoad64):
(testStoreRelAddLoadAcq64):
(testStoreAddLoadImm64):
(testStoreAddLoad32Index):
(testStoreAddLoadImm32Index):
(testStoreAddLoad8Index):
(testStoreAddLoadImm8Index):
(testStoreAddLoad16Index):
(testStoreAddLoadImm16Index):
(testStoreAddLoad64Index):
(testStoreAddLoadImm64Index):
(testStoreSubLoad):
(testStoreAddLoadInterference):
(testStoreAddAndLoad):
(testStoreNegLoad32):
(testStoreNegLoadPtr):
(testAdd1Uncommuted):
(testLoadOffset):
(testLoadOffsetNotConstant):
(testLoadOffsetUsingAdd):
(testLoadOffsetUsingAddInterference):
(testLoadOffsetUsingAddNotConstant):
(testLoadAddrShift):
(testFramePointer):
(testOverrideFramePointer):
(testStackSlot):
(testLoadFromFramePointer):
(testStoreLoadStackSlot):
(testStoreFloat):
(testStoreDoubleConstantAsFloat):
(testSpillGP):
(testSpillFP):
(testInt32ToDoublePartialRegisterStall):
(testInt32ToDoublePartialRegisterWithoutStall):
(testBranch):
(testBranchPtr):
(testDiamond):
(testBranchNotEqual):
(testBranchNotEqualCommute):
(testBranchNotEqualNotEqual):
(testBranchEqual):
(testBranchEqualEqual):
(testBranchEqualCommute):
(testBranchEqualEqual1):
(testBranchEqualOrUnorderedArgs):
(testBranchNotEqualAndOrderedArgs):
(testBranchEqualOrUnorderedDoubleArgImm):
(testBranchEqualOrUnorderedFloatArgImm):
(testBranchEqualOrUnorderedDoubleImms):
(testBranchEqualOrUnorderedFloatImms):
(testBranchEqualOrUnorderedFloatWithUselessDoubleConversion):
(testBranchFold):
(testDiamondFold):
(testBranchNotEqualFoldPtr):
(testBranchEqualFoldPtr):
(testBranchLoadPtr):
(testBranchLoad32):
(testBranchLoad8S):
(testBranchLoad8Z):
(testBranchLoad16S):
(testBranchLoad16Z):
(testBranch8WithLoad8ZIndex):
(testComplex):
(testBranchBitTest32TmpImm):
(testBranchBitTest32AddrImm):
(testBranchBitTest32TmpTmp):
(testBranchBitTest64TmpTmp):
(testBranchBitTest64AddrTmp):
(testBranchBitTestNegation):
(testBranchBitTestNegation2):
(testSimplePatchpoint):
(testSimplePatchpointWithoutOuputClobbersGPArgs):
(testSimplePatchpointWithOuputClobbersGPArgs):
(testSimplePatchpointWithoutOuputClobbersFPArgs):
(testSimplePatchpointWithOuputClobbersFPArgs):
(testPatchpointWithEarlyClobber):
(testPatchpointCallArg):
(testPatchpointFixedRegister):
(testPatchpointAny):
(testPatchpointGPScratch):
(testPatchpointFPScratch):
(testPatchpointLotsOfLateAnys):
(testPatchpointAnyImm):
* b3/testb3_5.cpp: Added.
(testPatchpointManyImms):
(testPatchpointWithRegisterResult):
(testPatchpointWithStackArgumentResult):
(testPatchpointWithAnyResult):
(testSimpleCheck):
(testCheckFalse):
(testCheckTrue):
(testCheckLessThan):
(testCheckMegaCombo):
(testCheckTrickyMegaCombo):
(testCheckTwoMegaCombos):
(testCheckTwoNonRedundantMegaCombos):
(testCheckAddImm):
(testCheckAddImmCommute):
(testCheckAddImmSomeRegister):
(testCheckAdd):
(testCheckAdd64):
(testCheckAddFold):
(testCheckAddFoldFail):
(testCheckAddArgumentAliasing64):
(testCheckAddArgumentAliasing32):
(testCheckAddSelfOverflow64):
(testCheckAddSelfOverflow32):
(testCheckSubImm):
(testCheckSubBadImm):
(testCheckSub):
(doubleSub):
(testCheckSub64):
(testCheckSubFold):
(testCheckSubFoldFail):
(testCheckNeg):
(testCheckNeg64):
(testCheckMul):
(testCheckMulMemory):
(testCheckMul2):
(testCheckMul64):
(testCheckMulFold):
(testCheckMulFoldFail):
(testCheckMulArgumentAliasing64):
(testCheckMulArgumentAliasing32):
(testCheckMul64SShr):
(genericTestCompare):
(modelCompare):
(testCompareLoad):
(testCompareImpl):
(testCompare):
(testEqualDouble):
(simpleFunction):
(testCallSimple):
(testCallRare):
(testCallRareLive):
(testCallSimplePure):
(functionWithHellaArguments):
(testCallFunctionWithHellaArguments):
(functionWithHellaArguments2):
(testCallFunctionWithHellaArguments2):
(functionWithHellaArguments3):
(testCallFunctionWithHellaArguments3):
(testReturnDouble):
(testReturnFloat):
(simpleFunctionDouble):
(testCallSimpleDouble):
(simpleFunctionFloat):
(testCallSimpleFloat):
(functionWithHellaDoubleArguments):
(testCallFunctionWithHellaDoubleArguments):
(functionWithHellaFloatArguments):
(testCallFunctionWithHellaFloatArguments):
(testLinearScanWithCalleeOnStack):
(testChillDiv):
(testChillDivTwice):
(testChillDiv64):
(testModArg):
(testModArgs):
(testModImms):
(testModArg32):
(testModArgs32):
(testModImms32):
(testChillModArg):
(testChillModArgs):
(testChillModImms):
(testChillModArg32):
(testChillModArgs32):
(testChillModImms32):
(testLoopWithMultipleHeaderEdges):
(testSwitch):
(testSwitchSameCaseAsDefault):
(testSwitchChillDiv):
(testSwitchTargettingSameBlock):
(testSwitchTargettingSameBlockFoldPathConstant):
(testTruncFold):
(testZExt32):
(testZExt32Fold):
(testSExt32):
(testSExt32Fold):
(testTruncZExt32):
(testTruncSExt32):
(testSExt8):
(testSExt8Fold):
(testSExt8SExt8):
(testSExt8SExt16):
(testSExt8BitAnd):
(testBitAndSExt8):
(testSExt16):
(testSExt16Fold):
(testSExt16SExt16):
(testSExt16SExt8):
(testSExt16BitAnd):
(testBitAndSExt16):
(testSExt32BitAnd):
* b3/testb3_6.cpp: Added.
(testBitAndSExt32):
(testBasicSelect):
(testSelectTest):
(testSelectCompareDouble):
(testSelectCompareFloat):
(testSelectCompareFloatToDouble):
(testSelectDouble):
(testSelectDoubleTest):
(testSelectDoubleCompareDouble):
(testSelectDoubleCompareFloat):
(testSelectFloatCompareFloat):
(testSelectDoubleCompareDoubleWithAliasing):
(testSelectFloatCompareFloatWithAliasing):
(testSelectFold):
(testSelectInvert):
(testCheckSelect):
(testCheckSelectCheckSelect):
(testCheckSelectAndCSE):
(b3Pow):
(testPowDoubleByIntegerLoop):
(testTruncOrHigh):
(testTruncOrLow):
(testBitAndOrHigh):
(testBitAndOrLow):
(testBranch64Equal):
(testBranch64EqualImm):
(testBranch64EqualMem):
(testBranch64EqualMemImm):
(testStore8Load8Z):
(testStore16Load16Z):
(testSShrShl32):
(testSShrShl64):
(testTrivialInfiniteLoop):
(testFoldPathEqual):
(testLShiftSelf32):
(testRShiftSelf32):
(testURShiftSelf32):
(testLShiftSelf64):
(testRShiftSelf64):
(testURShiftSelf64):
(testPatchpointDoubleRegs):
(testSpillDefSmallerThanUse):
(testSpillUseLargerThanDef):
(testLateRegister):
(interpreterPrint):
(testInterpreter):
(testReduceStrengthCheckBottomUseInAnotherBlock):
(testResetReachabilityDanglingReference):
(testEntrySwitchSimple):
(testEntrySwitchNoEntrySwitch):
(testEntrySwitchWithCommonPaths):
(testEntrySwitchWithCommonPathsAndNonTrivialEntrypoint):
(testEntrySwitchLoop):
(testSomeEarlyRegister):
(testBranchBitAndImmFusion):
(testTerminalPatchpointThatNeedsToBeSpilled):
(testTerminalPatchpointThatNeedsToBeSpilled2):
(testPatchpointTerminalReturnValue):
(testMemoryFence):
(testStoreFence):
(testLoadFence):
(testTrappingLoad):
(testTrappingStore):
(testTrappingLoadAddStore):
(testTrappingLoadDCE):
(testTrappingStoreElimination):
(testMoveConstants):
(testPCOriginMapDoesntInsertNops):
* b3/testb3_7.cpp: Added.
(testPinRegisters):
(testX86LeaAddAddShlLeft):
(testX86LeaAddAddShlRight):
(testX86LeaAddAdd):
(testX86LeaAddShlRight):
(testX86LeaAddShlLeftScale1):
(testX86LeaAddShlLeftScale2):
(testX86LeaAddShlLeftScale4):
(testX86LeaAddShlLeftScale8):
(testAddShl32):
(testAddShl64):
(testAddShl65):
(testReduceStrengthReassociation):
(testLoadBaseIndexShift2):
(testLoadBaseIndexShift32):
(testOptimizeMaterialization):
(generateLoop):
(makeArrayForLoops):
(generateLoopNotBackwardsDominant):
(oneFunction):
(noOpFunction):
(testLICMPure):
(testLICMPureSideExits):
(testLICMPureWritesPinned):
(testLICMPureWrites):
(testLICMReadsLocalState):
(testLICMReadsPinned):
(testLICMReads):
(testLICMPureNotBackwardsDominant):
(testLICMPureFoiledByChild):
(testLICMPureNotBackwardsDominantFoiledByChild):
(testLICMExitsSideways):
(testLICMWritesLocalState):
(testLICMWrites):
(testLICMFence):
(testLICMWritesPinned):
(testLICMControlDependent):
(testLICMControlDependentNotBackwardsDominant):
(testLICMControlDependentSideExits):
(testLICMReadsPinnedWritesPinned):
(testLICMReadsWritesDifferentHeaps):
(testLICMReadsWritesOverlappingHeaps):
(testLICMDefaultCall):
(testDepend32):
(testDepend64):
(testWasmBoundsCheck):
(testWasmAddress):
(testFastTLSLoad):
(testFastTLSStore):
(doubleEq):
(doubleNeq):
(doubleGt):
(doubleGte):
(doubleLt):
(doubleLte):
(testDoubleLiteralComparison):
(testFloatEqualOrUnorderedFolding):
(testFloatEqualOrUnorderedFoldingNaN):
(testFloatEqualOrUnorderedDontFold):
(functionNineArgs):
(testShuffleDoesntTrashCalleeSaves):
(testDemotePatchpointTerminal):
(testReportUsedRegistersLateUseFollowedByEarlyDefDoesNotMarkUseAsDead):
(testInfiniteLoopDoesntCauseBadHoisting):
* b3/testb3_8.cpp: Added.
(testAtomicWeakCAS):
(testAtomicStrongCAS):
(testAtomicXchg):
(addAtomicTests):
(testLoad):
(addLoadTests):

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

13 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/b3/testb3.cpp [deleted file]
Source/JavaScriptCore/b3/testb3.h [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3_1.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3_2.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3_3.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3_4.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3_5.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3_6.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3_7.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3_8.cpp [new file with mode: 0644]
Source/JavaScriptCore/shell/CMakeLists.txt

index a84b563..27bc829 100644 (file)
@@ -1,3 +1,751 @@
+2019-07-31  Alex Christensen  <achristensen@webkit.org>
+
+        Split testb3 into multiple files
+        https://bugs.webkit.org/show_bug.cgi?id=200326
+
+        Reviewed by Keith Miller.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * b3/testb3.cpp: Removed.
+        * b3/testb3.h: Added.
+        (hiddenTruthBecauseNoReturnIsStupid):
+        (usage):
+        (shouldBeVerbose):
+        (compileProc):
+        (invoke):
+        (compileAndRun):
+        (lowerToAirForTesting):
+        (checkDisassembly):
+        (checkUsesInstruction):
+        (checkDoesNotUseInstruction):
+        (populateWithInterestingValues):
+        (floatingPointOperands):
+        (int64Operands):
+        (int32Operands):
+        (add32):
+        (modelLoad):
+        (float>):
+        (double>):
+        * b3/testb3_1.cpp: Added.
+        (zero):
+        (negativeZero):
+        (shouldRun):
+        (testRotR):
+        (testRotL):
+        (testRotRWithImmShift):
+        (testRotLWithImmShift):
+        (testComputeDivisionMagic):
+        (run):
+        (main):
+        (dllLauncherEntryPoint):
+        * b3/testb3_2.cpp: Added.
+        (test42):
+        (testLoad42):
+        (testLoadAcq42):
+        (testLoadWithOffsetImpl):
+        (testLoadOffsetImm9Max):
+        (testLoadOffsetImm9MaxPlusOne):
+        (testLoadOffsetImm9MaxPlusTwo):
+        (testLoadOffsetImm9Min):
+        (testLoadOffsetImm9MinMinusOne):
+        (testLoadOffsetScaledUnsignedImm12Max):
+        (testLoadOffsetScaledUnsignedOverImm12Max):
+        (testBitXorTreeArgs):
+        (testBitXorTreeArgsEven):
+        (testBitXorTreeArgImm):
+        (testAddTreeArg32):
+        (testMulTreeArg32):
+        (testBitAndTreeArg32):
+        (testBitOrTreeArg32):
+        (testArg):
+        (testReturnConst64):
+        (testReturnVoid):
+        (testAddArg):
+        (testAddArgs):
+        (testAddArgImm):
+        (testAddImmArg):
+        (testAddArgMem):
+        (testAddMemArg):
+        (testAddImmMem):
+        (testAddArg32):
+        (testAddArgs32):
+        (testAddArgMem32):
+        (testAddMemArg32):
+        (testAddImmMem32):
+        (testAddNeg1):
+        (testAddNeg2):
+        (testAddArgZeroImmZDef):
+        (testAddLoadTwice):
+        (testAddArgDouble):
+        (testAddArgsDouble):
+        (testAddArgImmDouble):
+        (testAddImmArgDouble):
+        (testAddImmsDouble):
+        (testAddArgFloat):
+        (testAddArgsFloat):
+        (testAddFPRArgsFloat):
+        (testAddArgImmFloat):
+        (testAddImmArgFloat):
+        (testAddImmsFloat):
+        (testAddArgFloatWithUselessDoubleConversion):
+        (testAddArgsFloatWithUselessDoubleConversion):
+        (testAddArgsFloatWithEffectfulDoubleConversion):
+        (testAddMulMulArgs):
+        (testMulArg):
+        (testMulArgStore):
+        (testMulAddArg):
+        (testMulArgs):
+        (testMulArgNegArg):
+        (testMulNegArgArg):
+        (testMulArgImm):
+        (testMulImmArg):
+        (testMulArgs32):
+        (testMulArgs32SignExtend):
+        (testMulImm32SignExtend):
+        (testMulLoadTwice):
+        (testMulAddArgsLeft):
+        (testMulAddArgsRight):
+        (testMulAddArgsLeft32):
+        (testMulAddArgsRight32):
+        (testMulSubArgsLeft):
+        (testMulSubArgsRight):
+        (testMulSubArgsLeft32):
+        (testMulSubArgsRight32):
+        (testMulNegArgs):
+        (testMulNegArgs32):
+        (testMulArgDouble):
+        (testMulArgsDouble):
+        (testMulArgImmDouble):
+        (testMulImmArgDouble):
+        (testMulImmsDouble):
+        (testMulArgFloat):
+        (testMulArgsFloat):
+        (testMulArgImmFloat):
+        (testMulImmArgFloat):
+        (testMulImmsFloat):
+        (testMulArgFloatWithUselessDoubleConversion):
+        (testMulArgsFloatWithUselessDoubleConversion):
+        (testMulArgsFloatWithEffectfulDoubleConversion):
+        (testDivArgDouble):
+        (testDivArgsDouble):
+        (testDivArgImmDouble):
+        (testDivImmArgDouble):
+        (testDivImmsDouble):
+        (testDivArgFloat):
+        (testDivArgsFloat):
+        (testDivArgImmFloat):
+        (testDivImmArgFloat):
+        (testDivImmsFloat):
+        (testModArgDouble):
+        (testModArgsDouble):
+        (testModArgImmDouble):
+        (testModImmArgDouble):
+        (testModImmsDouble):
+        (testModArgFloat):
+        (testModArgsFloat):
+        (testModArgImmFloat):
+        (testModImmArgFloat):
+        (testModImmsFloat):
+        (testDivArgFloatWithUselessDoubleConversion):
+        (testDivArgsFloatWithUselessDoubleConversion):
+        (testDivArgsFloatWithEffectfulDoubleConversion):
+        (testUDivArgsInt32):
+        (testUDivArgsInt64):
+        (testUModArgsInt32):
+        (testUModArgsInt64):
+        (testSubArg):
+        (testSubArgs):
+        (testSubArgImm):
+        (testSubNeg):
+        (testNegSub):
+        (testNegValueSubOne):
+        (testSubSub):
+        (testSubSub2):
+        (testSubAdd):
+        (testSubFirstNeg):
+        (testSubImmArg):
+        (testSubArgMem):
+        (testSubMemArg):
+        (testSubImmMem):
+        (testSubMemImm):
+        (testSubArgs32):
+        (testSubArgImm32):
+        (testSubImmArg32):
+        (testSubMemArg32):
+        (testSubArgMem32):
+        (testSubImmMem32):
+        (testSubMemImm32):
+        (testNegValueSubOne32):
+        (testNegMulArgImm):
+        (testSubMulMulArgs):
+        (testSubArgDouble):
+        (testSubArgsDouble):
+        (testSubArgImmDouble):
+        (testSubImmArgDouble):
+        (testSubImmsDouble):
+        (testSubArgFloat):
+        (testSubArgsFloat):
+        (testSubArgImmFloat):
+        (testSubImmArgFloat):
+        (testSubImmsFloat):
+        (testSubArgFloatWithUselessDoubleConversion):
+        (testSubArgsFloatWithUselessDoubleConversion):
+        (testSubArgsFloatWithEffectfulDoubleConversion):
+        (testTernarySubInstructionSelection):
+        (testNegDouble):
+        (testNegFloat):
+        (testNegFloatWithUselessDoubleConversion):
+        (testBitAndArgs):
+        (testBitAndSameArg):
+        (testBitAndNotNot):
+        (testBitAndNotImm):
+        (testBitAndImms):
+        (testBitAndArgImm):
+        (testBitAndImmArg):
+        (testBitAndBitAndArgImmImm):
+        (testBitAndImmBitAndArgImm):
+        (testBitAndArgs32):
+        (testBitAndSameArg32):
+        (testBitAndImms32):
+        (testBitAndArgImm32):
+        (testBitAndImmArg32):
+        (testBitAndBitAndArgImmImm32):
+        (testBitAndImmBitAndArgImm32):
+        (testBitAndWithMaskReturnsBooleans):
+        (bitAndDouble):
+        (testBitAndArgDouble):
+        (testBitAndArgsDouble):
+        (testBitAndArgImmDouble):
+        (testBitAndImmsDouble):
+        (bitAndFloat):
+        (testBitAndArgFloat):
+        (testBitAndArgsFloat):
+        (testBitAndArgImmFloat):
+        (testBitAndImmsFloat):
+        (testBitAndArgsFloatWithUselessDoubleConversion):
+        (testBitOrArgs):
+        (testBitOrSameArg):
+        (testBitOrAndAndArgs):
+        (testBitOrAndSameArgs):
+        (testBitOrNotNot):
+        (testBitOrNotImm):
+        (testBitOrImms):
+        (testBitOrArgImm):
+        (testBitOrImmArg):
+        (testBitOrBitOrArgImmImm):
+        (testBitOrImmBitOrArgImm):
+        (testBitOrArgs32):
+        (testBitOrSameArg32):
+        (testBitOrImms32):
+        (testBitOrArgImm32):
+        (testBitOrImmArg32):
+        * b3/testb3_3.cpp: Added.
+        (testBitOrBitOrArgImmImm32):
+        (testBitOrImmBitOrArgImm32):
+        (bitOrDouble):
+        (testBitOrArgDouble):
+        (testBitOrArgsDouble):
+        (testBitOrArgImmDouble):
+        (testBitOrImmsDouble):
+        (bitOrFloat):
+        (testBitOrArgFloat):
+        (testBitOrArgsFloat):
+        (testBitOrArgImmFloat):
+        (testBitOrImmsFloat):
+        (testBitOrArgsFloatWithUselessDoubleConversion):
+        (testBitXorArgs):
+        (testBitXorSameArg):
+        (testBitXorAndAndArgs):
+        (testBitXorAndSameArgs):
+        (testBitXorImms):
+        (testBitXorArgImm):
+        (testBitXorImmArg):
+        (testBitXorBitXorArgImmImm):
+        (testBitXorImmBitXorArgImm):
+        (testBitXorArgs32):
+        (testBitXorSameArg32):
+        (testBitXorImms32):
+        (testBitXorArgImm32):
+        (testBitXorImmArg32):
+        (testBitXorBitXorArgImmImm32):
+        (testBitXorImmBitXorArgImm32):
+        (testBitNotArg):
+        (testBitNotImm):
+        (testBitNotMem):
+        (testBitNotArg32):
+        (testBitNotImm32):
+        (testBitNotMem32):
+        (testNotOnBooleanAndBranch32):
+        (testBitNotOnBooleanAndBranch32):
+        (testShlArgs):
+        (testShlImms):
+        (testShlArgImm):
+        (testShlSShrArgImm):
+        (testShlArg32):
+        (testShlArgs32):
+        (testShlImms32):
+        (testShlArgImm32):
+        (testShlZShrArgImm32):
+        (testSShrArgs):
+        (testSShrImms):
+        (testSShrArgImm):
+        (testSShrArg32):
+        (testSShrArgs32):
+        (testSShrImms32):
+        (testSShrArgImm32):
+        (testZShrArgs):
+        (testZShrImms):
+        (testZShrArgImm):
+        (testZShrArg32):
+        (testZShrArgs32):
+        (testZShrImms32):
+        (testZShrArgImm32):
+        (countLeadingZero):
+        (testClzArg64):
+        (testClzMem64):
+        (testClzArg32):
+        (testClzMem32):
+        (testAbsArg):
+        (testAbsImm):
+        (testAbsMem):
+        (testAbsAbsArg):
+        (testAbsNegArg):
+        (testAbsBitwiseCastArg):
+        (testBitwiseCastAbsBitwiseCastArg):
+        (testAbsArgWithUselessDoubleConversion):
+        (testAbsArgWithEffectfulDoubleConversion):
+        (testCeilArg):
+        (testCeilImm):
+        (testCeilMem):
+        (testCeilCeilArg):
+        (testFloorCeilArg):
+        (testCeilIToD64):
+        (testCeilIToD32):
+        (testCeilArgWithUselessDoubleConversion):
+        (testCeilArgWithEffectfulDoubleConversion):
+        (testFloorArg):
+        (testFloorImm):
+        (testFloorMem):
+        (testFloorFloorArg):
+        (testCeilFloorArg):
+        (testFloorIToD64):
+        (testFloorIToD32):
+        (testFloorArgWithUselessDoubleConversion):
+        (testFloorArgWithEffectfulDoubleConversion):
+        (correctSqrt):
+        (testSqrtArg):
+        (testSqrtImm):
+        (testSqrtMem):
+        (testSqrtArgWithUselessDoubleConversion):
+        (testSqrtArgWithEffectfulDoubleConversion):
+        (testCompareTwoFloatToDouble):
+        (testCompareOneFloatToDouble):
+        (testCompareFloatToDoubleThroughPhi):
+        (testDoubleToFloatThroughPhi):
+        (testReduceFloatToDoubleValidates):
+        (testDoubleProducerPhiToFloatConversion):
+        (testDoubleProducerPhiToFloatConversionWithDoubleConsumer):
+        (testDoubleProducerPhiWithNonFloatConst):
+        (testDoubleArgToInt64BitwiseCast):
+        (testDoubleImmToInt64BitwiseCast):
+        (testTwoBitwiseCastOnDouble):
+        (testBitwiseCastOnDoubleInMemory):
+        (testBitwiseCastOnDoubleInMemoryIndexed):
+        (testInt64BArgToDoubleBitwiseCast):
+        (testInt64BImmToDoubleBitwiseCast):
+        (testTwoBitwiseCastOnInt64):
+        (testBitwiseCastOnInt64InMemory):
+        (testBitwiseCastOnInt64InMemoryIndexed):
+        (testFloatImmToInt32BitwiseCast):
+        (testBitwiseCastOnFloatInMemory):
+        (testInt32BArgToFloatBitwiseCast):
+        (testInt32BImmToFloatBitwiseCast):
+        (testTwoBitwiseCastOnInt32):
+        (testBitwiseCastOnInt32InMemory):
+        (testConvertDoubleToFloatArg):
+        (testConvertDoubleToFloatImm):
+        (testConvertDoubleToFloatMem):
+        (testConvertFloatToDoubleArg):
+        (testConvertFloatToDoubleImm):
+        (testConvertFloatToDoubleMem):
+        (testConvertDoubleToFloatToDoubleToFloat):
+        (testLoadFloatConvertDoubleConvertFloatStoreFloat):
+        (testFroundArg):
+        (testFroundMem):
+        (testIToD64Arg):
+        (testIToF64Arg):
+        (testIToD32Arg):
+        (testIToF32Arg):
+        (testIToD64Mem):
+        (testIToF64Mem):
+        (testIToD32Mem):
+        (testIToF32Mem):
+        (testIToD64Imm):
+        (testIToF64Imm):
+        (testIToD32Imm):
+        (testIToF32Imm):
+        (testIToDReducedToIToF64Arg):
+        (testIToDReducedToIToF32Arg):
+        (testStore32):
+        (testStoreConstant):
+        (testStoreConstantPtr):
+        (testStore8Arg):
+        (testStore8Imm):
+        (testStorePartial8BitRegisterOnX86):
+        (testStore16Arg):
+        (testStore16Imm):
+        (testTrunc):
+        (testAdd1):
+        (testAdd1Ptr):
+        (testNeg32):
+        (testNegPtr):
+        (testStoreAddLoad32):
+        * b3/testb3_4.cpp: Added.
+        (testStoreRelAddLoadAcq32):
+        (testStoreAddLoadImm32):
+        (testStoreAddLoad8):
+        (testStoreRelAddLoadAcq8):
+        (testStoreRelAddFenceLoadAcq8):
+        (testStoreAddLoadImm8):
+        (testStoreAddLoad16):
+        (testStoreRelAddLoadAcq16):
+        (testStoreAddLoadImm16):
+        (testStoreAddLoad64):
+        (testStoreRelAddLoadAcq64):
+        (testStoreAddLoadImm64):
+        (testStoreAddLoad32Index):
+        (testStoreAddLoadImm32Index):
+        (testStoreAddLoad8Index):
+        (testStoreAddLoadImm8Index):
+        (testStoreAddLoad16Index):
+        (testStoreAddLoadImm16Index):
+        (testStoreAddLoad64Index):
+        (testStoreAddLoadImm64Index):
+        (testStoreSubLoad):
+        (testStoreAddLoadInterference):
+        (testStoreAddAndLoad):
+        (testStoreNegLoad32):
+        (testStoreNegLoadPtr):
+        (testAdd1Uncommuted):
+        (testLoadOffset):
+        (testLoadOffsetNotConstant):
+        (testLoadOffsetUsingAdd):
+        (testLoadOffsetUsingAddInterference):
+        (testLoadOffsetUsingAddNotConstant):
+        (testLoadAddrShift):
+        (testFramePointer):
+        (testOverrideFramePointer):
+        (testStackSlot):
+        (testLoadFromFramePointer):
+        (testStoreLoadStackSlot):
+        (testStoreFloat):
+        (testStoreDoubleConstantAsFloat):
+        (testSpillGP):
+        (testSpillFP):
+        (testInt32ToDoublePartialRegisterStall):
+        (testInt32ToDoublePartialRegisterWithoutStall):
+        (testBranch):
+        (testBranchPtr):
+        (testDiamond):
+        (testBranchNotEqual):
+        (testBranchNotEqualCommute):
+        (testBranchNotEqualNotEqual):
+        (testBranchEqual):
+        (testBranchEqualEqual):
+        (testBranchEqualCommute):
+        (testBranchEqualEqual1):
+        (testBranchEqualOrUnorderedArgs):
+        (testBranchNotEqualAndOrderedArgs):
+        (testBranchEqualOrUnorderedDoubleArgImm):
+        (testBranchEqualOrUnorderedFloatArgImm):
+        (testBranchEqualOrUnorderedDoubleImms):
+        (testBranchEqualOrUnorderedFloatImms):
+        (testBranchEqualOrUnorderedFloatWithUselessDoubleConversion):
+        (testBranchFold):
+        (testDiamondFold):
+        (testBranchNotEqualFoldPtr):
+        (testBranchEqualFoldPtr):
+        (testBranchLoadPtr):
+        (testBranchLoad32):
+        (testBranchLoad8S):
+        (testBranchLoad8Z):
+        (testBranchLoad16S):
+        (testBranchLoad16Z):
+        (testBranch8WithLoad8ZIndex):
+        (testComplex):
+        (testBranchBitTest32TmpImm):
+        (testBranchBitTest32AddrImm):
+        (testBranchBitTest32TmpTmp):
+        (testBranchBitTest64TmpTmp):
+        (testBranchBitTest64AddrTmp):
+        (testBranchBitTestNegation):
+        (testBranchBitTestNegation2):
+        (testSimplePatchpoint):
+        (testSimplePatchpointWithoutOuputClobbersGPArgs):
+        (testSimplePatchpointWithOuputClobbersGPArgs):
+        (testSimplePatchpointWithoutOuputClobbersFPArgs):
+        (testSimplePatchpointWithOuputClobbersFPArgs):
+        (testPatchpointWithEarlyClobber):
+        (testPatchpointCallArg):
+        (testPatchpointFixedRegister):
+        (testPatchpointAny):
+        (testPatchpointGPScratch):
+        (testPatchpointFPScratch):
+        (testPatchpointLotsOfLateAnys):
+        (testPatchpointAnyImm):
+        * b3/testb3_5.cpp: Added.
+        (testPatchpointManyImms):
+        (testPatchpointWithRegisterResult):
+        (testPatchpointWithStackArgumentResult):
+        (testPatchpointWithAnyResult):
+        (testSimpleCheck):
+        (testCheckFalse):
+        (testCheckTrue):
+        (testCheckLessThan):
+        (testCheckMegaCombo):
+        (testCheckTrickyMegaCombo):
+        (testCheckTwoMegaCombos):
+        (testCheckTwoNonRedundantMegaCombos):
+        (testCheckAddImm):
+        (testCheckAddImmCommute):
+        (testCheckAddImmSomeRegister):
+        (testCheckAdd):
+        (testCheckAdd64):
+        (testCheckAddFold):
+        (testCheckAddFoldFail):
+        (testCheckAddArgumentAliasing64):
+        (testCheckAddArgumentAliasing32):
+        (testCheckAddSelfOverflow64):
+        (testCheckAddSelfOverflow32):
+        (testCheckSubImm):
+        (testCheckSubBadImm):
+        (testCheckSub):
+        (doubleSub):
+        (testCheckSub64):
+        (testCheckSubFold):
+        (testCheckSubFoldFail):
+        (testCheckNeg):
+        (testCheckNeg64):
+        (testCheckMul):
+        (testCheckMulMemory):
+        (testCheckMul2):
+        (testCheckMul64):
+        (testCheckMulFold):
+        (testCheckMulFoldFail):
+        (testCheckMulArgumentAliasing64):
+        (testCheckMulArgumentAliasing32):
+        (testCheckMul64SShr):
+        (genericTestCompare):
+        (modelCompare):
+        (testCompareLoad):
+        (testCompareImpl):
+        (testCompare):
+        (testEqualDouble):
+        (simpleFunction):
+        (testCallSimple):
+        (testCallRare):
+        (testCallRareLive):
+        (testCallSimplePure):
+        (functionWithHellaArguments):
+        (testCallFunctionWithHellaArguments):
+        (functionWithHellaArguments2):
+        (testCallFunctionWithHellaArguments2):
+        (functionWithHellaArguments3):
+        (testCallFunctionWithHellaArguments3):
+        (testReturnDouble):
+        (testReturnFloat):
+        (simpleFunctionDouble):
+        (testCallSimpleDouble):
+        (simpleFunctionFloat):
+        (testCallSimpleFloat):
+        (functionWithHellaDoubleArguments):
+        (testCallFunctionWithHellaDoubleArguments):
+        (functionWithHellaFloatArguments):
+        (testCallFunctionWithHellaFloatArguments):
+        (testLinearScanWithCalleeOnStack):
+        (testChillDiv):
+        (testChillDivTwice):
+        (testChillDiv64):
+        (testModArg):
+        (testModArgs):
+        (testModImms):
+        (testModArg32):
+        (testModArgs32):
+        (testModImms32):
+        (testChillModArg):
+        (testChillModArgs):
+        (testChillModImms):
+        (testChillModArg32):
+        (testChillModArgs32):
+        (testChillModImms32):
+        (testLoopWithMultipleHeaderEdges):
+        (testSwitch):
+        (testSwitchSameCaseAsDefault):
+        (testSwitchChillDiv):
+        (testSwitchTargettingSameBlock):
+        (testSwitchTargettingSameBlockFoldPathConstant):
+        (testTruncFold):
+        (testZExt32):
+        (testZExt32Fold):
+        (testSExt32):
+        (testSExt32Fold):
+        (testTruncZExt32):
+        (testTruncSExt32):
+        (testSExt8):
+        (testSExt8Fold):
+        (testSExt8SExt8):
+        (testSExt8SExt16):
+        (testSExt8BitAnd):
+        (testBitAndSExt8):
+        (testSExt16):
+        (testSExt16Fold):
+        (testSExt16SExt16):
+        (testSExt16SExt8):
+        (testSExt16BitAnd):
+        (testBitAndSExt16):
+        (testSExt32BitAnd):
+        * b3/testb3_6.cpp: Added.
+        (testBitAndSExt32):
+        (testBasicSelect):
+        (testSelectTest):
+        (testSelectCompareDouble):
+        (testSelectCompareFloat):
+        (testSelectCompareFloatToDouble):
+        (testSelectDouble):
+        (testSelectDoubleTest):
+        (testSelectDoubleCompareDouble):
+        (testSelectDoubleCompareFloat):
+        (testSelectFloatCompareFloat):
+        (testSelectDoubleCompareDoubleWithAliasing):
+        (testSelectFloatCompareFloatWithAliasing):
+        (testSelectFold):
+        (testSelectInvert):
+        (testCheckSelect):
+        (testCheckSelectCheckSelect):
+        (testCheckSelectAndCSE):
+        (b3Pow):
+        (testPowDoubleByIntegerLoop):
+        (testTruncOrHigh):
+        (testTruncOrLow):
+        (testBitAndOrHigh):
+        (testBitAndOrLow):
+        (testBranch64Equal):
+        (testBranch64EqualImm):
+        (testBranch64EqualMem):
+        (testBranch64EqualMemImm):
+        (testStore8Load8Z):
+        (testStore16Load16Z):
+        (testSShrShl32):
+        (testSShrShl64):
+        (testTrivialInfiniteLoop):
+        (testFoldPathEqual):
+        (testLShiftSelf32):
+        (testRShiftSelf32):
+        (testURShiftSelf32):
+        (testLShiftSelf64):
+        (testRShiftSelf64):
+        (testURShiftSelf64):
+        (testPatchpointDoubleRegs):
+        (testSpillDefSmallerThanUse):
+        (testSpillUseLargerThanDef):
+        (testLateRegister):
+        (interpreterPrint):
+        (testInterpreter):
+        (testReduceStrengthCheckBottomUseInAnotherBlock):
+        (testResetReachabilityDanglingReference):
+        (testEntrySwitchSimple):
+        (testEntrySwitchNoEntrySwitch):
+        (testEntrySwitchWithCommonPaths):
+        (testEntrySwitchWithCommonPathsAndNonTrivialEntrypoint):
+        (testEntrySwitchLoop):
+        (testSomeEarlyRegister):
+        (testBranchBitAndImmFusion):
+        (testTerminalPatchpointThatNeedsToBeSpilled):
+        (testTerminalPatchpointThatNeedsToBeSpilled2):
+        (testPatchpointTerminalReturnValue):
+        (testMemoryFence):
+        (testStoreFence):
+        (testLoadFence):
+        (testTrappingLoad):
+        (testTrappingStore):
+        (testTrappingLoadAddStore):
+        (testTrappingLoadDCE):
+        (testTrappingStoreElimination):
+        (testMoveConstants):
+        (testPCOriginMapDoesntInsertNops):
+        * b3/testb3_7.cpp: Added.
+        (testPinRegisters):
+        (testX86LeaAddAddShlLeft):
+        (testX86LeaAddAddShlRight):
+        (testX86LeaAddAdd):
+        (testX86LeaAddShlRight):
+        (testX86LeaAddShlLeftScale1):
+        (testX86LeaAddShlLeftScale2):
+        (testX86LeaAddShlLeftScale4):
+        (testX86LeaAddShlLeftScale8):
+        (testAddShl32):
+        (testAddShl64):
+        (testAddShl65):
+        (testReduceStrengthReassociation):
+        (testLoadBaseIndexShift2):
+        (testLoadBaseIndexShift32):
+        (testOptimizeMaterialization):
+        (generateLoop):
+        (makeArrayForLoops):
+        (generateLoopNotBackwardsDominant):
+        (oneFunction):
+        (noOpFunction):
+        (testLICMPure):
+        (testLICMPureSideExits):
+        (testLICMPureWritesPinned):
+        (testLICMPureWrites):
+        (testLICMReadsLocalState):
+        (testLICMReadsPinned):
+        (testLICMReads):
+        (testLICMPureNotBackwardsDominant):
+        (testLICMPureFoiledByChild):
+        (testLICMPureNotBackwardsDominantFoiledByChild):
+        (testLICMExitsSideways):
+        (testLICMWritesLocalState):
+        (testLICMWrites):
+        (testLICMFence):
+        (testLICMWritesPinned):
+        (testLICMControlDependent):
+        (testLICMControlDependentNotBackwardsDominant):
+        (testLICMControlDependentSideExits):
+        (testLICMReadsPinnedWritesPinned):
+        (testLICMReadsWritesDifferentHeaps):
+        (testLICMReadsWritesOverlappingHeaps):
+        (testLICMDefaultCall):
+        (testDepend32):
+        (testDepend64):
+        (testWasmBoundsCheck):
+        (testWasmAddress):
+        (testFastTLSLoad):
+        (testFastTLSStore):
+        (doubleEq):
+        (doubleNeq):
+        (doubleGt):
+        (doubleGte):
+        (doubleLt):
+        (doubleLte):
+        (testDoubleLiteralComparison):
+        (testFloatEqualOrUnorderedFolding):
+        (testFloatEqualOrUnorderedFoldingNaN):
+        (testFloatEqualOrUnorderedDontFold):
+        (functionNineArgs):
+        (testShuffleDoesntTrashCalleeSaves):
+        (testDemotePatchpointTerminal):
+        (testReportUsedRegistersLateUseFollowedByEarlyDefDoesNotMarkUseAsDead):
+        (testInfiniteLoopDoesntCauseBadHoisting):
+        * b3/testb3_8.cpp: Added.
+        (testAtomicWeakCAS):
+        (testAtomicStrongCAS):
+        (testAtomicXchg):
+        (addAtomicTests):
+        (testLoad):
+        (addLoadTests):
+
 2019-07-30  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Emit write barrier after storing instead of before storing
index 73f6ede..faf259e 100644 (file)
                0FEC85911BDACDC70080FF74 /* AirValidate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC856C1BDACDC70080FF74 /* AirValidate.h */; };
                0FEC85A31BDB5CF10080FF74 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51F0EB6105C86C6B00E6DF1B /* Foundation.framework */; };
                0FEC85A41BDB5CF10080FF74 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; };
-               0FEC85AF1BDB5D5E0080FF74 /* testb3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEC85AE1BDB5D5E0080FF74 /* testb3.cpp */; settings = {COMPILER_FLAGS = "-O0 -DRELEASE_WITHOUT_OPTIMIZATIONS"; }; };
+               0FEC85AF1BDB5D5E0080FF74 /* testb3_1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEC85AE1BDB5D5E0080FF74 /* testb3_1.cpp */; settings = {COMPILER_FLAGS = "-O0 -DRELEASE_WITHOUT_OPTIMIZATIONS"; }; };
                0FEC85B31BDED9570080FF74 /* B3ConstPtrValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC85B21BDED9570080FF74 /* B3ConstPtrValue.h */; };
                0FEC85BA1BE1462F0080FF74 /* B3InsertionSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC85B51BE1462F0080FF74 /* B3InsertionSet.h */; };
                0FEC85BB1BE1462F0080FF74 /* B3InsertionSetInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC85B61BE1462F0080FF74 /* B3InsertionSetInlines.h */; };
                5B70CFDE1DB69E6600EC23F9 /* JSAsyncFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */; };
                5B70CFE01DB69E6600EC23F9 /* AsyncFunctionPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDA1DB69E5C00EC23F9 /* AsyncFunctionPrototype.h */; };
                5B70CFE21DB69E6600EC23F9 /* AsyncFunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */; };
+               5C3A77B422F247FC003827FF /* testb3_8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A77B322F247CB003827FF /* testb3_8.cpp */; };
+               5C3A77B522F24800003827FF /* testb3_7.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A77AD22F247C9003827FF /* testb3_7.cpp */; };
+               5C3A77B622F24803003827FF /* testb3_6.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A77AF22F247CA003827FF /* testb3_6.cpp */; };
+               5C3A77B722F24806003827FF /* testb3_5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A77B022F247CB003827FF /* testb3_5.cpp */; };
+               5C3A77B822F24809003827FF /* testb3_4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A77AE22F247CA003827FF /* testb3_4.cpp */; };
+               5C3A77B922F2480B003827FF /* testb3_3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A77B122F247CB003827FF /* testb3_3.cpp */; };
+               5C3A77BA22F2480F003827FF /* testb3_2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A77B222F247CB003827FF /* testb3_2.cpp */; };
                5C4196622270E0000047B7CD /* InspectorBackendDispatcherCompatibility.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C4196612270DFF30047B7CD /* InspectorBackendDispatcherCompatibility.cpp */; };
                5C4E8E961DBEBE620036F1FC /* JSONParseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */; };
                5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; };
                0FEC856C1BDACDC70080FF74 /* AirValidate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirValidate.h; path = b3/air/AirValidate.h; sourceTree = "<group>"; };
                0FEC85921BDB1E100080FF74 /* AirGenerated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirGenerated.cpp; path = b3/air/AirGenerated.cpp; sourceTree = "<group>"; };
                0FEC85AD1BDB5CF10080FF74 /* testb3 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testb3; sourceTree = BUILT_PRODUCTS_DIR; };
-               0FEC85AE1BDB5D5E0080FF74 /* testb3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3.cpp; path = b3/testb3.cpp; sourceTree = "<group>"; };
+               0FEC85AE1BDB5D5E0080FF74 /* testb3_1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3_1.cpp; path = b3/testb3_1.cpp; sourceTree = "<group>"; };
                0FEC85B21BDED9570080FF74 /* B3ConstPtrValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3ConstPtrValue.h; path = b3/B3ConstPtrValue.h; sourceTree = "<group>"; };
                0FEC85B41BE1462F0080FF74 /* B3InsertionSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3InsertionSet.cpp; path = b3/B3InsertionSet.cpp; sourceTree = "<group>"; };
                0FEC85B51BE1462F0080FF74 /* B3InsertionSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3InsertionSet.h; path = b3/B3InsertionSet.h; sourceTree = "<group>"; };
                5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncFunctionConstructor.h; sourceTree = "<group>"; };
                5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncFunctionConstructor.cpp; sourceTree = "<group>"; };
                5B8243041DB7AA4900EA6384 /* AsyncFunctionPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = AsyncFunctionPrototype.js; sourceTree = "<group>"; };
+               5C3A77AD22F247C9003827FF /* testb3_7.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3_7.cpp; path = b3/testb3_7.cpp; sourceTree = "<group>"; };
+               5C3A77AE22F247CA003827FF /* testb3_4.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3_4.cpp; path = b3/testb3_4.cpp; sourceTree = "<group>"; };
+               5C3A77AF22F247CA003827FF /* testb3_6.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3_6.cpp; path = b3/testb3_6.cpp; sourceTree = "<group>"; };
+               5C3A77B022F247CB003827FF /* testb3_5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3_5.cpp; path = b3/testb3_5.cpp; sourceTree = "<group>"; };
+               5C3A77B122F247CB003827FF /* testb3_3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3_3.cpp; path = b3/testb3_3.cpp; sourceTree = "<group>"; };
+               5C3A77B222F247CB003827FF /* testb3_2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3_2.cpp; path = b3/testb3_2.cpp; sourceTree = "<group>"; };
+               5C3A77B322F247CB003827FF /* testb3_8.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testb3_8.cpp; path = b3/testb3_8.cpp; sourceTree = "<group>"; };
+               5C3A77BB22F24890003827FF /* testb3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = testb3.h; path = b3/testb3.h; sourceTree = "<group>"; };
                5C4196612270DFF30047B7CD /* InspectorBackendDispatcherCompatibility.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorBackendDispatcherCompatibility.cpp; sourceTree = "<group>"; };
                5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSONParseTest.cpp; path = API/tests/JSONParseTest.cpp; sourceTree = "<group>"; };
                5C4E8E951DBEBDA20036F1FC /* JSONParseTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONParseTest.h; path = API/tests/JSONParseTest.h; sourceTree = "<group>"; };
                                5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */,
                                0F2C63AD1E60AE3C00C13839 /* B3Width.cpp */,
                                0F2C63AE1E60AE3D00C13839 /* B3Width.h */,
-                               0FEC85AE1BDB5D5E0080FF74 /* testb3.cpp */,
+                               5C3A77BB22F24890003827FF /* testb3.h */,
+                               0FEC85AE1BDB5D5E0080FF74 /* testb3_1.cpp */,
+                               5C3A77B222F247CB003827FF /* testb3_2.cpp */,
+                               5C3A77B122F247CB003827FF /* testb3_3.cpp */,
+                               5C3A77AE22F247CA003827FF /* testb3_4.cpp */,
+                               5C3A77B022F247CB003827FF /* testb3_5.cpp */,
+                               5C3A77AF22F247CA003827FF /* testb3_6.cpp */,
+                               5C3A77AD22F247C9003827FF /* testb3_7.cpp */,
+                               5C3A77B322F247CB003827FF /* testb3_8.cpp */,
                        );
                        name = b3;
                        sourceTree = "<group>";
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0FEC85AF1BDB5D5E0080FF74 /* testb3.cpp in Sources */,
+                               0FEC85AF1BDB5D5E0080FF74 /* testb3_1.cpp in Sources */,
+                               5C3A77BA22F2480F003827FF /* testb3_2.cpp in Sources */,
+                               5C3A77B922F2480B003827FF /* testb3_3.cpp in Sources */,
+                               5C3A77B822F24809003827FF /* testb3_4.cpp in Sources */,
+                               5C3A77B722F24806003827FF /* testb3_5.cpp in Sources */,
+                               5C3A77B622F24803003827FF /* testb3_6.cpp in Sources */,
+                               5C3A77B522F24800003827FF /* testb3_7.cpp in Sources */,
+                               5C3A77B422F247FC003827FF /* testb3_8.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/Source/JavaScriptCore/b3/testb3.cpp b/Source/JavaScriptCore/b3/testb3.cpp
deleted file mode 100644 (file)
index 4411e03..0000000
+++ /dev/null
@@ -1,19216 +0,0 @@
-/*
- * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#include "config.h"
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirValidate.h"
-#include "AllowMacroScratchRegisterUsage.h"
-#include "B3ArgumentRegValue.h"
-#include "B3AtomicValue.h"
-#include "B3BasicBlockInlines.h"
-#include "B3BreakCriticalEdges.h"
-#include "B3CCallValue.h"
-#include "B3Compilation.h"
-#include "B3Compile.h"
-#include "B3ComputeDivisionMagic.h"
-#include "B3Const32Value.h"
-#include "B3Const64Value.h"
-#include "B3ConstPtrValue.h"
-#include "B3Effects.h"
-#include "B3FenceValue.h"
-#include "B3FixSSA.h"
-#include "B3Generate.h"
-#include "B3LowerToAir.h"
-#include "B3MathExtras.h"
-#include "B3MemoryValue.h"
-#include "B3MoveConstants.h"
-#include "B3NativeTraits.h"
-#include "B3Procedure.h"
-#include "B3ReduceStrength.h"
-#include "B3SlotBaseValue.h"
-#include "B3StackSlot.h"
-#include "B3StackmapGenerationParams.h"
-#include "B3SwitchValue.h"
-#include "B3UpsilonValue.h"
-#include "B3UseCounts.h"
-#include "B3Validate.h"
-#include "B3ValueInlines.h"
-#include "B3VariableValue.h"
-#include "B3WasmAddressValue.h"
-#include "B3WasmBoundsCheckValue.h"
-#include "CCallHelpers.h"
-#include "FPRInfo.h"
-#include "GPRInfo.h"
-#include "InitializeThreading.h"
-#include "JSCInlines.h"
-#include "LinkBuffer.h"
-#include "PureNaN.h"
-#include <cmath>
-#include <string>
-#include <wtf/FastTLS.h>
-#include <wtf/IndexSet.h>
-#include <wtf/ListDump.h>
-#include <wtf/Lock.h>
-#include <wtf/NumberOfCores.h>
-#include <wtf/StdList.h>
-#include <wtf/Threading.h>
-#include <wtf/text/StringCommon.h>
-
-// We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous.
-static bool hiddenTruthBecauseNoReturnIsStupid() { return true; }
-
-static void usage()
-{
-    dataLog("Usage: testb3 [<filter>]\n");
-    if (hiddenTruthBecauseNoReturnIsStupid())
-        exit(1);
-}
-
-#if ENABLE(B3_JIT)
-
-using namespace JSC;
-using namespace JSC::B3;
-
-namespace {
-
-bool shouldBeVerbose()
-{
-    return shouldDumpIR(B3Mode);
-}
-
-Lock crashLock;
-
-// Nothing fancy for now; we just use the existing WTF assertion machinery.
-#define CHECK(x) do {                                                   \
-        if (!!(x))                                                      \
-            break;                                                      \
-        crashLock.lock();                                               \
-        WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
-        CRASH();                                                        \
-    } while (false)
-
-#define CHECK_EQ(x, y) do { \
-        auto __x = (x); \
-        auto __y = (y); \
-        if (__x == __y) \
-            break; \
-        crashLock.lock(); \
-        WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, toCString(#x " == " #y, " (" #x " == ", __x, ", " #y " == ", __y, ")").data()); \
-        CRASH(); \
-    } while (false)
-
-std::unique_ptr<Compilation> compileProc(Procedure& procedure, unsigned optLevel = Options::defaultB3OptLevel())
-{
-    procedure.setOptLevel(optLevel);
-    return std::make_unique<Compilation>(B3::compile(procedure));
-}
-
-template<typename T, typename... Arguments>
-T invoke(MacroAssemblerCodePtr<B3CompilationPtrTag> ptr, Arguments... arguments)
-{
-    void* executableAddress = untagCFunctionPtr<B3CompilationPtrTag>(ptr.executableAddress());
-    T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(executableAddress);
-    return function(arguments...);
-}
-
-template<typename T, typename... Arguments>
-T invoke(const Compilation& code, Arguments... arguments)
-{
-    return invoke<T>(code.code(), arguments...);
-}
-
-template<typename T, typename... Arguments>
-T compileAndRun(Procedure& procedure, Arguments... arguments)
-{
-    return invoke<T>(*compileProc(procedure), arguments...);
-}
-
-void lowerToAirForTesting(Procedure& proc)
-{
-    proc.resetReachability();
-    
-    if (shouldBeVerbose())
-        dataLog("B3 before lowering:\n", proc);
-    
-    validate(proc);
-    lowerToAir(proc);
-    
-    if (shouldBeVerbose())
-        dataLog("Air after lowering:\n", proc.code());
-    
-    Air::validate(proc.code());
-}
-
-template<typename Func>
-void checkDisassembly(Compilation& compilation, const Func& func, const CString& failText)
-{
-    CString disassembly = compilation.disassembly();
-    if (func(disassembly.data()))
-        return;
-    
-    crashLock.lock();
-    dataLog("Bad lowering!  ", failText, "\n");
-    dataLog(disassembly);
-    CRASH();
-}
-
-void checkUsesInstruction(Compilation& compilation, const char* text)
-{
-    checkDisassembly(
-        compilation,
-        [&] (const char* disassembly) -> bool {
-            return strstr(disassembly, text);
-        },
-        toCString("Expected to find ", text, " but didnt!"));
-}
-
-void checkDoesNotUseInstruction(Compilation& compilation, const char* text)
-{
-    checkDisassembly(
-        compilation,
-        [&] (const char* disassembly) -> bool {
-            return !strstr(disassembly, text);
-        },
-        toCString("Did not expected to find ", text, " but it's there!"));
-}
-
-template<typename Type>
-struct Operand {
-    const char* name;
-    Type value;
-};
-
-typedef Operand<int64_t> Int64Operand;
-typedef Operand<int32_t> Int32Operand;
-
-template<typename FloatType>
-void populateWithInterestingValues(Vector<Operand<FloatType>>& operands)
-{
-    operands.append({ "0.", static_cast<FloatType>(0.) });
-    operands.append({ "-0.", static_cast<FloatType>(-0.) });
-    operands.append({ "0.4", static_cast<FloatType>(0.5) });
-    operands.append({ "-0.4", static_cast<FloatType>(-0.5) });
-    operands.append({ "0.5", static_cast<FloatType>(0.5) });
-    operands.append({ "-0.5", static_cast<FloatType>(-0.5) });
-    operands.append({ "0.6", static_cast<FloatType>(0.5) });
-    operands.append({ "-0.6", static_cast<FloatType>(-0.5) });
-    operands.append({ "1.", static_cast<FloatType>(1.) });
-    operands.append({ "-1.", static_cast<FloatType>(-1.) });
-    operands.append({ "2.", static_cast<FloatType>(2.) });
-    operands.append({ "-2.", static_cast<FloatType>(-2.) });
-    operands.append({ "M_PI", static_cast<FloatType>(M_PI) });
-    operands.append({ "-M_PI", static_cast<FloatType>(-M_PI) });
-    operands.append({ "min", std::numeric_limits<FloatType>::min() });
-    operands.append({ "max", std::numeric_limits<FloatType>::max() });
-    operands.append({ "lowest", std::numeric_limits<FloatType>::lowest() });
-    operands.append({ "epsilon", std::numeric_limits<FloatType>::epsilon() });
-    operands.append({ "infiniti", std::numeric_limits<FloatType>::infinity() });
-    operands.append({ "-infiniti", - std::numeric_limits<FloatType>::infinity() });
-    operands.append({ "PNaN", static_cast<FloatType>(PNaN) });
-}
-
-template<typename FloatType>
-Vector<Operand<FloatType>> floatingPointOperands()
-{
-    Vector<Operand<FloatType>> operands;
-    populateWithInterestingValues(operands);
-    return operands;
-};
-
-static Vector<Int64Operand> int64Operands()
-{
-    Vector<Int64Operand> operands;
-    operands.append({ "0", 0 });
-    operands.append({ "1", 1 });
-    operands.append({ "-1", -1 });
-    operands.append({ "42", 42 });
-    operands.append({ "-42", -42 });
-    operands.append({ "int64-max", std::numeric_limits<int64_t>::max() });
-    operands.append({ "int64-min", std::numeric_limits<int64_t>::min() });
-    operands.append({ "int32-max", std::numeric_limits<int32_t>::max() });
-    operands.append({ "int32-min", std::numeric_limits<int32_t>::min() });
-    operands.append({ "uint64-max", static_cast<int64_t>(std::numeric_limits<uint64_t>::max()) });
-    operands.append({ "uint64-min", static_cast<int64_t>(std::numeric_limits<uint64_t>::min()) });
-    operands.append({ "uint32-max", static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) });
-    operands.append({ "uint32-min", static_cast<int64_t>(std::numeric_limits<uint32_t>::min()) });
-
-    return operands;
-}
-
-static Vector<Int32Operand> int32Operands()
-{
-    Vector<Int32Operand> operands({
-        { "0", 0 },
-        { "1", 1 },
-        { "-1", -1 },
-        { "42", 42 },
-        { "-42", -42 },
-        { "int32-max", std::numeric_limits<int32_t>::max() },
-        { "int32-min", std::numeric_limits<int32_t>::min() },
-        { "uint32-max", static_cast<int32_t>(std::numeric_limits<uint32_t>::max()) },
-        { "uint32-min", static_cast<int32_t>(std::numeric_limits<uint32_t>::min()) }
-    });
-    return operands;
-}
-
-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;
-    BasicBlock* root = proc.addBlock();
-    Value* const42 = root->appendNew<Const32Value>(proc, Origin(), 42);
-    root->appendNewControlValue(proc, Return, Origin(), const42);
-
-    CHECK(compileAndRun<int>(proc) == 42);
-}
-
-void testLoad42()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    int x = 42;
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load, Int32, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), &x)));
-
-    CHECK(compileAndRun<int>(proc) == 42);
-}
-
-void testLoadAcq42()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    int x = 42;
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load, Int32, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), &x),
-            0, HeapRange(42), HeapRange(42)));
-
-    auto code = compileProc(proc);
-    if (isARM64())
-        checkUsesInstruction(*code, "lda");
-    CHECK(invoke<int>(*code) == 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->appendNewControlValue(
-            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->appendNewControlValue(
-            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 testBitXorTreeArgs(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* node = root->appendNew<Value>(proc, BitXor, Origin(), argA, argB);
-    node = root->appendNew<Value>(proc, BitXor, Origin(), node, argB);
-    node = root->appendNew<Value>(proc, BitXor, Origin(), node, argA);
-    node = root->appendNew<Value>(proc, BitXor, Origin(), node, argB);
-    root->appendNew<Value>(proc, Return, Origin(), node);
-
-    CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (((a ^ b) ^ b) ^ a) ^ b);
-}
-
-void testBitXorTreeArgsEven(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* node = root->appendNew<Value>(proc, BitXor, Origin(), argA, argB);
-    node = root->appendNew<Value>(proc, BitXor, Origin(), node, argB);
-    node = root->appendNew<Value>(proc, BitXor, Origin(), node, argA);
-    root->appendNew<Value>(proc, Return, Origin(), node);
-
-    CHECK_EQ(compileAndRun<int64_t>(proc, a, b), ((a ^ b) ^ b) ^ a);
-}
-
-void testBitXorTreeArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* immB = root->appendNew<Const64Value>(proc, Origin(), b);
-    Value* node = root->appendNew<Value>(proc, BitXor, Origin(), argA, immB);
-    node = root->appendNew<Value>(proc, BitXor, Origin(), argA, node);
-    node = root->appendNew<Value>(proc, BitXor, Origin(), argA, node);
-    node = root->appendNew<Value>(proc, BitXor, Origin(), immB, node);
-    root->appendNew<Value>(proc, Return, Origin(), node);
-
-    CHECK_EQ(compileAndRun<int64_t>(proc, a), b ^ (a ^ (a ^ (a ^ b))));
-}
-
-void testAddTreeArg32(int32_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    argA = root->appendNew<Value>(proc, Trunc, Origin(), argA);
-    Value* node = argA;
-    int32_t expectedResult = a;
-    for (unsigned i = 0; i < 20; ++i) {
-        Value* otherNode;
-        if (!(i % 3)) {
-            otherNode = root->appendNew<Const32Value>(proc, Origin(), i);
-            expectedResult += i;
-        } else {
-            otherNode = argA;
-            expectedResult += a;
-        }
-        node = root->appendNew<Value>(proc, Add, Origin(), node, otherNode);
-    }
-    root->appendNew<Value>(proc, Return, Origin(), node);
-
-    CHECK_EQ(compileAndRun<int32_t>(proc, a), expectedResult);
-}
-
-void testMulTreeArg32(int32_t a)
-{
-    // Fibonacci-like expression tree with multiplication instead of addition.
-    // Verifies that we don't explode on heavily factored graphs.
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    argA = root->appendNew<Value>(proc, Trunc, Origin(), argA);
-    Value* nodeA = argA;
-    Value* nodeB = argA;
-    int32_t expectedA = a, expectedResult = a;
-    for (unsigned i = 0; i < 20; ++i) {
-        Value* newNodeB = root->appendNew<Value>(proc, Mul, Origin(), nodeA, nodeB);
-        nodeA = nodeB;
-        nodeB = newNodeB;
-        int32_t newExpectedResult = expectedA * expectedResult;
-        expectedA = expectedResult;
-        expectedResult = newExpectedResult;
-    }
-    root->appendNew<Value>(proc, Return, Origin(), nodeB);
-
-    CHECK_EQ(compileAndRun<int32_t>(proc, a), expectedResult);
-}
-
-void testBitAndTreeArg32(int32_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    argA = root->appendNew<Value>(proc, Trunc, Origin(), argA);
-    Value* node = argA;
-    for (unsigned i = 0; i < 8; ++i) {
-        Value* constI = root->appendNew<Const32Value>(proc, Origin(), i | 42);
-        Value* newBitAnd = root->appendNew<Value>(proc, BitAnd, Origin(), argA, constI);
-        node = root->appendNew<Value>(proc, BitAnd, Origin(), node, newBitAnd);
-    }
-    root->appendNew<Value>(proc, Return, Origin(), node);
-
-    CHECK_EQ(compileAndRun<int32_t>(proc, a), a & 42);
-}
-
-void testBitOrTreeArg32(int32_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    argA = root->appendNew<Value>(proc, Trunc, Origin(), argA);
-    Value* node = argA;
-    for (unsigned i = 0; i < 8; ++i) {
-        Value* constI = root->appendNew<Const32Value>(proc, Origin(), i);
-        Value* newBitAnd = root->appendNew<Value>(proc, BitOr, Origin(), argA, constI);
-        node = root->appendNew<Value>(proc, BitOr, Origin(), node, newBitAnd);
-    }
-    root->appendNew<Value>(proc, Return, Origin(), node);
-
-    CHECK_EQ(compileAndRun<int32_t>(proc, a), a | 7);
-}
-
-void testArg(int argument)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-
-    CHECK(compileAndRun<int>(proc, argument) == argument);
-}
-
-void testReturnConst64(int64_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const64Value>(proc, Origin(), value));
-
-    CHECK(compileAndRun<int64_t>(proc) == value);
-}
-
-void testReturnVoid()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(proc, Return, Origin());
-    compileAndRun<void>(proc);
-}
-
-void testAddArg(int a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Add, Origin(), value, value));
-
-    CHECK(compileAndRun<int>(proc, a) == a + a);
-}
-
-void testAddArgs(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
-
-    CHECK(compileAndRun<int>(proc, a, b) == a + b);
-}
-
-void testAddArgImm(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int>(proc, a) == a + b);
-}
-
-void testAddImmArg(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(
-        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;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, 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) == 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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    int32_t inputOutput = b;
-    CHECK(!compileAndRun<int>(proc, &inputOutput));
-    CHECK(inputOutput == a + b);
-}
-
-void testAddNeg1(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<Value>(proc, Neg, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
-    
-    CHECK(compileAndRun<int>(proc, a, b) == (- a) + b);
-}
-
-void testAddNeg2(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Value>(proc, Neg, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
-
-    CHECK(compileAndRun<int>(proc, a, b) == a + (- b));
-}
-
-void testAddArgZeroImmZDef()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* arg = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* constZero = root->appendNew<Const32Value>(proc, Origin(), 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            arg,
-            constZero));
-
-    auto code = compileProc(proc, 0);
-    CHECK(invoke<int64_t>(*code, 0x0123456789abcdef) == 0x89abcdef);
-}
-
-void testAddLoadTwice()
-{
-    auto test = [&] () {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        int32_t value = 42;
-        Value* load = root->appendNew<MemoryValue>(
-            proc, Load, Int32, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), &value));
-        root->appendNewControlValue(
-            proc, Return, Origin(),
-            root->appendNew<Value>(proc, Add, Origin(), load, load));
-
-        auto code = compileProc(proc);
-        CHECK(invoke<int32_t>(*code) == 42 * 2);
-    };
-
-    test();
-}
-
-void testAddArgDouble(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Add, Origin(), value, value));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a + a));
-}
-
-void testAddArgsDouble(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Add, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), a + b));
-}
-
-void testAddArgImmDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Add, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a + b));
-}
-
-void testAddImmArgDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Add, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, b), a + b));
-}
-
-void testAddImmsDouble(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Add, Origin(), valueA, valueB));
-
-    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->appendNewControlValue(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->appendNewControlValue(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 testAddFPRArgsFloat(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
-    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1));
-    Value* result = root->appendNew<Value>(proc, Add, Origin(), argument1, argument2);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, a, b), 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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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 testAddMulMulArgs(int64_t a, int64_t b, int64_t c)
-{
-    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
-    // ((a * b) + (a * c))
-    // ((a * b) + (c * a))
-    // ((b * a) + (a * c))
-    // ((b * a) + (c * a))
-    for (int i = 0; i < 4; ++i) {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-        Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-        Value* argC = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-        Value* mulAB = i & 2 ? root->appendNew<Value>(proc, Mul, Origin(), argA, argB)
-            : root->appendNew<Value>(proc, Mul, Origin(), argB, argA);
-        Value* mulAC = i & 1 ? root->appendNew<Value>(proc, Mul, Origin(), argA, argC)
-            : root->appendNew<Value>(proc, Mul, Origin(), argC, argA);
-        root->appendNew<Value>(proc, Return, Origin(),
-            root->appendNew<Value>(proc, Add, Origin(),
-                mulAB,
-                mulAC));
-
-        CHECK_EQ(compileAndRun<int64_t>(proc, a, b, c), ((a * b) + (a * c)));
-    }
-}
-
-void testMulArg(int a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<Value>(
-        proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mul, Origin(), value, value));
-
-    CHECK(compileAndRun<int>(proc, a) == a * a);
-}
-
-void testMulArgStore(int a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    int mulSlot;
-    int valueSlot;
-    
-    Value* value = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* mul = root->appendNew<Value>(proc, Mul, Origin(), value, value);
-
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(), value,
-        root->appendNew<ConstPtrValue>(proc, Origin(), &valueSlot), 0);
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(), mul,
-        root->appendNew<ConstPtrValue>(proc, Origin(), &mulSlot), 0);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc, a));
-    CHECK(mulSlot == a * a);
-    CHECK(valueSlot == a);
-}
-
-void testMulAddArg(int a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<Value>(proc, Mul, Origin(), value, value),
-            value));
-
-    CHECK(compileAndRun<int>(proc, a) == a * a + a);
-}
-
-void testMulArgs(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Mul, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
-
-    CHECK(compileAndRun<int>(proc, a, b) == a * b);
-}
-
-void testMulArgNegArg(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* negB = root->appendNew<Value>(proc, Neg, Origin(), argB);
-    Value* result = root->appendNew<Value>(proc, Mul, Origin(), argA, negB);
-    root->appendNew<Value>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int>(proc, a, b) == a * (-b));
-}
-
-void testMulNegArgArg(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* negA = root->appendNew<Value>(proc, Neg, Origin(), argA);
-    Value* result = root->appendNew<Value>(proc, Mul, Origin(), negA, argB);
-    root->appendNew<Value>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int>(proc, a, b) == (-a) * b);
-}
-
-void testMulArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Mul, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == a * b);
-}
-
-void testMulImmArg(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Mul, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    CHECK(compileAndRun<int>(proc, b) == a * b);
-}
-
-void testMulArgs32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Mul, 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) == a * b);
-}
-
-void testMulArgs32SignExtend(int a, int b)
-{
-    Procedure proc;
-    if (proc.optLevel() < 1)
-        return;
-    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));
-    Value* arg164 = root->appendNew<Value>(proc, SExt32, Origin(), arg1);
-    Value* arg264 = root->appendNew<Value>(proc, SExt32, Origin(), arg2);
-    Value* mul = root->appendNew<Value>(proc, Mul, Origin(), arg164, arg264);
-    root->appendNewControlValue(proc, Return, Origin(), mul);
-
-    auto code = compileProc(proc);
-
-    CHECK(invoke<long int>(*code, a, b) == ((long int) a) * ((long int) b));
-}
-
-void testMulImm32SignExtend(const int a, int b)
-{
-    Procedure proc;
-    if (proc.optLevel() < 1)
-        return;
-    BasicBlock* root = proc.addBlock();
-    Value* arg1 = root->appendNew<Const64Value>(proc, Origin(), a);
-    Value* arg2 = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* arg264 = root->appendNew<Value>(proc, SExt32, Origin(), arg2);
-    Value* mul = root->appendNew<Value>(proc, Mul, Origin(), arg1, arg264);
-    root->appendNewControlValue(proc, Return, Origin(), mul);
-
-    auto code = compileProc(proc);
-
-    CHECK(invoke<long int>(*code, b) == ((long int) a) * ((long int) b));
-}
-
-void testMulLoadTwice()
-{
-    auto test = [&] () {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        int32_t value = 42;
-        Value* load = root->appendNew<MemoryValue>(
-            proc, Load, Int32, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), &value));
-        root->appendNewControlValue(
-            proc, Return, Origin(),
-            root->appendNew<Value>(proc, Mul, Origin(), load, load));
-
-        auto code = compileProc(proc);
-        CHECK(invoke<int32_t>(*code) == 42 * 42);
-    };
-
-    test();
-}
-
-void testMulAddArgsLeft()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg0, arg1);
-    Value* added = root->appendNew<Value>(proc, Add, Origin(), multiplied, arg2);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int64Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            for (auto c : testValues) {
-                CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value * b.value + c.value);
-            }
-        }
-    }
-}
-
-void testMulAddArgsRight()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg1, arg2);
-    Value* added = root->appendNew<Value>(proc, Add, Origin(), arg0, multiplied);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int64Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            for (auto c : testValues) {
-                CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value + b.value * c.value);
-            }
-        }
-    }
-}
-
-void testMulAddArgsLeft32()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* arg2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg0, arg1);
-    Value* added = root->appendNew<Value>(proc, Add, Origin(), multiplied, arg2);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int32Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            for (auto c : testValues) {
-                CHECK(invoke<int32_t>(*code, a.value, b.value, c.value) == a.value * b.value + c.value);
-            }
-        }
-    }
-}
-
-void testMulAddArgsRight32()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* arg2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg1, arg2);
-    Value* added = root->appendNew<Value>(proc, Add, Origin(), arg0, multiplied);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int32Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            for (auto c : testValues) {
-                CHECK(invoke<int32_t>(*code, a.value, b.value, c.value) == a.value + b.value * c.value);
-            }
-        }
-    }
-}
-
-void testMulSubArgsLeft()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg0, arg1);
-    Value* added = root->appendNew<Value>(proc, Sub, Origin(), multiplied, arg2);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int64Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            for (auto c : testValues) {
-                CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value * b.value - c.value);
-            }
-        }
-    }
-}
-
-void testMulSubArgsRight()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg1, arg2);
-    Value* added = root->appendNew<Value>(proc, Sub, Origin(), arg0, multiplied);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int64Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            for (auto c : testValues) {
-                CHECK(invoke<int64_t>(*code, a.value, b.value, c.value) == a.value - b.value * c.value);
-            }
-        }
-    }
-}
-
-void testMulSubArgsLeft32()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* arg2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg0, arg1);
-    Value* added = root->appendNew<Value>(proc, Sub, Origin(), multiplied, arg2);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int32Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            for (auto c : testValues) {
-                CHECK(invoke<int32_t>(*code, a.value, b.value, c.value) == a.value * b.value - c.value);
-            }
-        }
-    }
-}
-
-void testMulSubArgsRight32()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* arg2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg1, arg2);
-    Value* added = root->appendNew<Value>(proc, Sub, Origin(), arg0, multiplied);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int32Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            for (auto c : testValues) {
-                CHECK(invoke<int32_t>(*code, a.value, b.value, c.value) == a.value - b.value * c.value);
-            }
-        }
-    }
-}
-
-void testMulNegArgs()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg0, arg1);
-    Value* zero = root->appendNew<Const64Value>(proc, Origin(), 0);
-    Value* added = root->appendNew<Value>(proc, Sub, Origin(), zero, multiplied);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int64Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            CHECK(invoke<int64_t>(*code, a.value, b.value) == -(a.value * b.value));
-        }
-    }
-}
-
-void testMulNegArgs32()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg0 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* multiplied = root->appendNew<Value>(proc, Mul, Origin(), arg0, arg1);
-    Value* zero = root->appendNew<Const32Value>(proc, Origin(), 0);
-    Value* added = root->appendNew<Value>(proc, Sub, Origin(), zero, multiplied);
-    root->appendNewControlValue(proc, Return, Origin(), added);
-
-    auto code = compileProc(proc);
-
-    auto testValues = int32Operands();
-    for (auto a : testValues) {
-        for (auto b : testValues) {
-            CHECK(invoke<int32_t>(*code, a.value, b.value) == -(a.value * b.value));
-        }
-    }
-}
-
-void testMulArgDouble(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mul, Origin(), value, value));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a * a));
-}
-
-void testMulArgsDouble(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mul, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), a * b));
-}
-
-void testMulArgImmDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mul, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a * b));
-}
-
-void testMulImmArgDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mul, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, b), a * b));
-}
-
-void testMulImmsDouble(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mul, Origin(), valueA, valueB));
-
-    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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Div, Origin(), value, value));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a / a));
-}
-
-void testDivArgsDouble(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Div, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), a / b));
-}
-
-void testDivArgImmDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Div, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a / b));
-}
-
-void testDivImmArgDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Div, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, b), a / b));
-}
-
-void testDivImmsDouble(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Div, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc), a / b));
-}
-
-void testDivArgFloat(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, Div, Origin(), floatValue, floatValue);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a / a)));
-}
-
-void testDivArgsFloat(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, Div, Origin(), floatValue1, floatValue2);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(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 testDivArgImmFloat(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, Div, Origin(), floatValue, constValue);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a / b)));
-}
-
-void testDivImmArgFloat(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, Div, Origin(), constValue, floatValue);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a / b)));
-}
-
-void testDivImmsFloat(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, Div, Origin(), constValue1, constValue2);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a / b)));
-}
-
-void testModArgDouble(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mod, Origin(), value, value));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), fmod(a, a)));
-}
-
-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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), fmod(a, b)));
-}
-
-void testModArgImmDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), fmod(a, b)));
-}
-
-void testModImmArgDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, b), fmod(a, b)));
-}
-
-void testModImmsDouble(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Mod, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc), fmod(a, b)));
-}
-
-void testModArgFloat(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, Mod, Origin(), floatValue, floatValue);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, a)))));
-}
-
-void testModArgsFloat(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, Mod, Origin(), floatValue1, floatValue2);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(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 testModArgImmFloat(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, Mod, Origin(), floatValue, constValue);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b)))));
-}
-
-void testModImmArgFloat(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, Mod, Origin(), constValue, floatValue);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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 testUDivArgsInt32(uint32_t a, uint32_t b)
-{
-    // UDiv with denominator == 0 is invalid.
-    if (!b)
-        return;
-
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* result = root->appendNew<Value>(proc, UDiv, Origin(), argument1, argument2);
-    root->appendNew<Value>(proc, Return, Origin(), result);
-
-    CHECK_EQ(compileAndRun<uint32_t>(proc, a, b), a / b);
-}
-
-void testUDivArgsInt64(uint64_t a, uint64_t b)
-{
-    // UDiv with denominator == 0 is invalid.
-    if (!b)
-        return;
-
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* result = root->appendNew<Value>(proc, UDiv, Origin(), argument1, argument2);
-    root->appendNew<Value>(proc, Return, Origin(), result);
-
-    CHECK_EQ(compileAndRun<uint64_t>(proc, a, b), a / b);
-}
-
-void testUModArgsInt32(uint32_t a, uint32_t b)
-{
-    // UMod with denominator == 0 is invalid.
-    if (!b)
-        return;
-
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* result = root->appendNew<Value>(proc, UMod, Origin(), argument1, argument2);
-    root->appendNew<Value>(proc, Return, Origin(), result);
-
-    CHECK_EQ(compileAndRun<uint32_t>(proc, a, b), a % b);
-}
-
-void testUModArgsInt64(uint64_t a, uint64_t b)
-{
-    // UMod with denominator == 0 is invalid.
-    if (!b)
-        return;
-
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* result = root->appendNew<Value>(proc, UMod, Origin(), argument1, argument2);
-    root->appendNew<Value>(proc, Return, Origin(), result);
-    
-    CHECK_EQ(compileAndRun<uint64_t>(proc, a, b), a % b);
-}
-
-void testSubArg(int a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), value, value));
-
-    CHECK(!compileAndRun<int>(proc, a));
-}
-
-void testSubArgs(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
-
-    CHECK(compileAndRun<int>(proc, a, b) == a - b);
-}
-
-void testSubArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == a - b);
-}
-
-void testSubNeg(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Value>(proc, Neg, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
-    
-    CHECK(compileAndRun<int>(proc, a, b) == a - (- b));
-}
-
-void testNegSub(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Neg, Origin(),
-            root->appendNew<Value>(proc, Sub, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
-
-    CHECK(compileAndRun<int>(proc, a, b) == -(a - 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->appendNewControlValue(proc, Return, Origin(), negArgumentMinusOne);
-    CHECK(compileAndRun<int>(proc, a) == -a - 1);
-}
-
-void testSubSub(int a, int b, int c)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Value>(proc, Sub, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
-
-    CHECK(compileAndRun<int>(proc, a, b, c) == (a-b)-c);
-}
-
-void testSubSub2(int a, int b, int c)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Value>(proc, Sub, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))));
-
-    CHECK(compileAndRun<int>(proc, a, b, c) == a-(b-c));
-}
-
-void testSubAdd(int a, int b, int c)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Value>(proc, Add, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
-
-    CHECK(compileAndRun<int>(proc, a, b, c) == (a+b)-c);
-}
-
-void testSubFirstNeg(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Value>(proc, Neg, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
-
-    CHECK(compileAndRun<int>(proc, a, b) == (-a)-b);
-}
-
-void testSubImmArg(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    CHECK(compileAndRun<int>(proc, b) == a - b);
-}
-
-void testSubArgMem(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, Sub, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        load);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int64_t>(proc, a, &b) == a - b);
-}
-
-void testSubMemArg(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, Sub, Origin(),
-        load,
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
-    root->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    int64_t inputOutput = a;
-    CHECK(!compileAndRun<int64_t>(proc, &inputOutput, b));
-    CHECK(inputOutput == a - b);
-}
-
-void testSubImmMem(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, Sub, Origin(),
-        root->appendNew<Const64Value>(proc, Origin(), a),
-        load);
-    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
-    root->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    int64_t inputOutput = b;
-    CHECK(!compileAndRun<int>(proc, &inputOutput));
-    CHECK(inputOutput == a - b);
-}
-
-void testSubMemImm(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, Sub, Origin(),
-        load,
-        root->appendNew<Const64Value>(proc, Origin(), b));
-    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
-    root->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    int64_t inputOutput = a;
-    CHECK(!compileAndRun<int>(proc, &inputOutput));
-    CHECK(inputOutput == a - b);
-}
-
-
-void testSubArgs32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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))));
-
-    CHECK(compileAndRun<int>(proc, a, b) == a - b);
-}
-
-void testSubArgImm32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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)));
-
-    CHECK(compileAndRun<int>(proc, a) == a - b);
-}
-
-void testSubImmArg32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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))));
-
-    CHECK(compileAndRun<int>(proc, b) == a - b);
-}
-
-void testSubMemArg32(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, Sub, Origin(), load, argument);
-    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
-    root->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    int32_t inputOutput = a;
-    CHECK(!compileAndRun<int32_t>(proc, &inputOutput, b));
-    CHECK(inputOutput == a - b);
-}
-
-void testSubArgMem32(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, Sub, Origin(), argument, load);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int32_t>(proc, a, &b) == a - b);
-}
-
-void testSubImmMem32(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, Sub, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), a),
-        load);
-    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
-    root->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    int32_t inputOutput = b;
-    CHECK(!compileAndRun<int>(proc, &inputOutput));
-    CHECK(inputOutput == a - b);
-}
-
-void testSubMemImm32(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, Sub, Origin(),
-        load,
-        root->appendNew<Const32Value>(proc, Origin(), b));
-    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
-    root->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    int32_t inputOutput = a;
-    CHECK(!compileAndRun<int>(proc, &inputOutput));
-    CHECK(inputOutput == a - b);
-}
-
-void testNegValueSubOne32(int a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), negArgumentMinusOne);
-    CHECK(compileAndRun<int>(proc, a) == -a - 1);
-}
-
-void testNegMulArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* constant = root->appendNew<Const64Value>(proc, Origin(), b);
-    Value* mul = root->appendNew<Value>(proc, Mul, Origin(), argument, constant);
-    Value* result = root->appendNew<Value>(proc, Neg, Origin(), mul);
-    root->appendNew<Value>(proc, Return, Origin(), result);
-
-    CHECK(compileAndRun<int64_t>(proc, a) == -(a * b));
-}
-
-void testSubMulMulArgs(int64_t a, int64_t b, int64_t c)
-{
-    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
-    // ((a * b) - (a * c))
-    // ((a * b) - (c * a))
-    // ((b * a) - (a * c))
-    // ((b * a) - (c * a))
-    for (int i = 0; i < 4; ++i) {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-        Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-        Value* argC = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-        Value* mulAB = i & 2 ? root->appendNew<Value>(proc, Mul, Origin(), argA, argB)
-            : root->appendNew<Value>(proc, Mul, Origin(), argB, argA);
-        Value* mulAC = i & 1 ? root->appendNew<Value>(proc, Mul, Origin(), argA, argC)
-            : root->appendNew<Value>(proc, Mul, Origin(), argC, argA);
-        root->appendNew<Value>(proc, Return, Origin(),
-            root->appendNew<Value>(proc, Sub, Origin(),
-                mulAB,
-                mulAC));
-
-        CHECK_EQ(compileAndRun<int64_t>(proc, a, b, c), ((a * b) - (a * c)));
-    }
-}
-
-void testSubArgDouble(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), value, value));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a - a));
-}
-
-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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), a - b));
-}
-
-void testSubArgImmDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* valueB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), a - b));
-}
-
-void testSubImmArgDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* valueA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    Value* valueB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, b), a - 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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), valueA, valueB));
-    
-    CHECK(isIdentical(compileAndRun<double>(proc), 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->appendNewControlValue(proc, Return, Origin(), result32);
-
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a - a)));
-}
-
-void testSubArgsFloat(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, Sub, Origin(), floatValue1, floatValue2);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(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 testSubArgImmFloat(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, Sub, Origin(), floatValue, constValue);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a - b)));
-}
-
-void testSubImmArgFloat(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, Sub, Origin(), constValue, floatValue);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a - b)));
-}
-
-void testSubImmsFloat(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, Sub, Origin(), constValue1, constValue2);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a - b)));
-}
-
-void testSubArgFloatWithUselessDoubleConversion(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, Sub, Origin(), asDouble, asDouble);
-    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a - a)));
-}
-
-void testSubArgsFloatWithUselessDoubleConversion(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* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
-    root->appendNewControlValue(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 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->appendNewControlValue(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 testTernarySubInstructionSelection(B3::Opcode valueModifier, Type valueType, Air::Opcode expectedOpcode)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* left = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* right = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-
-    if (valueModifier == Trunc) {
-        left = root->appendNew<Value>(proc, valueModifier, valueType, Origin(), left);
-        right = root->appendNew<Value>(proc, valueModifier, valueType, Origin(), right);
-    }
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sub, Origin(), left, right));
-
-    lowerToAirForTesting(proc);
-
-    auto block = proc.code()[0];
-    unsigned numberOfSubInstructions = 0;
-    for (auto instruction : *block) {
-        if (instruction.kind.opcode == expectedOpcode) {
-            CHECK_EQ(instruction.args.size(), 3ul);
-            CHECK_EQ(instruction.args[0].kind(), Air::Arg::Tmp);
-            CHECK_EQ(instruction.args[1].kind(), Air::Arg::Tmp);
-            CHECK_EQ(instruction.args[2].kind(), Air::Arg::Tmp);
-            numberOfSubInstructions++;
-        }
-    }
-    CHECK_EQ(numberOfSubInstructions, 1ul);
-}
-
-void testNegDouble(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Neg, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), -a));
-}
-
-void testNegFloat(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);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Neg, Origin(), floatValue));
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), -a));
-}
-
-void testNegFloatWithUselessDoubleConversion(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, Neg, Origin(), asDouble);
-    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), floatResult);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), -a));
-}
-
-void testBitAndArgs(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            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));
-}
-
-void testBitAndSameArg(int64_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            argument,
-            argument));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == a);
-}
-
-void testBitAndNotNot(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
-    Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const64Value>(proc, Origin(), -1));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            notA,
-            notB));
-
-    CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & ~b));
-}
-
-void testBitAndNotImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
-    Value* cstB = root->appendNew<Const64Value>(proc, Origin(), b);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            notA,
-            cstB));
-
-    CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & b));
-}
-
-void testBitAndImms(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc) == (a & b));
-}
-
-void testBitAndArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == (a & b));
-}
-
-void testBitAndImmArg(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    CHECK(compileAndRun<int64_t>(proc, b) == (a & b));
-}
-
-void testBitAndBitAndArgImmImm(int64_t a, int64_t b, int64_t c)
-{
-    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(), b));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            innerBitAnd,
-            root->appendNew<Const64Value>(proc, Origin(), c)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == ((a & b) & c));
-}
-
-void testBitAndImmBitAndArgImm(int64_t a, int64_t b, int64_t c)
-{
-    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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            innerBitAnd));
-
-    CHECK(compileAndRun<int64_t>(proc, b) == (a & (b & c)));
-}
-
-void testBitAndArgs32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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))));
-
-    CHECK(compileAndRun<int>(proc, a, b) == (a & b));
-}
-
-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));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            argument,
-            argument));
-
-    CHECK(compileAndRun<int>(proc, a) == a);
-}
-
-void testBitAndImms32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int>(proc) == (a & b));
-}
-
-void testBitAndArgImm32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int>(proc, a) == (a & b));
-}
-
-void testBitAndImmArg32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            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));
-}
-
-void testBitAndBitAndArgImmImm32(int a, int b, int c)
-{
-    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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            innerBitAnd,
-            root->appendNew<Const32Value>(proc, Origin(), c)));
-
-    CHECK(compileAndRun<int>(proc, a) == ((a & b) & c));
-}
-
-void testBitAndImmBitAndArgImm32(int a, int b, int c)
-{
-    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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitAnd, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            innerBitAnd));
-
-    CHECK(compileAndRun<int>(proc, b) == (a & (b & c)));
-}
-
-void testBitAndWithMaskReturnsBooleans(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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));
-
-    root->appendNewControlValue(proc, Return, Origin(), select);
-
-    int64_t expected = (a == b) ? -5 : 42;
-    CHECK(compileAndRun<int64_t>(proc, a, b) == expected);
-}
-
-double bitAndDouble(double a, double b)
-{
-    return bitwise_cast<double>(bitwise_cast<uint64_t>(a) & bitwise_cast<uint64_t>(b));
-}
-
-void testBitAndArgDouble(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argument, argument);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), bitAndDouble(a, a)));
-}
-
-void testBitAndArgsDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), bitAndDouble(a, b)));
-}
-
-void testBitAndArgImmDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), bitAndDouble(a, b)));
-}
-
-void testBitAndImmsDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<double>(proc), bitAndDouble(a, 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();
-    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->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), bitAndFloat(a, a)));
-}
-
-void testBitAndArgsFloat(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitAndFloat(a, b)));
-}
-
-void testBitAndArgImmFloat(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitAndFloat(a, b)));
-}
-
-void testBitAndImmsFloat(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc), bitAndFloat(a, b)));
-}
-
-void testBitAndArgsFloatWithUselessDoubleConversion(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), floatResult);
-
-    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 testBitOrArgs(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
-
-    CHECK(compileAndRun<int64_t>(proc, a, b) == (a | b));
-}
-
-void testBitOrSameArg(int64_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            argument,
-            argument));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == a);
-}
-
-void testBitOrAndAndArgs(int64_t a, int64_t b, int64_t c)
-{
-    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
-    // ((a & b) | (a & c))
-    // ((a & b) | (c & a))
-    // ((b & a) | (a & c))
-    // ((b & a) | (c & a))
-    for (int i = 0; i < 4; ++i) {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-        Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-        Value* argC = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-        Value* andAB = i & 2 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB)
-            : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA);
-        Value* andAC = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argC)
-            : root->appendNew<Value>(proc, BitAnd, Origin(), argC, argA);
-        root->appendNewControlValue(
-            proc, Return, Origin(),
-            root->appendNew<Value>(
-                proc, BitOr, Origin(),
-                andAB,
-                andAC));
-
-        CHECK_EQ(compileAndRun<int64_t>(proc, a, b, c), ((a & b) | (a & c)));
-    }
-}
-
-void testBitOrAndSameArgs(int64_t a, int64_t b)
-{
-    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
-    // ((a & b) | a)
-    // ((b & a) | a)
-    // (a | (a & b))
-    // (a | (b & a))
-    for (int i = 0; i < 4; ++i) {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-        Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-        Value* andAB = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB)
-            : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA);
-        Value* result = i & 2 ? root->appendNew<Value>(proc, BitOr, Origin(), andAB, argA)
-            : root->appendNew<Value>(proc, BitOr, Origin(), argA, andAB);
-        root->appendNewControlValue(proc, Return, Origin(), result);
-
-        CHECK_EQ(compileAndRun<int64_t>(proc, a, b), ((a & b) | a));
-    }
-}
-
-void testBitOrNotNot(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
-    Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const64Value>(proc, Origin(), -1));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            notA,
-            notB));
-
-    CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a | ~b));
-}
-
-void testBitOrNotImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
-    Value* cstB = root->appendNew<Const64Value>(proc, Origin(), b);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            notA,
-            cstB));
-    
-    CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a | b));
-}
-
-void testBitOrImms(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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));
-}
-
-void testBitOrArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == (a | b));
-}
-
-void testBitOrImmArg(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    CHECK(compileAndRun<int64_t>(proc, b) == (a | 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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            innerBitOr,
-            root->appendNew<Const64Value>(proc, Origin(), c)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == ((a | b) | c));
-}
-
-void testBitOrImmBitOrArgImm(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(), c));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            innerBitOr));
-
-    CHECK(compileAndRun<int64_t>(proc, b) == (a | (b | c)));
-}
-
-void testBitOrArgs32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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))));
-
-    CHECK(compileAndRun<int>(proc, a, b) == (a | b));
-}
-
-void testBitOrSameArg32(int a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            argument,
-            argument));
-
-    CHECK(compileAndRun<int>(proc, a) == a);
-}
-
-void testBitOrImms32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int>(proc) == (a | b));
-}
-
-void testBitOrArgImm32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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)));
-
-    CHECK(compileAndRun<int>(proc, a) == (a | b));
-}
-
-void testBitOrImmArg32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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<Const32Value>(proc, Origin(), b));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            innerBitOr,
-            root->appendNew<Const32Value>(proc, Origin(), c)));
-
-    CHECK(compileAndRun<int>(proc, a) == ((a | b) | c));
-}
-
-void testBitOrImmBitOrArgImm32(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<Const32Value>(proc, Origin(), c));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitOr, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            innerBitOr));
-
-    CHECK(compileAndRun<int>(proc, b) == (a | (b | c)));
-}
-
-double bitOrDouble(double a, double b)
-{
-    return bitwise_cast<double>(bitwise_cast<uint64_t>(a) | bitwise_cast<uint64_t>(b));
-}
-
-void testBitOrArgDouble(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* result = root->appendNew<Value>(proc, BitOr, Origin(), argument, argument);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), bitOrDouble(a, a)));
-}
-
-void testBitOrArgsDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
-    Value* result = root->appendNew<Value>(proc, BitOr, Origin(), argumentA, argumentB);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), bitOrDouble(a, b)));
-}
-
-void testBitOrArgImmDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
-    Value* result = root->appendNew<Value>(proc, BitOr, Origin(), argumentA, argumentB);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a, b), bitOrDouble(a, b)));
-}
-
-void testBitOrImmsDouble(double a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argumentA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
-    Value* result = root->appendNew<Value>(proc, BitOr, Origin(), argumentA, argumentB);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-    
-    CHECK(isIdentical(compileAndRun<double>(proc), bitOrDouble(a, b)));
-}
-
-float bitOrFloat(float a, float b)
-{
-    return bitwise_cast<float>(bitwise_cast<uint32_t>(a) | bitwise_cast<uint32_t>(b));
-}
-
-void testBitOrArgFloat(float a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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, BitOr, Origin(), argument, argument);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), bitOrFloat(a, a)));
-}
-
-void testBitOrArgsFloat(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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, BitOr, Origin(), argumentA, argumentB);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitOrFloat(a, b)));
-}
-
-void testBitOrArgImmFloat(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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, BitOr, Origin(), argumentA, argumentB);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitOrFloat(a, b)));
-}
-
-void testBitOrImmsFloat(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argumentA = root->appendNew<ConstFloatValue>(proc, Origin(), a);
-    Value* argumentB = root->appendNew<ConstFloatValue>(proc, Origin(), b);
-    Value* result = root->appendNew<Value>(proc, BitOr, Origin(), argumentA, argumentB);
-    root->appendNewControlValue(proc, Return, Origin(), result);
-
-    CHECK(isIdentical(compileAndRun<float>(proc), bitOrFloat(a, b)));
-}
-
-void testBitOrArgsFloatWithUselessDoubleConversion(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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, BitOr, Origin(), argumentAasDouble, argumentBasDouble);
-    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), doubleResult);
-    root->appendNewControlValue(proc, Return, Origin(), floatResult);
-    
-    double doubleA = a;
-    double doubleB = b;
-    float expected = static_cast<float>(bitOrDouble(doubleA, doubleB));
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), expected));
-}
-
-void testBitXorArgs(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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<int64_t>(proc, a, b) == (a ^ b));
-}
-
-void testBitXorSameArg(int64_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            argument,
-            argument));
-
-    CHECK(!compileAndRun<int64_t>(proc, a));
-}
-
-void testBitXorAndAndArgs(int64_t a, int64_t b, int64_t c)
-{
-    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
-    // ((a & b) ^ (a & c))
-    // ((a & b) ^ (c & a))
-    // ((b & a) ^ (a & c))
-    // ((b & a) ^ (c & a))
-    for (int i = 0; i < 4; ++i) {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-        Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-        Value* argC = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
-        Value* andAB = i & 2 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB)
-            : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA);
-        Value* andAC = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argC)
-            : root->appendNew<Value>(proc, BitAnd, Origin(), argC, argA);
-        root->appendNewControlValue(
-            proc, Return, Origin(),
-            root->appendNew<Value>(
-                proc, BitXor, Origin(),
-                andAB,
-                andAC));
-
-        CHECK_EQ(compileAndRun<int64_t>(proc, a, b, c), ((a & b) ^ (a & c)));
-    }
-}
-
-void testBitXorAndSameArgs(int64_t a, int64_t b)
-{
-    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
-    // ((a & b) ^ a)
-    // ((b & a) ^ a)
-    // (a ^ (a & b))
-    // (a ^ (b & a))
-    for (int i = 0; i < 4; ++i) {
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-        Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-        Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-        Value* andAB = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB)
-            : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA);
-        Value* result = i & 2 ? root->appendNew<Value>(proc, BitXor, Origin(), andAB, argA)
-            : root->appendNew<Value>(proc, BitXor, Origin(), argA, andAB);
-        root->appendNewControlValue(proc, Return, Origin(), result);
-        
-        CHECK_EQ(compileAndRun<int64_t>(proc, a, b), ((a & b) ^ a));
-    }
-}
-
-void testBitXorImms(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc) == (a ^ b));
-}
-
-void testBitXorArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const64Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == (a ^ b));
-}
-
-void testBitXorImmArg(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    CHECK(compileAndRun<int64_t>(proc, b) == (a ^ b));
-}
-
-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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            innerBitXor,
-            root->appendNew<Const64Value>(proc, Origin(), c)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == ((a ^ b) ^ c));
-}
-
-void testBitXorImmBitXorArgImm(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(), c));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            innerBitXor));
-
-    CHECK(compileAndRun<int64_t>(proc, b) == (a ^ (b ^ c)));
-}
-
-void testBitXorArgs32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, 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) == (a ^ b));
-}
-
-void testBitXorSameArg32(int a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            argument,
-            argument));
-
-    CHECK(!compileAndRun<int>(proc, a));
-}
-
-void testBitXorImms32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int>(proc) == (a ^ b));
-}
-
-void testBitXorArgImm32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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<int>(proc, a) == (a ^ b));
-}
-
-void testBitXorImmArg32(int a, int b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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<int>(proc, b) == (a ^ b));
-}
-
-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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            innerBitXor,
-            root->appendNew<Const32Value>(proc, Origin(), c)));
-
-    CHECK(compileAndRun<int>(proc, a) == ((a ^ b) ^ c));
-}
-
-void testBitXorImmBitXorArgImm32(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(), c));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            innerBitXor));
-
-    CHECK(compileAndRun<int>(proc, b) == (a ^ (b ^ c)));
-}
-
-void testBitNotArg(int64_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitXor, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), -1),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    CHECK(isIdentical(compileAndRun<int64_t>(proc, a), static_cast<int64_t>((static_cast<uint64_t>(a) ^ 0xffffffffffffffff))));
-}
-
-void testBitNotImm(int64_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            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 testBitNotMem(int64_t a)
-{
-    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* notLoad = root->appendNew<Value>(proc, BitXor, Origin(),
-        root->appendNew<Const64Value>(proc, Origin(), -1),
-        load);
-    root->appendNew<MemoryValue>(proc, Store, Origin(), notLoad, address);
-    root->appendNewControlValue(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->appendNewControlValue(
-        proc, Return, Origin(),
-        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 testBitNotImm32(int32_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            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 testBitNotMem32(int32_t a)
-{
-    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* notLoad = root->appendNew<Value>(proc, BitXor, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), -1),
-        load);
-    root->appendNew<MemoryValue>(proc, Store, Origin(), notLoad, address);
-    root->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    int32_t input = a;
-    compileAndRun<int32_t>(proc, &input);
-    CHECK(isIdentical(input, static_cast<int32_t>((static_cast<uint32_t>(a) ^ 0xffffffff))));
-}
-
-void testNotOnBooleanAndBranch32(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        argsAreNotEqual,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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 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* bitNotArgsAreEqual = root->appendNew<Value>(proc, BitXor, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), -1),
-        argsAreEqual);
-
-    root->appendNewControlValue(proc, Branch, Origin(),
-        bitNotArgsAreEqual, FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), -42));
-
-    static constexpr int32_t expectedValue = 42;
-    CHECK(compileAndRun<int32_t>(proc, a, b) == expectedValue);
-}
-
-void testShlArgs(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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))));
-
-    CHECK(compileAndRun<int64_t>(proc, a, b) == (a << b));
-}
-
-void testShlImms(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    b = b & 0x3f; // to avoid undefined behaviour below
-    CHECK(compileAndRun<int64_t>(proc) == (a << b));
-}
-
-void testShlArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    b = b & 0x3f; // to avoid undefined behaviour below
-    CHECK(compileAndRun<int64_t>(proc, a) == (a << b));
-}
-
-void testShlSShrArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* constB = root->appendNew<Const32Value>(proc, Origin(), b);
-    Value* innerShift = root->appendNew<Value>(proc, SShr, Origin(), argA, constB);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            innerShift,
-            constB));
-
-    b = b & 0x3f; // to avoid undefined behaviour below
-    CHECK(compileAndRun<int64_t>(proc, a) == ((a >> b) << b));
-}
-
-void testShlArg32(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Shl, Origin(), value, value));
-
-    CHECK(compileAndRun<int32_t>(proc, a) == (a << a));
-}
-
-void testShlArgs32(int32_t a, int32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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, a, b) == (a << b));
-}
-
-void testShlImms32(int32_t a, int32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    b = b & 0x1f; // to avoid undefined behaviour below
-    CHECK(compileAndRun<int32_t>(proc) == (a << b));
-}
-
-void testShlArgImm32(int32_t a, int32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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)));
-
-    b = b & 0x1f; // to avoid undefined behaviour below
-    CHECK(compileAndRun<int32_t>(proc, a) == (a << b));
-}
-
-void testShlZShrArgImm32(int32_t a, int32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argA = root->appendNew<Value>(
-        proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* constB = root->appendNew<Const32Value>(proc, Origin(), b);
-    Value* innerShift = root->appendNew<Value>(proc, ZShr, Origin(), argA, constB);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Shl, Origin(),
-            innerShift,
-            constB));
-
-    b = b & 0x1f; // to avoid undefined behaviour below
-    CHECK(compileAndRun<int32_t>(proc, a) == static_cast<int32_t>((static_cast<uint32_t>(a) >> b) << b));
-}
-
-void testSShrArgs(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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))));
-
-    CHECK(compileAndRun<int64_t>(proc, a, b) == (a >> b));
-}
-
-void testSShrImms(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, SShr, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc) == (a >> b));
-}
-
-void testSShrArgImm(int64_t a, int64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, SShr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int64_t>(proc, a) == (a >> b));
-}
-
-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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, SShr, Origin(), value, value));
-
-    CHECK(compileAndRun<int32_t>(proc, a) == (a >> (a & 31)));
-}
-
-void testSShrArgs32(int32_t a, int32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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))));
-
-    CHECK(compileAndRun<int32_t>(proc, a, b) == (a >> b));
-}
-
-void testSShrImms32(int32_t a, int32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, SShr, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<int32_t>(proc) == (a >> b));
-}
-
-void testSShrArgImm32(int32_t a, int32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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)));
-
-    CHECK(compileAndRun<int32_t>(proc, a) == (a >> b));
-}
-
-void testZShrArgs(uint64_t a, uint64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, ZShr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
-
-    CHECK(compileAndRun<uint64_t>(proc, a, b) == (a >> b));
-}
-
-void testZShrImms(uint64_t a, uint64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, ZShr, Origin(),
-            root->appendNew<Const64Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<uint64_t>(proc) == (a >> b));
-}
-
-void testZShrArgImm(uint64_t a, uint64_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, ZShr, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<uint64_t>(proc, a) == (a >> b));
-}
-
-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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, ZShr, Origin(), value, value));
-
-    CHECK(compileAndRun<uint32_t>(proc, a) == (a >> (a & 31)));
-}
-
-void testZShrArgs32(uint32_t a, uint32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, ZShr, 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<uint32_t>(proc, a, b) == (a >> b));
-}
-
-void testZShrImms32(uint32_t a, uint32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, ZShr, Origin(),
-            root->appendNew<Const32Value>(proc, Origin(), a),
-            root->appendNew<Const32Value>(proc, Origin(), b)));
-
-    CHECK(compileAndRun<uint32_t>(proc) == (a >> b));
-}
-
-void testZShrArgImm32(uint32_t a, uint32_t b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, ZShr, 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));
-}
-
-template<typename IntegerType>
-static unsigned countLeadingZero(IntegerType value)
-{
-    unsigned bitCount = sizeof(IntegerType) * 8;
-    if (!value)
-        return bitCount;
-
-    unsigned counter = 0;
-    while (!(static_cast<uint64_t>(value) & (1l << (bitCount - 1)))) {
-        value <<= 1;
-        ++counter;
-    }
-    return counter;
-}
-
-void testClzArg64(int64_t a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* clzValue = root->appendNew<Value>(proc, Clz, Origin(), argument);
-    root->appendNewControlValue(proc, Return, Origin(), clzValue);
-    CHECK(compileAndRun<unsigned>(proc, a) == countLeadingZero(a));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), clzValue);
-    CHECK(compileAndRun<unsigned>(proc, &a) == countLeadingZero(a));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), clzValue);
-    CHECK(compileAndRun<unsigned>(proc, a) == countLeadingZero(a));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), clzValue);
-    CHECK(compileAndRun<unsigned>(proc, &a) == countLeadingZero(a));
-}
-
-void testAbsArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Abs, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), fabs(a)));
-}
-
-void testAbsImm(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Abs, Origin(), argument));
-
-    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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Abs, Origin(), loadDouble));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, &a), fabs(a)));
-}
-
-void testAbsAbsArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = 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->appendNewControlValue(proc, Return, Origin(), secondAbs);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), fabs(fabs(a))));
-}
-
-void testAbsNegArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* neg = root->appendNew<Value>(proc, Neg, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
-    Value* abs = root->appendNew<Value>(proc, Abs, Origin(), neg);
-    root->appendNewControlValue(proc, Return, Origin(), abs);
-    
-    CHECK(isIdentical(compileAndRun<double>(proc, a), fabs(- a)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), absValue);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, bitwise_cast<int64_t>(a)), fabs(a)));
-}
-
-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);
-
-    root->appendNewControlValue(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 testAbsArg(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, Abs, Origin(), argument);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
-}
-
-void testAbsMem(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, Abs, Origin(), loadFloat);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), secondAbs);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), static_cast<float>(fabs(fabs(a)))));
-}
-
-void testAbsNegArg(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* neg = root->appendNew<Value>(proc, Neg, Origin(), argument);
-    Value* abs = root->appendNew<Value>(proc, Abs, Origin(), neg);
-    root->appendNewControlValue(proc, Return, Origin(), abs);
-    
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), static_cast<float>(fabs(- a))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), absValue);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), static_cast<float>(fabs(a))));
-}
-
-void testBitwiseCastAbsBitwiseCastArg(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);
-    Value* resultAsInt64 = root->appendNew<Value>(proc, BitwiseCast, Origin(), absValue);
-
-    root->appendNewControlValue(proc, Return, Origin(), resultAsInt64);
-
-    int32_t expectedResult = bitwise_cast<int32_t>(static_cast<float>(fabs(a)));
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), expectedResult));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    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, static_cast<double>(fabs(a))));
-}
-
-void testCeilArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Ceil, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(a)));
-}
-
-void testCeilImm(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Ceil, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<double>(proc), ceil(a)));
-}
-
-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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Ceil, Origin(), loadDouble));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, &a), ceil(a)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), secondCeil);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(a)));
-}
-
-void testFloorCeilArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* firstCeil = root->appendNew<Value>(proc, Ceil, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
-    Value* wrappingFloor = root->appendNew<Value>(proc, Floor, Origin(), firstCeil);
-    root->appendNewControlValue(proc, Return, Origin(), wrappingFloor);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(a)));
-}
-
-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);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Ceil, Origin(), argumentAsDouble));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(static_cast<double>(a))));
-}
-
-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);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Ceil, Origin(), argumentAsDouble));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(static_cast<double>(a))));
-}
-
-void testCeilArg(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, Ceil, Origin(), argument);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
-}
-
-void testCeilImm(float a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(ceilf(a))));
-}
-
-void testCeilCeilArg(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* firstCeil = root->appendNew<Value>(proc, Ceil, Origin(), argument);
-    Value* secondCeil = root->appendNew<Value>(proc, Ceil, Origin(), firstCeil);
-    root->appendNewControlValue(proc, Return, Origin(), secondCeil);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), ceilf(a)));
-}
-
-void testFloorCeilArg(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* firstCeil = root->appendNew<Value>(proc, Ceil, Origin(), argument);
-    Value* wrappingFloor = root->appendNew<Value>(proc, Floor, Origin(), firstCeil);
-    root->appendNewControlValue(proc, Return, Origin(), wrappingFloor);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), ceilf(a)));
-}
-
-void testCeilArgWithUselessDoubleConversion(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);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    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, static_cast<double>(ceilf(a))));
-}
-
-void testFloorArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Floor, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), floor(a)));
-}
-
-void testFloorImm(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Floor, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<double>(proc), floor(a)));
-}
-
-void testFloorMem(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Floor, Origin(), loadDouble));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, &a), floor(a)));
-}
-
-void testFloorFloorArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* firstFloor = root->appendNew<Value>(proc, Floor, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
-    Value* secondFloor = root->appendNew<Value>(proc, Floor, Origin(), firstFloor);
-    root->appendNewControlValue(proc, Return, Origin(), secondFloor);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), floor(a)));
-}
-
-void testCeilFloorArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* firstFloor = root->appendNew<Value>(proc, Floor, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
-    Value* wrappingCeil = root->appendNew<Value>(proc, Ceil, Origin(), firstFloor);
-    root->appendNewControlValue(proc, Return, Origin(), wrappingCeil);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), floor(a)));
-}
-
-void testFloorIToD64(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);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Floor, Origin(), argumentAsDouble));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), floor(static_cast<double>(a))));
-}
-
-void testFloorIToD32(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);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Floor, Origin(), argumentAsDouble));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), floor(static_cast<double>(a))));
-}
-
-void testFloorArg(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, Floor, Origin(), argument);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(floorf(a))));
-}
-
-void testFloorImm(float a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), a);
-    Value* result = root->appendNew<Value>(proc, Floor, Origin(), argument);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(floorf(a))));
-}
-
-void testFloorMem(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, Floor, Origin(), loadFloat);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(floorf(a))));
-}
-
-void testFloorFloorArg(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* firstFloor = root->appendNew<Value>(proc, Floor, Origin(), argument);
-    Value* secondFloor = root->appendNew<Value>(proc, Floor, Origin(), firstFloor);
-    root->appendNewControlValue(proc, Return, Origin(), secondFloor);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), floorf(a)));
-}
-
-void testCeilFloorArg(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* firstFloor = root->appendNew<Value>(proc, Floor, Origin(), argument);
-    Value* wrappingCeil = root->appendNew<Value>(proc, Ceil, Origin(), firstFloor);
-    root->appendNewControlValue(proc, Return, Origin(), wrappingCeil);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), floorf(a)));
-}
-
-void testFloorArgWithUselessDoubleConversion(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, Floor, Origin(), asDouble);
-    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
-    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
-    root->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(floorf(a))));
-}
-
-void testFloorArgWithEffectfulDoubleConversion(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, Floor, 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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    double effect = 0;
-    int32_t resultValue = compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), &effect);
-    CHECK(isIdentical(resultValue, bitwise_cast<int32_t>(floorf(a))));
-    CHECK(isIdentical(effect, static_cast<double>(floorf(a))));
-}
-
-double correctSqrt(double value)
-{
-#if CPU(X86) || CPU(X86_64)
-    double result;
-    asm ("sqrtsd %1, %0" : "=x"(result) : "x"(value));
-    return result;
-#else    
-    return sqrt(value);
-#endif
-}
-
-void testSqrtArg(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sqrt, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, a), correctSqrt(a)));
-}
-
-void testSqrtImm(double a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sqrt, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<double>(proc), correctSqrt(a)));
-}
-
-void testSqrtMem(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(proc, Sqrt, Origin(), loadDouble));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, &a), correctSqrt(a)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(correctSqrt(a)))));
-}
-
-void testSqrtImm(float a)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(correctSqrt(a)))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(static_cast<float>(correctSqrt(a)))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(correctSqrt(a)))));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), result32);
-
-    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>(correctSqrt(a)))));
-    double expected = static_cast<double>(correctSqrt(a));
-    CHECK(isIdentical(effect, expected));
-}
-
-void testCompareTwoFloatToDouble(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg1As32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg1Float = root->appendNew<Value>(proc, BitwiseCast, Origin(), arg1As32);
-    Value* arg1AsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), arg1Float);
-
-    Value* arg2As32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* arg2Float = root->appendNew<Value>(proc, BitwiseCast, Origin(), arg2As32);
-    Value* arg2AsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), arg2Float);
-    Value* equal = root->appendNew<Value>(proc, Equal, Origin(), arg1AsDouble, arg2AsDouble);
-
-    root->appendNewControlValue(proc, Return, Origin(), equal);
-
-    CHECK(compileAndRun<int64_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)) == (a == b));
-}
-
-void testCompareOneFloatToDouble(float a, double b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    Value* arg1As32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* arg1Float = root->appendNew<Value>(proc, BitwiseCast, Origin(), arg1As32);
-    Value* arg1AsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), arg1Float);
-
-    Value* arg2AsDouble = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* equal = root->appendNew<Value>(proc, Equal, Origin(), arg1AsDouble, arg2AsDouble);
-
-    root->appendNewControlValue(proc, Return, Origin(), equal);
-
-    CHECK(compileAndRun<int64_t>(proc, bitwise_cast<int32_t>(a), b) == (a == b));
-}
-
-void testCompareFloatToDoubleThroughPhi(float a, float b)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* tail = proc.addBlock();
-
-    Value* condition = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-
-    Value* arg1As32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* arg1Float = root->appendNew<Value>(proc, BitwiseCast, Origin(), arg1As32);
-    Value* arg1AsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), arg1Float);
-
-    Value* arg2AsDouble = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-    Value* arg2AsFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), arg2AsDouble);
-    Value* arg2AsFRoundedDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), arg2AsFloat);
-
-    root->appendNewControlValue(
-        proc, Branch, Origin(),
-        condition,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    UpsilonValue* thenValue = thenCase->appendNew<UpsilonValue>(proc, Origin(), arg1AsDouble);
-    thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* elseConst = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), 0.);
-    UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), elseConst);
-    elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* doubleInput = tail->appendNew<Value>(proc, Phi, Double, Origin());
-    thenValue->setPhi(doubleInput);
-    elseValue->setPhi(doubleInput);
-    Value* equal = tail->appendNew<Value>(proc, Equal, Origin(), doubleInput, arg2AsFRoundedDouble);
-    tail->appendNewControlValue(proc, Return, Origin(), equal);
-
-    auto code = compileProc(proc);
-    int32_t integerA = bitwise_cast<int32_t>(a);
-    double doubleB = b;
-    CHECK(invoke<int64_t>(*code, 1, integerA, doubleB) == (a == b));
-    CHECK(invoke<int64_t>(*code, 0, integerA, doubleB) == (b == 0));
-}
-
-void testDoubleToFloatThroughPhi(float value)
-{
-    // Simple case of:
-    //     if (a) {
-    //         x = DoubleAdd(a, b)
-    //     else
-    //         x = DoubleAdd(a, c)
-    //     DoubleToFloat(x)
-    //
-    // Both Adds can be converted to float add.
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* tail = proc.addBlock();
-
-    Value* condition = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
-    Value* argAsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
-
-    root->appendNewControlValue(
-        proc, Branch, Origin(),
-        condition,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    Value* postitiveConst = thenCase->appendNew<ConstDoubleValue>(proc, Origin(), 42.5f);
-    Value* thenAdd = thenCase->appendNew<Value>(proc, Add, Origin(), argAsDouble, postitiveConst);
-    UpsilonValue* thenValue = thenCase->appendNew<UpsilonValue>(proc, Origin(), thenAdd);
-    thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* elseConst = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), M_PI);
-    UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), elseConst);
-    elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* doubleInput = tail->appendNew<Value>(proc, Phi, Double, Origin());
-    thenValue->setPhi(doubleInput);
-    elseValue->setPhi(doubleInput);
-    Value* floatResult = tail->appendNew<Value>(proc, DoubleToFloat, Origin(), doubleInput);
-    tail->appendNewControlValue(proc, Return, Origin(), floatResult);
-
-    auto code = compileProc(proc);
-    CHECK(isIdentical(invoke<float>(*code, 1, bitwise_cast<int32_t>(value)), value + 42.5f));
-    CHECK(isIdentical(invoke<float>(*code, 0, bitwise_cast<int32_t>(value)), static_cast<float>(M_PI)));
-}
-
-void testReduceFloatToDoubleValidates()
-{
-    // Simple case of:
-    //     f = DoubleToFloat(Bitcast(argGPR0))
-    //     if (a) {
-    //         x = FloatConst()
-    //     else
-    //         x = FloatConst()
-    //     p = Phi(x)
-    //     a = Mul(p, p)
-    //     b = Add(a, f)
-    //     c = Add(p, b)
-    //     Return(c)
-    //
-    // This should not crash in the validator after ReduceFloatToDouble.
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* tail = proc.addBlock();
-
-    Value* condition = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* thingy = root->appendNew<Value>(proc, BitwiseCast, Origin(), condition);
-    thingy = root->appendNew<Value>(proc, DoubleToFloat, Origin(), thingy); // Make the phase think it has work to do.
-    root->appendNewControlValue(
-        proc, Branch, Origin(),
-        condition,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    UpsilonValue* thenValue = thenCase->appendNew<UpsilonValue>(proc, Origin(),
-        thenCase->appendNew<ConstFloatValue>(proc, Origin(), 11.5));
-    thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), 
-        elseCase->appendNew<ConstFloatValue>(proc, Origin(), 10.5));
-    elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* phi =  tail->appendNew<Value>(proc, Phi, Float, Origin());
-    thenValue->setPhi(phi);
-    elseValue->setPhi(phi);
-    Value* result = tail->appendNew<Value>(proc, Mul, Origin(), 
-            phi, phi);
-    result = tail->appendNew<Value>(proc, Add, Origin(), 
-            result,
-            thingy);
-    result = tail->appendNew<Value>(proc, Add, Origin(), 
-            phi,
-            result);
-    tail->appendNewControlValue(proc, Return, Origin(), result);
-
-    auto code = compileProc(proc);
-    CHECK(isIdentical(invoke<float>(*code, 1), 11.5f * 11.5f + static_cast<float>(bitwise_cast<double>(static_cast<uint64_t>(1))) + 11.5f));
-    CHECK(isIdentical(invoke<float>(*code, 0), 10.5f * 10.5f + static_cast<float>(bitwise_cast<double>(static_cast<uint64_t>(0))) + 10.5f));
-}
-
-void testDoubleProducerPhiToFloatConversion(float value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* tail = proc.addBlock();
-
-    Value* condition = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
-
-    root->appendNewControlValue(
-        proc, Branch, Origin(),
-        condition,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    Value* asDouble = thenCase->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
-    UpsilonValue* thenValue = thenCase->appendNew<UpsilonValue>(proc, Origin(), asDouble);
-    thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* constDouble = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), 42.5);
-    UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), constDouble);
-    elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* doubleInput = tail->appendNew<Value>(proc, Phi, Double, Origin());
-    thenValue->setPhi(doubleInput);
-    elseValue->setPhi(doubleInput);
-
-    Value* argAsDoubleAgain = tail->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
-    Value* finalAdd = tail->appendNew<Value>(proc, Add, Origin(), doubleInput, argAsDoubleAgain);
-    Value* floatResult = tail->appendNew<Value>(proc, DoubleToFloat, Origin(), finalAdd);
-    tail->appendNewControlValue(proc, Return, Origin(), floatResult);
-
-    auto code = compileProc(proc);
-    CHECK(isIdentical(invoke<float>(*code, 1, bitwise_cast<int32_t>(value)), value + value));
-    CHECK(isIdentical(invoke<float>(*code, 0, bitwise_cast<int32_t>(value)), 42.5f + value));
-}
-
-void testDoubleProducerPhiToFloatConversionWithDoubleConsumer(float value)
-{
-    // In this case, the Upsilon-Phi effectively contains a Float value, but it is used
-    // as a Float and as a Double.
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* tail = proc.addBlock();
-
-    Value* condition = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
-
-    root->appendNewControlValue(
-        proc, Branch, Origin(),
-        condition,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    Value* asDouble = thenCase->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
-    UpsilonValue* thenValue = thenCase->appendNew<UpsilonValue>(proc, Origin(), asDouble);
-    thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* constDouble = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), 42.5);
-    UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), constDouble);
-    elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* doubleInput = tail->appendNew<Value>(proc, Phi, Double, Origin());
-    thenValue->setPhi(doubleInput);
-    elseValue->setPhi(doubleInput);
-
-    Value* argAsDoubleAgain = tail->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
-    Value* floatAdd = tail->appendNew<Value>(proc, Add, Origin(), doubleInput, argAsDoubleAgain);
-
-    // FRound.
-    Value* floatResult = tail->appendNew<Value>(proc, DoubleToFloat, Origin(), floatAdd);
-    Value* doubleResult = tail->appendNew<Value>(proc, FloatToDouble, Origin(), floatResult);
-
-    // This one *cannot* be eliminated
-    Value* doubleAdd = tail->appendNew<Value>(proc, Add, Origin(), doubleInput, doubleResult);
-
-    tail->appendNewControlValue(proc, Return, Origin(), doubleAdd);
-
-    auto code = compileProc(proc);
-    CHECK(isIdentical(invoke<double>(*code, 1, bitwise_cast<int32_t>(value)), (value + value) + static_cast<double>(value)));
-    CHECK(isIdentical(invoke<double>(*code, 0, bitwise_cast<int32_t>(value)), static_cast<double>((42.5f + value) + 42.5f)));
-}
-
-void testDoubleProducerPhiWithNonFloatConst(float value, double constValue)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-    BasicBlock* tail = proc.addBlock();
-
-    Value* condition = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
-
-    root->appendNewControlValue(
-        proc, Branch, Origin(),
-        condition,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    Value* asDouble = thenCase->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
-    UpsilonValue* thenValue = thenCase->appendNew<UpsilonValue>(proc, Origin(), asDouble);
-    thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* constDouble = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), constValue);
-    UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), constDouble);
-    elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail));
-
-    Value* doubleInput = tail->appendNew<Value>(proc, Phi, Double, Origin());
-    thenValue->setPhi(doubleInput);
-    elseValue->setPhi(doubleInput);
-
-    Value* argAsDoubleAgain = tail->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
-    Value* finalAdd = tail->appendNew<Value>(proc, Add, Origin(), doubleInput, argAsDoubleAgain);
-    Value* floatResult = tail->appendNew<Value>(proc, DoubleToFloat, Origin(), finalAdd);
-    tail->appendNewControlValue(proc, Return, Origin(), floatResult);
-
-    auto code = compileProc(proc);
-    CHECK(isIdentical(invoke<float>(*code, 1, bitwise_cast<int32_t>(value)), value + value));
-    CHECK(isIdentical(invoke<float>(*code, 0, bitwise_cast<int32_t>(value)), static_cast<float>(constValue + value)));
-}
-
-void testDoubleArgToInt64BitwiseCast(double value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitwiseCast, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<int64_t>(proc, value), bitwise_cast<int64_t>(value)));
-}
-
-void testDoubleImmToInt64BitwiseCast(double value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), value);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitwiseCast, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<int64_t>(proc), bitwise_cast<int64_t>(value)));
-}
-
-void testTwoBitwiseCastOnDouble(double value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), second);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, value), value));
-}
-
-void testBitwiseCastOnDoubleInMemory(double value)
-{
-    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);
-    Value* cast = root->appendNew<Value>(proc, BitwiseCast, Origin(), loadDouble);
-    root->appendNewControlValue(proc, Return, Origin(), cast);
-
-    CHECK(isIdentical(compileAndRun<int64_t>(proc, &value), bitwise_cast<int64_t>(value)));
-}
-
-void testBitwiseCastOnDoubleInMemoryIndexed(double value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(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->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitwiseCast, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<double>(proc, value), bitwise_cast<double>(value)));
-}
-
-void testInt64BImmToDoubleBitwiseCast(int64_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<Const64Value>(proc, Origin(), value);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitwiseCast, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<double>(proc), bitwise_cast<double>(value)));
-}
-
-void testTwoBitwiseCastOnInt64(int64_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->appendNewControlValue(proc, Return, Origin(), second);
-
-    CHECK(isIdentical(compileAndRun<int64_t>(proc, value), value));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), cast);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, &value), bitwise_cast<double>(value)));
-}
-
-void testBitwiseCastOnInt64InMemoryIndexed(int64_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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, Int64, Origin(), address);
-    Value* cast = root->appendNew<Value>(proc, BitwiseCast, Origin(), loadDouble);
-    root->appendNewControlValue(proc, Return, Origin(), cast);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, &value, 0), bitwise_cast<double>(value)));
-}
-
-void testFloatImmToInt32BitwiseCast(float value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), value);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitwiseCast, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(value)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), cast);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, &value), bitwise_cast<int32_t>(value)));
-}
-
-void testInt32BArgToFloatBitwiseCast(int32_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitwiseCast, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<float>(proc, value), bitwise_cast<float>(value)));
-}
-
-void testInt32BImmToFloatBitwiseCast(int32_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<Const64Value>(proc, Origin(), value);
-
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, BitwiseCast, Origin(), argument));
-
-    CHECK(isIdentical(compileAndRun<float>(proc), bitwise_cast<float>(value)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), second);
-
-    CHECK(isIdentical(compileAndRun<int32_t>(proc, value), value));
-}
-
-void testBitwiseCastOnInt32InMemory(int32_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), cast);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, &value), bitwise_cast<float>(value)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), asFloat);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, value), static_cast<float>(value)));
-}
-
-void testConvertDoubleToFloatImm(double value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), value);
-    Value* asFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument);
-    root->appendNewControlValue(proc, Return, Origin(), asFloat);
-
-    CHECK(isIdentical(compileAndRun<float>(proc), static_cast<float>(value)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), asFloat);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, &value), static_cast<float>(value)));
-}
-
-void testConvertFloatToDoubleArg(float value)
-{
-    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);
-    root->appendNewControlValue(proc, Return, Origin(), asDouble);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, bitwise_cast<int32_t>(value)), static_cast<double>(value)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), asDouble);
-
-    CHECK(isIdentical(compileAndRun<double>(proc), static_cast<double>(value)));
-}
-
-void testConvertFloatToDoubleMem(float value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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->appendNewControlValue(proc, Return, Origin(), asDouble);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, &value), static_cast<double>(value)));
-}
-
-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->appendNewControlValue(proc, Return, Origin(), asFloatAgain);
-
-    CHECK(isIdentical(compileAndRun<float>(proc, value), static_cast<float>(value)));
-}
-
-void testLoadFloatConvertDoubleConvertFloatStoreFloat(float value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    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);
-
-    root->appendNewControlValue(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    float input = value;
-    float output = 0.;
-    CHECK(!compileAndRun<int64_t>(proc, &input, &output));
-    CHECK(isIdentical(input, output));
-}
-
-void testFroundArg(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);
-    root->appendNewControlValue(proc, Return, Origin(), asDouble);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, value), static_cast<double>(static_cast<float>(value))));
-}
-
-void testFroundMem(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);
-    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), asFloat);
-    root->appendNewControlValue(proc, Return, Origin(), asDouble);
-
-    CHECK(isIdentical(compileAndRun<double>(proc, &value), static_cast<double>(static_cast<float>(value))));
-}
-
-void testIToD64Arg()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* srcAsDouble = root->appendNew<Value>(proc, IToD, Origin(), src);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsDouble);
-
-    auto code = compileProc(proc);
-    for (auto testValue : int64Operands())
-        CHECK(isIdentical(invoke<double>(*code, testValue.value), static_cast<double>(testValue.value)));
-}
-
-void testIToF64Arg()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* srcAsFloat = root->appendNew<Value>(proc, IToF, Origin(), src);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsFloat);
-
-    auto code = compileProc(proc);
-    for (auto testValue : int64Operands())
-        CHECK(isIdentical(invoke<float>(*code, testValue.value), static_cast<float>(testValue.value)));
-}
-
-void testIToD32Arg()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* srcAsDouble = root->appendNew<Value>(proc, IToD, Origin(), src);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsDouble);
-
-    auto code = compileProc(proc);
-    for (auto testValue : int32Operands())
-        CHECK(isIdentical(invoke<double>(*code, testValue.value), static_cast<double>(testValue.value)));
-}
-
-void testIToF32Arg()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* srcAsFloat = root->appendNew<Value>(proc, IToF, Origin(), src);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsFloat);
-
-    auto code = compileProc(proc);
-    for (auto testValue : int32Operands())
-        CHECK(isIdentical(invoke<float>(*code, testValue.value), static_cast<float>(testValue.value)));
-}
-
-void testIToD64Mem()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    MemoryValue* loadedSrc = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
-    Value* srcAsDouble = root->appendNew<Value>(proc, IToD, Origin(), loadedSrc);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsDouble);
-
-    auto code = compileProc(proc);
-    int64_t inMemoryValue;
-    for (auto testValue : int64Operands()) {
-        inMemoryValue = testValue.value;
-        CHECK(isIdentical(invoke<double>(*code, &inMemoryValue), static_cast<double>(testValue.value)));
-        CHECK(inMemoryValue == testValue.value);
-    }
-}
-
-void testIToF64Mem()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    MemoryValue* loadedSrc = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
-    Value* srcAsFloat = root->appendNew<Value>(proc, IToF, Origin(), loadedSrc);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsFloat);
-
-    auto code = compileProc(proc);
-    int64_t inMemoryValue;
-    for (auto testValue : int64Operands()) {
-        inMemoryValue = testValue.value;
-        CHECK(isIdentical(invoke<float>(*code, &inMemoryValue), static_cast<float>(testValue.value)));
-        CHECK(inMemoryValue == testValue.value);
-    }
-}
-
-void testIToD32Mem()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    MemoryValue* loadedSrc = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
-    Value* srcAsDouble = root->appendNew<Value>(proc, IToD, Origin(), loadedSrc);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsDouble);
-
-    auto code = compileProc(proc);
-    int32_t inMemoryValue;
-    for (auto testValue : int32Operands()) {
-        inMemoryValue = testValue.value;
-        CHECK(isIdentical(invoke<double>(*code, &inMemoryValue), static_cast<double>(testValue.value)));
-        CHECK(inMemoryValue == testValue.value);
-    }
-}
-
-void testIToF32Mem()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    MemoryValue* loadedSrc = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
-    Value* srcAsFloat = root->appendNew<Value>(proc, IToF, Origin(), loadedSrc);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsFloat);
-
-    auto code = compileProc(proc);
-    int32_t inMemoryValue;
-    for (auto testValue : int32Operands()) {
-        inMemoryValue = testValue.value;
-        CHECK(isIdentical(invoke<float>(*code, &inMemoryValue), static_cast<float>(testValue.value)));
-        CHECK(inMemoryValue == testValue.value);
-    }
-}
-
-void testIToD64Imm(int64_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<Const64Value>(proc, Origin(), value);
-    Value* srcAsFloatingPoint = root->appendNew<Value>(proc, IToD, Origin(), src);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsFloatingPoint);
-    CHECK(isIdentical(compileAndRun<double>(proc), static_cast<double>(value)));
-}
-
-void testIToF64Imm(int64_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<Const64Value>(proc, Origin(), value);
-    Value* srcAsFloatingPoint = root->appendNew<Value>(proc, IToF, Origin(), src);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsFloatingPoint);
-    CHECK(isIdentical(compileAndRun<float>(proc), static_cast<float>(value)));
-}
-
-void testIToD32Imm(int32_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<Const32Value>(proc, Origin(), value);
-    Value* srcAsFloatingPoint = root->appendNew<Value>(proc, IToD, Origin(), src);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsFloatingPoint);
-    CHECK(isIdentical(compileAndRun<double>(proc), static_cast<double>(value)));
-}
-
-void testIToF32Imm(int32_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<Const32Value>(proc, Origin(), value);
-    Value* srcAsFloatingPoint = root->appendNew<Value>(proc, IToF, Origin(), src);
-    root->appendNewControlValue(proc, Return, Origin(), srcAsFloatingPoint);
-    CHECK(isIdentical(compileAndRun<float>(proc), static_cast<float>(value)));
-}
-
-void testIToDReducedToIToF64Arg()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* srcAsDouble = root->appendNew<Value>(proc, IToD, Origin(), src);
-    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), srcAsDouble);
-    root->appendNewControlValue(proc, Return, Origin(), floatResult);
-
-    auto code = compileProc(proc);
-    for (auto testValue : int64Operands())
-        CHECK(isIdentical(invoke<float>(*code, testValue.value), static_cast<float>(testValue.value)));
-}
-
-void testIToDReducedToIToF32Arg()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* src = root->appendNew<Value>(proc, Trunc, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* srcAsDouble = root->appendNew<Value>(proc, IToD, Origin(), src);
-    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), srcAsDouble);
-    root->appendNewControlValue(proc, Return, Origin(), floatResult);
-
-    auto code = compileProc(proc);
-    for (auto testValue : int32Operands())
-        CHECK(isIdentical(invoke<float>(*code, testValue.value), static_cast<float>(testValue.value)));
-}
-
-void testStore32(int value)
-{
-    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), 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc, value));
-    CHECK(slot == value);
-}
-
-void testStoreConstant(int value)
-{
-    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), 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == value);
-}
-
-void testStoreConstantPtr(intptr_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    intptr_t slot;
-#if CPU(ADDRESS64)
-    slot = (static_cast<intptr_t>(0xbaadbeef) << 32) + static_cast<intptr_t>(0xbaadbeef);
-#else
-    slot = 0xbaadbeef;
-#endif
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
-        root->appendNew<ConstPtrValue>(proc, Origin(), value),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == value);
-}
-
-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->appendNewControlValue(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->appendNewControlValue(proc, Return, Origin(), value);
-
-        int8_t storage = 0;
-        CHECK(compileAndRun<int64_t>(proc, 42, &storage, 1) == 42);
-        CHECK(storage == 42);
-    }
-}
-
-void testStore8Imm()
-{
-    { // 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, Store8, Origin(), value, address);
-        root->appendNewControlValue(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->appendNewControlValue(proc, Return, Origin(), value);
-
-        int8_t storage = 0;
-        CHECK(compileAndRun<int64_t>(proc, &storage, 1) == 42);
-        CHECK(storage == 42);
-    }
-}
-
-void testStorePartial8BitRegisterOnX86()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-
-    // 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) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            jit.xor64(params[0].gpr(), params[0].gpr());
-        });
-
-    // 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);
-
-    root->appendNewControlValue(proc, Return, Origin(), returnValue);
-
-    int8_t storage = 0xff;
-    CHECK(compileAndRun<int64_t>(proc, 0x12345678abcdef12, &storage) == 0x12345678abcdef12);
-    CHECK(!storage);
-}
-
-void testStore16Arg()
-{
-    { // Direct addressing.
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-
-        Value* value = root->appendNew<Value>(proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-        Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-
-        root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address);
-        root->appendNewControlValue(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->appendNewControlValue(proc, Return, Origin(), value);
-
-        int16_t storage = -1;
-        CHECK(compileAndRun<int64_t>(proc, 42, &storage, 1) == 42);
-        CHECK(storage == 42);
-    }
-}
-
-void testStore16Imm()
-{
-    { // Direct addressing.
-        Procedure proc;
-        BasicBlock* root = proc.addBlock();
-
-        Value* value = root->appendNew<Const32Value>(proc, Origin(), 42);
-        Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-
-        root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address);
-        root->appendNewControlValue(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->appendNewControlValue(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();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    CHECK(compileAndRun<int>(proc, value) == static_cast<int>(value));
-}
-
-void testAdd1(int value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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)));
-
-    CHECK(compileAndRun<int>(proc, value) == value + 1);
-}
-
-void testAdd1Ptr(intptr_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-            root->appendNew<ConstPtrValue>(proc, Origin(), 1)));
-
-    CHECK(compileAndRun<intptr_t>(proc, value) == value + 1);
-}
-
-void testNeg32(int32_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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))));
-
-    CHECK(compileAndRun<int32_t>(proc, value) == -value);
-}
-
-void testNegPtr(intptr_t value)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Value>(
-            proc, Sub, Origin(),
-            root->appendNew<ConstPtrValue>(proc, Origin(), 0),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
-
-    CHECK(compileAndRun<intptr_t>(proc, value) == -value);
-}
-
-void testStoreAddLoad32(int amount)
-{
-    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<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr, 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc, amount));
-    CHECK(slot == 37 + amount);
-}
-
-void testStoreRelAddLoadAcq32(int amount)
-{
-    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, 0, HeapRange(42), HeapRange(42)),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr, 0, HeapRange(42), HeapRange(42));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(proc);
-    if (isARM64()) {
-        checkUsesInstruction(*code, "lda");
-        checkUsesInstruction(*code, "stl");
-    }
-    if (isX86())
-        checkUsesInstruction(*code, "xchg");
-    CHECK(!invoke<int>(*code, amount));
-    CHECK(slot == 37 + amount);
-}
-
-void testStoreAddLoadImm32(int amount)
-{
-    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, 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == 37 + amount);
-}
-
-void testStoreAddLoad8(int amount, B3::Opcode loadOpcode)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    int8_t slot = 37;
-    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
-    root->appendNew<MemoryValue>(
-        proc, Store8, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr, 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc, amount));
-    CHECK(slot == 37 + amount);
-}
-
-void testStoreRelAddLoadAcq8(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, 0, HeapRange(42), HeapRange(42)),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr, 0, HeapRange(42), HeapRange(42));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(proc);
-    if (isARM64()) {
-        checkUsesInstruction(*code, "lda");
-        checkUsesInstruction(*code, "stl");
-    }
-    if (isX86())
-        checkUsesInstruction(*code, "xchg");
-    CHECK(!invoke<int>(*code, amount));
-    CHECK(slot == 37 + amount);
-}
-
-void testStoreRelAddFenceLoadAcq8(int amount, B3::Opcode loadOpcode)
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    int8_t slot = 37;
-    ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot);
-    Value* loadedValue = root->appendNew<MemoryValue>(
-        proc, loadOpcode, Origin(), slotPtr, 0, HeapRange(42), HeapRange(42));
-    PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
-    patchpoint->clobber(RegisterSet::macroScratchRegisters());
-    patchpoint->setGenerator(
-        [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
-            AllowMacroScratchRegisterUsage allowScratch(jit);
-            jit.store8(CCallHelpers::TrustedImm32(0xbeef), &slot);
-        });
-    patchpoint->effects = Effects::none();
-    patchpoint->effects.fence = true;
-    root->appendNew<MemoryValue>(
-        proc, Store8, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            loadedValue,
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr, 0, HeapRange(42), HeapRange(42));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(proc);
-    if (isARM64()) {
-        checkUsesInstruction(*code, "lda");
-        checkUsesInstruction(*code, "stl");
-    }
-    if (isX86())
-        checkUsesInstruction(*code, "xchg");
-    CHECK(!invoke<int>(*code, amount));
-    CHECK(slot == 37 + amount);
-}
-
-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, 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc));
-    CHECK(slot == 37 + amount);
-}
-
-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, 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc, amount));
-    CHECK(slot == 37 + amount);
-}
-
-void testStoreRelAddLoadAcq16(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, 0, HeapRange(42), HeapRange(42)),
-            root->appendNew<Value>(
-                proc, Trunc, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr, 0, HeapRange(42), HeapRange(42));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(proc);
-    if (isARM64()) {
-        checkUsesInstruction(*code, "lda");
-        checkUsesInstruction(*code, "stl");
-    }
-    if (isX86())
-        checkUsesInstruction(*code, "xchg");
-    CHECK(!invoke<int>(*code, amount));
-    CHECK(slot == 37 + amount);
-}
-
-void testStoreAddLoadImm16(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<Const32Value>(proc, Origin(), amount)),
-        slotPtr, 0);
-    root->appendNewControlValue(
-        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, 0);
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    CHECK(!compileAndRun<int>(proc, amount));
-    CHECK(slot == 37000000000ll + amount);
-}
-
-void testStoreRelAddLoadAcq64(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, 0, HeapRange(42), HeapRange(42)),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        slotPtr, 0, HeapRange(42), HeapRange(42));
-    root->appendNewControlValue(
-        proc, Return, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(proc);
-    if (isARM64()) {
-        checkUsesInstruction(*code, "lda");
-        checkUsesInstruction(*code, "stl");
-    }
-    if (isX86())
-        checkUsesInstruction(*code, "xchg");
-    CHECK(!invoke<int>(*code, 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, 0);
-    root->appendNewControlValue(
-        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, 0);
-    root->appendNewControlValue(
-        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, 0);
-    root->appendNewControlValue(
-        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->appendNewControlValue(
-        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->appendNewControlValue(
-        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->appendNewControlValue(
-        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->appendNewControlValue(
-        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, 0);
-    root->appendNewControlValue(
-        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, 0);
-    root->appendNewControlValue(
-        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, 0);
-    root->appendNewControlValue(
-        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, 0);
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(),
-        root->appendNew<Value>(
-            proc, Add, Origin(),
-            load, root->appendNew<Const32Value>(proc, Origin(), amount)),
-        slotPtr, 0);
-    root->appendNewControlValue(
-        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, 0);
-    root->appendNewControlValue(
-        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, 0);
-    
-    root->appendNewControlValue(
-        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, 0);
-    
-    root->appendNewControlValue(
-        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->appendNewControlValue(
-        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->appendNewControlValue(
-        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, static_cast<int32_t>(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->appendNewControlValue(
-        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, static_cast<int32_t>(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->appendNewControlValue(
-        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(), static_cast<int32_t>(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(), static_cast<int32_t>(sizeof(int)))));
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, 0);
-    root->appendNew<MemoryValue>(
-        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, static_cast<int32_t>(sizeof(int)));
-    root->appendNewControlValue(
-        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->appendNewControlValue(
-        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(), static_cast<int32_t>(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->appendNewControlValue(
-        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->appendNewControlValue(
-        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->appendNewControlValue(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->appendNewControlValue(proc, Return, Origin(), result);
-        CHECK(compileAndRun<int64_t>(proc, 1, 2));
-    }
-}
-
-void testStackSlot()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    root->appendNewControlValue(
-        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->appendNewControlValue(
-        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, 0);
-    
-    root->appendNewControlValue(
-        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->appendNewControlValue(
-            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->appendNewControlValue(
-            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->appendNewControlValue(
-            proc, Return, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, opcode, type, Origin(),
-                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                static_cast<int32_t>(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->appendNewControlValue(
-            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->appendNewControlValue(
-            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->appendNewControlValue(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->appendNewControlValue(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 testStoreDoubleConstantAsFloat(double input)
-{
-    // Simple store from an address in a register.
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    Value* value = root->appendNew<ConstDoubleValue>(proc, Origin(), input);
-    Value* valueAsFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), value);
-
-    Value* destinationAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-
-    root->appendNew<MemoryValue>(proc, Store, Origin(), valueAsFloat, destinationAddress);
-
-    root->appendNewControlValue(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));
-}
-
-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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        decCounter,
-        FrequentedBlock(loop), FrequentedBlock(done));
-
-    // Tail.
-    done->appendNewControlValue(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->appendNewControlValue(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        decCounter,
-        FrequentedBlock(loop), FrequentedBlock(done));
-
-    // Tail.
-    done->appendNewControlValue(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, Trunc, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        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->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(done));
-
-    UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(
-        proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-    elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(done));
-
-    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
-    thenResult->setPhi(phi);
-    elseResult->setPhi(phi);
-    done->appendNewControlValue(proc, Return, Origin(), phi);
-
-    auto code = compileProc(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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    auto code = compileProc(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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    auto code = compileProc(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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    auto code = compileProc(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argumentA,
-            argumentB),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argumentA,
-            argumentB),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        notEqualAndOrdered,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        notEqualAndOrdered,
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argumentA,
-            argumentB),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argumentA,
-            argumentB),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argumentA,
-            argumentB),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argumentA,
-            argumentB),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, EqualOrUnordered, Origin(),
-            argument1AsDouble,
-            argument2AsDouble),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 42));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Const32Value>(proc, Origin(), value),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        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->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(done));
-
-    UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(
-        proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-    elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(done));
-
-    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
-    thenResult->setPhi(phi);
-    elseResult->setPhi(phi);
-    done->appendNewControlValue(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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load, pointerType(), Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load, Int32, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load8S, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load8Z, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load16S, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(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->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<MemoryValue>(
-            proc, Load16Z, Origin(),
-            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(proc);
-    uint16_t cond;
-    cond = 1;
-    CHECK(invoke<int>(*code, &cond) == 1);
-    cond = 0;
-    CHECK(invoke<int>(*code, &cond) == 0);
-}
-
-void testBranch8WithLoad8ZIndex()
-{
-    Procedure proc;
-    BasicBlock* root = proc.addBlock();
-    BasicBlock* thenCase = proc.addBlock();
-    BasicBlock* elseCase = proc.addBlock();
-
-    int logScale = 1;
-    root->appendNewControlValue(
-        proc, Branch, Origin(),
-        root->appendNew<Value>(
-            proc, Above, Origin(),
-            root->appendNew<MemoryValue>(
-                proc, Load8Z, Origin(),
-                root->appendNew<Value>(
-                    proc, Add, Origin(),
-                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                    root->appendNew<Value>(
-                        proc, Shl, Origin(),
-                        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
-                        root->appendNew<Const32Value>(proc, Origin(), logScale)))),
-            root->appendNew<Const32Value>(proc, Origin(), 250)),
-        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
-
-    thenCase->appendNewControlValue(
-        proc, Return, Origin(),
-        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
-
-    elseCase->appendNewControlValue(
-        proc, Return, Origin(),
-        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
-
-    auto code = compileProc(proc);
-    uint32_t cond;
-    cond = 0xffffffffU; // All bytes are 0xff.
-    CHECK(invoke<int>(*code, &cond - 2, (sizeof(uint32_t) * 2) >> logScale) == 1);
-    cond = 0x00000000U; // All bytes are 0.
-    CHECK(invoke<int>(*code, &cond - 2, (sizeof(uint32_t) * 2) >> logScale) == 0);
-}
-
-void testComplex(unsigned numVars, unsigned numConstructs)
-{
-    MonotonicTime before = MonotonicTime::now();
-    
-    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->appendNewControlValue(
-                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->appendNewControlValue(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->appendNewControlValue(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);
-        &