/* * Copyright (C) 2015-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * 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 "AllowMacroScratchRegisterUsage.h" #include "B3ArgumentRegValue.h" #include "B3BasicBlockInlines.h" #include "B3CCallValue.h" #include "B3Compilation.h" #include "B3ComputeDivisionMagic.h" #include "B3Const32Value.h" #include "B3ConstPtrValue.h" #include "B3ControlValue.h" #include "B3Effects.h" #include "B3MathExtras.h" #include "B3MemoryValue.h" #include "B3Procedure.h" #include "B3SlotBaseValue.h" #include "B3StackSlot.h" #include "B3StackmapGenerationParams.h" #include "B3SwitchValue.h" #include "B3UpsilonValue.h" #include "B3ValueInlines.h" #include "CCallHelpers.h" #include "InitializeThreading.h" #include "JSCInlines.h" #include "LinkBuffer.h" #include "PureNaN.h" #include "VM.h" #include <cmath> #include <string> #include <wtf/Lock.h> #include <wtf/NumberOfCores.h> #include <wtf/Threading.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 { StaticLock 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) VM* vm; std::unique_ptr<Compilation> compile(Procedure& procedure, unsigned optLevel = 1) { return std::make_unique<Compilation>(*vm, procedure, optLevel); } template<typename T, typename... Arguments> T invoke(const Compilation& code, Arguments... arguments) { T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(code.code().executableAddress()); return function(arguments...); } template<typename T, typename... Arguments> T compileAndRun(Procedure& procedure, Arguments... arguments) { return invoke<T>(*compile(procedure), arguments...); } 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() }); 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() } }); 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->appendNew<ControlValue>(proc, Return, Origin(), const42); CHECK(compileAndRun<int>(proc) == 42); } void testLoad42() { Procedure proc; BasicBlock* root = proc.addBlock(); int x = 42; root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &x))); CHECK(compileAndRun<int>(proc) == 42); } void testLoadWithOffsetImpl(int32_t offset64, int32_t offset32) { { Procedure proc; BasicBlock* root = proc.addBlock(); int64_t x = -42; Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, Load, Int64, Origin(), base, offset64)); char* address = reinterpret_cast<char*>(&x) - offset64; CHECK(compileAndRun<int64_t>(proc, address) == -42); } { Procedure proc; BasicBlock* root = proc.addBlock(); int32_t x = -42; Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), base, offset32)); char* address = reinterpret_cast<char*>(&x) - offset32; CHECK(compileAndRun<int32_t>(proc, address) == -42); } } void testLoadOffsetImm9Max() { testLoadWithOffsetImpl(255, 255); } void testLoadOffsetImm9MaxPlusOne() { testLoadWithOffsetImpl(256, 256); } void testLoadOffsetImm9MaxPlusTwo() { testLoadWithOffsetImpl(257, 257); } void testLoadOffsetImm9Min() { testLoadWithOffsetImpl(-256, -256); } void testLoadOffsetImm9MinMinusOne() { testLoadWithOffsetImpl(-257, -257); } void testLoadOffsetScaledUnsignedImm12Max() { testLoadWithOffsetImpl(32760, 16380); } void testLoadOffsetScaledUnsignedOverImm12Max() { testLoadWithOffsetImpl(32760, 32760); testLoadWithOffsetImpl(32761, 16381); testLoadWithOffsetImpl(32768, 16384); } void testArg(int argument) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const64Value>(proc, Origin(), value)); CHECK(compileAndRun<int64_t>(proc) == value); } void testAddArg(int a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, Add, Origin(), value, value)); CHECK(compileAndRun<int>(proc, a) == a + a); } void testAddArgs(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); int64_t inputOutput = b; CHECK(!compileAndRun<int64_t>(proc, a, &inputOutput)); CHECK(inputOutput == a + b); } void testAddMemArg(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address); Value* result = root->appendNew<Value>(proc, Add, Origin(), load, root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int64_t>(proc, &a, b) == a + b); } void testAddImmMem(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address); Value* result = root->appendNew<Value>(proc, Add, Origin(), root->appendNew<Const64Value>(proc, Origin(), a), load); root->appendNew<MemoryValue>(proc, Store, Origin(), result, address); root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); int64_t inputOutput = b; CHECK(!compileAndRun<int>(proc, &inputOutput)); CHECK(inputOutput == a + b); } void testAddArg32(int a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, Add, Origin(), value, value)); CHECK(compileAndRun<int>(proc, a) == a + a); } void testAddArgs32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<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->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); int32_t inputOutput = b; CHECK(!compileAndRun<int32_t>(proc, a, &inputOutput)); CHECK(inputOutput == a + b); } void testAddMemArg32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address); Value* argument = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* result = root->appendNew<Value>(proc, Add, Origin(), load, argument); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int32_t>(proc, &a, b) == a + b); } void testAddImmMem32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address); Value* result = root->appendNew<Value>(proc, Add, Origin(), root->appendNew<Const32Value>(proc, Origin(), a), load); root->appendNew<MemoryValue>(proc, Store, Origin(), result, address); root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); int32_t inputOutput = b; CHECK(!compileAndRun<int>(proc, &inputOutput)); CHECK(inputOutput == a + b); } void 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), arg, constZero)); auto code = compile(proc, 0); CHECK(invoke<int64_t>(*code, 0x0123456789abcdef) == 0x89abcdef); } void testAddLoadTwice() { auto test = [&] (unsigned optLevel) { 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, Add, Origin(), load, load)); auto code = compile(proc, optLevel); CHECK(invoke<int32_t>(*code) == 42 * 2); }; test(0); test(1); } void testAddArgDouble(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a + a))); } void testAddArgsFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* result = root->appendNew<Value>(proc, Add, Origin(), floatValue1, floatValue2); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a + b))); } void testAddArgImmFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32); Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), b); Value* result = root->appendNew<Value>(proc, Add, Origin(), floatValue, constValue); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a + b))); } void testAddImmArgFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32); Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), a); Value* result = root->appendNew<Value>(proc, Add, Origin(), constValue, floatValue); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a + b))); } void testAddImmsFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a); Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b); Value* result = root->appendNew<Value>(proc, Add, Origin(), constValue1, constValue2); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a + b))); } void testAddArgFloatWithUselessDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentInt32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentInt32); Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew<Value>(proc, Add, Origin(), asDouble, asDouble); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a + a))); } void testAddArgsFloatWithUselessDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1); Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2); Value* result = root->appendNew<Value>(proc, Add, Origin(), asDouble1, asDouble2); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a + b))); } void testAddArgsFloatWithEffectfulDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1); Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2); Value* result = root->appendNew<Value>(proc, Add, Origin(), asDouble1, asDouble2); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* doubleAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleAddress); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); double effect = 0; CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), &effect), bitwise_cast<int32_t>(a + b))); CHECK(isIdentical(effect, static_cast<double>(a) + static_cast<double>(b))); } void testMulArg(int a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, 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)); root->appendNew<MemoryValue>( proc, Store, Origin(), mul, root->appendNew<ConstPtrValue>(proc, Origin(), &mulSlot)); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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 testMulArgImm(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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 testMulLoadTwice() { auto test = [&] (unsigned optLevel) { 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, Mul, Origin(), load, load)); auto code = compile(proc, optLevel); CHECK(invoke<int32_t>(*code) == 42 * 42); }; test(0); test(1); } 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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), added); auto code = compile(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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a * a))); } void testMulArgsFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* result = root->appendNew<Value>(proc, Mul, Origin(), floatValue1, floatValue2); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a * b))); } void testMulArgImmFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32); Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), b); Value* result = root->appendNew<Value>(proc, Mul, Origin(), floatValue, constValue); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a * b))); } void testMulImmArgFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32); Value* constValue = root->appendNew<ConstFloatValue>(proc, Origin(), a); Value* result = root->appendNew<Value>(proc, Mul, Origin(), constValue, floatValue); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a * b))); } void testMulImmsFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a); Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b); Value* result = root->appendNew<Value>(proc, Mul, Origin(), constValue1, constValue2); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(a * b))); } void testMulArgFloatWithUselessDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentInt32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentInt32); Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew<Value>(proc, Mul, Origin(), asDouble, asDouble); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a * a))); } void testMulArgsFloatWithUselessDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1); Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2); Value* result = root->appendNew<Value>(proc, Mul, Origin(), asDouble1, asDouble2); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a * b))); } void testMulArgsFloatWithEffectfulDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1); Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2); Value* result = root->appendNew<Value>(proc, Mul, Origin(), asDouble1, asDouble2); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* doubleMulress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleMulress); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); double effect = 0; CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), &effect), bitwise_cast<int32_t>(a * b))); CHECK(isIdentical(effect, static_cast<double>(a) * static_cast<double>(b))); } void testDivArgDouble(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a / b))); } void 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b))))); } void 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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b))))); } void testModImmsFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* constValue1 = root->appendNew<ConstFloatValue>(proc, Origin(), a); Value* constValue2 = root->appendNew<ConstFloatValue>(proc, Origin(), b); Value* result = root->appendNew<Value>(proc, Mod, Origin(), constValue1, constValue2); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc), bitwise_cast<int32_t>(static_cast<float>(fmod(a, b))))); } void testDivArgFloatWithUselessDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentInt32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentInt32); Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew<Value>(proc, Div, Origin(), asDouble, asDouble); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(a / a))); } void testDivArgsFloatWithUselessDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1); Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2); Value* result = root->appendNew<Value>(proc, Div, Origin(), asDouble1, asDouble2); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a / b))); } void testDivArgsFloatWithEffectfulDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1); Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2); Value* result = root->appendNew<Value>(proc, Div, Origin(), asDouble1, asDouble2); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* doubleDivress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleDivress); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); double effect = 0; CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), &effect), bitwise_cast<int32_t>(a / b))); CHECK(isIdentical(effect, static_cast<double>(a) / static_cast<double>(b))); } void testSubArg(int a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, Sub, Origin(), value, value)); CHECK(!compileAndRun<int>(proc, a)); } void testSubArgs(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); CHECK(compileAndRun<int>(proc, a, b) == a - b); } void testSubArgImm(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const64Value>(proc, Origin(), b))); CHECK(compileAndRun<int64_t>(proc, a) == 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->appendNew<ControlValue>(proc, Return, Origin(), negArgumentMinusOne); CHECK(compileAndRun<int>(proc, a) == -a - 1); } void testSubImmArg(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); int64_t inputOutput = b; CHECK(!compileAndRun<int>(proc, &inputOutput)); CHECK(inputOutput == a - b); } void 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->appendNew<ControlValue>(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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun<int>(proc, a, b) == a - b); } void testSubArgImm32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int>(proc, a) == a - b); } void testSubImmArg32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<Const32Value>(proc, Origin(), a), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); int32_t inputOutput = b; CHECK(!compileAndRun<int>(proc, &inputOutput)); CHECK(inputOutput == a - b); } void 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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), negArgumentMinusOne); CHECK(compileAndRun<int>(proc, a) == -a - 1); } void testSubArgDouble(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a - b))); } void 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitwise_cast<int32_t>(a - b))); } void testSubArgsFloatWithEffectfulDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* asDouble1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1); Value* asDouble2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2); Value* result = root->appendNew<Value>(proc, Sub, Origin(), asDouble1, asDouble2); Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result); Value* doubleSubress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleSubress); Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult); root->appendNew<ControlValue>(proc, Return, Origin(), result32); double effect = 0; CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), &effect), bitwise_cast<int32_t>(a - b))); CHECK(isIdentical(effect, static_cast<double>(a) - static_cast<double>(b))); } void testBitAndArgs(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), argument, argument)); CHECK(compileAndRun<int64_t>(proc, a) == a); } void testBitAndImms(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int>(proc, a) == (a & b)); } void testBitAndImmArg32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Const32Value>(proc, Origin(), a), root->appendNew<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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), argument, argument)); CHECK(compileAndRun<int64_t>(proc, a) == a); } void testBitOrImms(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<Const64Value>(proc, Origin(), a), root->appendNew<Const64Value>(proc, Origin(), b))); CHECK(compileAndRun<int64_t>(proc) == (a | b)); } void testBitOrArgImm(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<Const32Value>(proc, Origin(), a), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int>(proc) == (a | b)); } void testBitOrArgImm32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int>(proc, a) == (a | b)); } void testBitOrImmArg32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<Const32Value>(proc, Origin(), a), root->appendNew<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->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<Const32Value>(proc, Origin(), a), innerBitOr)); CHECK(compileAndRun<int>(proc, b) == (a | (b | c))); } void testBitXorArgs(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitXor, Origin(), argument, argument)); CHECK(!compileAndRun<int64_t>(proc, a)); } void testBitXorImms(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); int64_t input = a; compileAndRun<int32_t>(proc, &input); CHECK(isIdentical(input, static_cast<int64_t>((static_cast<uint64_t>(a) ^ 0xffffffffffffffff)))); } void testBitNotArg32(int32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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 testBitNotOnBooleanAndBranch32(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* arg1 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* argsAreEqual = root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2); Value* argsAreNotEqual = root->appendNew<Value>(proc, BitXor, Origin(), root->appendNew<Const32Value>(proc, Origin(), -1), argsAreEqual); root->appendNew<ControlValue>( proc, Branch, Origin(), argsAreNotEqual, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -42)); int32_t expectedValue = (a != b) ? 42 : -42; CHECK(compileAndRun<int32_t>(proc, a, b) == expectedValue); } void testShlArgs(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun<int64_t>(proc, a, b) == (a << b)); } void testShlImms(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<Const64Value>(proc, Origin(), a), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int64_t>(proc) == (a << b)); } void testShlArgImm(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int64_t>(proc, a) == (a << 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun<int32_t>(proc, a, b) == (a << b)); } void testShlImms32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<Const32Value>(proc, Origin(), a), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int32_t>(proc) == (a << b)); } void testShlArgImm32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int32_t>(proc, a) == (a << b)); } void testSShrArgs(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SShr, Origin(), root->appendNew<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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SShr, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun<int32_t>(proc, a, b) == (a >> b)); } void testSShrImms32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SShr, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), b))); CHECK(compileAndRun<int32_t>(proc, a) == (a >> b)); } void testZShrArgs(uint64_t a, uint64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), clzValue); CHECK(compileAndRun<unsigned>(proc, &a) == countLeadingZero(a)); } void testAbsArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Return, Origin(), secondAbs); 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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), resultAsInt64); int64_t expectedResult = bitwise_cast<int64_t>(fabs(a)); CHECK(isIdentical(compileAndRun<int64_t>(proc, bitwise_cast<int64_t>(a)), expectedResult)); } void 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), secondAbs); 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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, fabs(a))); } void testCeilArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Ceil, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0))); 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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, ceilf(a))); } void testFloorArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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, floorf(a))); } void testSqrtArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Sqrt, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0))); CHECK(isIdentical(compileAndRun<double>(proc, a), sqrt(a))); } void testSqrtImm(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, Sqrt, Origin(), argument)); CHECK(isIdentical(compileAndRun<double>(proc), sqrt(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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, Sqrt, Origin(), loadDouble)); CHECK(isIdentical(compileAndRun<double>(proc, &a), sqrt(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(sqrt(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(sqrt(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(static_cast<float>(sqrt(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->appendNew<ControlValue>(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(sqrt(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->appendNew<ControlValue>(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>(sqrt(a))))); CHECK(isIdentical(effect, sqrt(a))); } 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>( proc, Branch, Origin(), condition, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); UpsilonValue* thenValue = thenCase->appendNew<UpsilonValue>(proc, Origin(), arg1AsDouble); thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(tail)); Value* elseConst = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), 0.); UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), elseConst); elseCase->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), equal); auto code = compile(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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(tail)); Value* elseConst = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), M_PI); UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), elseConst); elseCase->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), floatResult); auto code = compile(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 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(tail)); Value* constDouble = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), 42.5); UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), constDouble); elseCase->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), floatResult); auto code = compile(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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(tail)); Value* constDouble = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), 42.5); UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), constDouble); elseCase->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), doubleAdd); auto code = compile(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)), (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->appendNew<ControlValue>( 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->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(tail)); Value* constDouble = elseCase->appendNew<ConstDoubleValue>(proc, Origin(), constValue); UpsilonValue* elseValue = elseCase->appendNew<UpsilonValue>(proc, Origin(), constDouble); elseCase->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), floatResult); auto code = compile(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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun<int64_t>(proc, value), bitwise_cast<int64_t>(value))); } void testDoubleImmToInt64BitwiseCast(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), value); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun<int64_t>(proc), bitwise_cast<int64_t>(value))); } void 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), cast); CHECK(isIdentical(compileAndRun<int64_t>(proc, &value, 0), bitwise_cast<int64_t>(value))); } void testInt64BArgToDoubleBitwiseCast(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>( 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->appendNew<ControlValue>( 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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), srcAsDouble); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), srcAsFloat); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), srcAsDouble); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), srcAsFloat); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), srcAsDouble); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), srcAsFloat); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), srcAsDouble); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), srcAsFloat); auto code = compile(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), floatResult); auto code = compile(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->appendNew<ControlValue>(proc, Return, Origin(), floatResult); auto code = compile(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)); root->appendNew<ControlValue>( 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)); root->appendNew<ControlValue>( 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 (is64Bit()) slot = (static_cast<intptr_t>(0xbaadbeef) << 32) + static_cast<intptr_t>(0xbaadbeef); else slot = 0xbaadbeef; root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), value), root->appendNew<ConstPtrValue>(proc, Origin(), &slot)); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); 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->appendNew<ControlValue>(proc, Return, Origin(), value); int8_t storage = 0; CHECK(compileAndRun<int64_t>(proc, 42, &storage) == 42); CHECK(storage == 42); } { // Indexed addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); Value* displacement = root->appendNew<Const64Value>(proc, Origin(), -1); Value* baseDisplacement = root->appendNew<Value>(proc, Add, Origin(), displacement, base); Value* address = root->appendNew<Value>(proc, Add, Origin(), baseDisplacement, offset); root->appendNew<MemoryValue>(proc, Store8, Origin(), value, address); root->appendNew<ControlValue>(proc, Return, Origin(), value); int8_t storage = 0; CHECK(compileAndRun<int64_t>(proc, 42, &storage, 1) == 42); CHECK(storage == 42); } } void 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->appendNew<ControlValue>(proc, Return, Origin(), value); int8_t storage = 0; CHECK(compileAndRun<int64_t>(proc, &storage) == 42); CHECK(storage == 42); } { // Indexed addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<Const32Value>(proc, Origin(), 42); Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* displacement = root->appendNew<Const64Value>(proc, Origin(), -1); Value* baseDisplacement = root->appendNew<Value>(proc, Add, Origin(), displacement, base); Value* address = root->appendNew<Value>(proc, Add, Origin(), baseDisplacement, offset); root->appendNew<MemoryValue>(proc, Store8, Origin(), value, address); root->appendNew<ControlValue>(proc, Return, Origin(), value); int8_t storage = 0; CHECK(compileAndRun<int64_t>(proc, &storage, 1) == 42); CHECK(storage == 42); } } void 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->appendNew<ControlValue>(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->appendNew<ControlValue>(proc, Return, Origin(), value); int16_t storage = -1; CHECK(compileAndRun<int64_t>(proc, 42, &storage) == 42); CHECK(storage == 42); } { // Indexed addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); Value* displacement = root->appendNew<Const64Value>(proc, Origin(), -1); Value* baseDisplacement = root->appendNew<Value>(proc, Add, Origin(), displacement, base); Value* address = root->appendNew<Value>(proc, Add, Origin(), baseDisplacement, offset); root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address); root->appendNew<ControlValue>(proc, Return, Origin(), value); int16_t storage = -1; CHECK(compileAndRun<int64_t>(proc, 42, &storage, 1) == 42); CHECK(storage == 42); } } void testStore16Imm() { { // Direct addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<Const32Value>(proc, Origin(), 42); Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address); root->appendNew<ControlValue>(proc, Return, Origin(), value); int16_t storage = -1; CHECK(compileAndRun<int64_t>(proc, &storage) == 42); CHECK(storage == 42); } { // Indexed addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew<Const32Value>(proc, Origin(), 42); Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* displacement = root->appendNew<Const64Value>(proc, Origin(), -1); Value* baseDisplacement = root->appendNew<Value>(proc, Add, Origin(), displacement, base); Value* address = root->appendNew<Value>(proc, Add, Origin(), baseDisplacement, offset); root->appendNew<MemoryValue>(proc, Store16, Origin(), value, address); root->appendNew<ControlValue>(proc, Return, Origin(), value); int16_t storage = -1; CHECK(compileAndRun<int64_t>(proc, &storage, 1) == 42); CHECK(storage == 42); } } void testTrunc(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), 1))); CHECK(compileAndRun<int>(proc, value) == value + 1); } void testAdd1Ptr(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, 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->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(compileAndRun<int32_t>(proc, value) == -value); } void testNegPtr(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), 0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); 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); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, 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); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); CHECK(slot == 37 + amount); } void testStoreAddLoad8(int amount, B3::Opcode loadOpcode) { Procedure proc; BasicBlock* root = proc.addBlock(); int8_t slot = 37; ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); root->appendNew<MemoryValue>( proc, Store8, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, 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); root->appendNew<ControlValue>( 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); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, 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); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); CHECK(slot == 37 + amount); } void testStoreAddLoad64(int amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int64_t slot = 37000000000ll; ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, amount)); CHECK(slot == 37000000000ll + amount); } void testStoreAddLoadImm64(int64_t amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int64_t slot = 370000000000ll; ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr), root->appendNew<Const64Value>(proc, Origin(), amount)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); CHECK(slot == 370000000000ll + amount); } void testStoreAddLoad32Index(int amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int slot = 37; int* ptr = &slot; intptr_t zero = 0; Value* slotPtr = root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &zero))); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, amount)); CHECK(slot == 37 + amount); } void testStoreAddLoadImm32Index(int amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int slot = 37; int* ptr = &slot; intptr_t zero = 0; Value* slotPtr = root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &zero))); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr), root->appendNew<Const32Value>(proc, Origin(), amount)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); CHECK(slot == 37 + amount); } void testStoreAddLoad8Index(int amount, B3::Opcode loadOpcode) { Procedure proc; BasicBlock* root = proc.addBlock(); int8_t slot = 37; int8_t* ptr = &slot; intptr_t zero = 0; Value* slotPtr = root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &zero))); root->appendNew<MemoryValue>( proc, Store8, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, amount)); CHECK(slot == 37 + amount); } void testStoreAddLoadImm8Index(int amount, B3::Opcode loadOpcode) { Procedure proc; BasicBlock* root = proc.addBlock(); int8_t slot = 37; int8_t* ptr = &slot; intptr_t zero = 0; Value* slotPtr = root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &zero))); root->appendNew<MemoryValue>( proc, Store8, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr), root->appendNew<Const32Value>(proc, Origin(), amount)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); CHECK(slot == 37 + amount); } void testStoreAddLoad16Index(int amount, B3::Opcode loadOpcode) { Procedure proc; BasicBlock* root = proc.addBlock(); int16_t slot = 37; int16_t* ptr = &slot; intptr_t zero = 0; Value* slotPtr = root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &zero))); root->appendNew<MemoryValue>( proc, Store16, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, amount)); CHECK(slot == 37 + amount); } void testStoreAddLoadImm16Index(int amount, B3::Opcode loadOpcode) { Procedure proc; BasicBlock* root = proc.addBlock(); int16_t slot = 37; int16_t* ptr = &slot; intptr_t zero = 0; Value* slotPtr = root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &zero))); root->appendNew<MemoryValue>( proc, Store16, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr), root->appendNew<Const32Value>(proc, Origin(), amount)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); CHECK(slot == 37 + amount); } void testStoreAddLoad64Index(int amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int64_t slot = 37000000000ll; int64_t* ptr = &slot; intptr_t zero = 0; Value* slotPtr = root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &zero))); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, amount)); CHECK(slot == 37000000000ll + amount); } void testStoreAddLoadImm64Index(int64_t amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int64_t slot = 370000000000ll; int64_t* ptr = &slot; intptr_t zero = 0; Value* slotPtr = root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &ptr)), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &zero))); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr), root->appendNew<Const64Value>(proc, Origin(), amount)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); CHECK(slot == 370000000000ll + amount); } void testStoreSubLoad(int amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int32_t startValue = std::numeric_limits<int32_t>::min(); int32_t slot = startValue; ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, amount)); CHECK(slot == startValue - amount); } void testStoreAddLoadInterference(int amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int slot = 37; ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); ArgumentRegValue* otherSlotPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Const32Value>(proc, Origin(), 666), otherSlotPtr); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Add, Origin(), load, root->appendNew<Const32Value>(proc, Origin(), amount)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc, &slot)); CHECK(slot == 37 + amount); } void testStoreAddAndLoad(int amount, int mask) { Procedure proc; BasicBlock* root = proc.addBlock(); int slot = 37; ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr), root->appendNew<Const32Value>(proc, Origin(), amount)), root->appendNew<Const32Value>(proc, Origin(), mask)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); CHECK(slot == ((37 + amount) & mask)); } void testStoreNegLoad32(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); int32_t slot = value; ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int32_t>(proc)); CHECK(slot == -value); } void testStoreNegLoadPtr(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); intptr_t slot = value; ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Sub, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), 0), root->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), slotPtr)), slotPtr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int32_t>(proc)); CHECK(slot == -value); } void testAdd1Uncommuted(int value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Const32Value>(proc, Origin(), 1), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(compileAndRun<int>(proc, value) == value + 1); } void testLoadOffset() { Procedure proc; BasicBlock* root = proc.addBlock(); int array[] = { 1, 2 }; ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int)))); CHECK(compileAndRun<int>(proc) == array[0] + array[1]); } void testLoadOffsetNotConstant() { Procedure proc; BasicBlock* root = proc.addBlock(); int array[] = { 1, 2 }; Value* arrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int)))); CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]); } void testLoadOffsetUsingAdd() { Procedure proc; BasicBlock* root = proc.addBlock(); int array[] = { 1, 2 }; ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<Value>( proc, Add, Origin(), arrayPtr, root->appendNew<ConstPtrValue>(proc, Origin(), 0))), root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<Value>( proc, Add, Origin(), arrayPtr, root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int)))))); CHECK(compileAndRun<int>(proc) == array[0] + array[1]); } void testLoadOffsetUsingAddInterference() { Procedure proc; BasicBlock* root = proc.addBlock(); int array[] = { 1, 2 }; ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array); ArgumentRegValue* otherArrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Const32Value* theNumberOfTheBeast = root->appendNew<Const32Value>(proc, Origin(), 666); MemoryValue* left = root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<Value>( proc, Add, Origin(), arrayPtr, root->appendNew<ConstPtrValue>(proc, Origin(), 0))); MemoryValue* right = root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<Value>( proc, Add, Origin(), arrayPtr, root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int)))); root->appendNew<MemoryValue>( proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, 0); root->appendNew<MemoryValue>( proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, sizeof(int)); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), left, right)); CHECK(compileAndRun<int>(proc, &array[0]) == 1 + 2); CHECK(array[0] == 666); CHECK(array[1] == 666); } void testLoadOffsetUsingAddNotConstant() { Procedure proc; BasicBlock* root = proc.addBlock(); int array[] = { 1, 2 }; Value* arrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<Value>( proc, Add, Origin(), arrayPtr, root->appendNew<ConstPtrValue>(proc, Origin(), 0))), root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<Value>( proc, Add, Origin(), arrayPtr, root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int)))))); CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]); } void testLoadAddrShift(unsigned shift) { Procedure proc; BasicBlock* root = proc.addBlock(); int slots[2]; // Figure out which slot to use while having proper alignment for the shift. int* slot; uintptr_t arg; for (unsigned i = sizeof(slots)/sizeof(slots[0]); i--;) { slot = slots + i; arg = bitwise_cast<uintptr_t>(slot) >> shift; if (bitwise_cast<int*>(arg << shift) == slot) break; } *slot = 8675309; root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const32Value>(proc, Origin(), shift)))); CHECK(compileAndRun<int>(proc, arg) == 8675309); } void testFramePointer() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, FramePointer, Origin())); void* fp = compileAndRun<void*>(proc); CHECK(fp < &proc); CHECK(fp >= bitwise_cast<char*>(&proc) - 10000); } void testOverrideFramePointer() { { Procedure proc; BasicBlock* root = proc.addBlock(); // Add a stack slot to make the frame non trivial. root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(8)); // Sub on x86 UseDef the source. If FP is not protected correctly, it will be overridden since it is the last visible use. Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* fp = root->appendNew<Value>(proc, FramePointer, Origin()); Value* result = root->appendNew<Value>(proc, Sub, Origin(), fp, offset); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int64_t>(proc, 1)); } { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(8)); Value* offset = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* fp = root->appendNew<Value>(proc, FramePointer, Origin()); Value* offsetFP = root->appendNew<Value>(proc, BitAnd, Origin(), offset, fp); Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* offsetArg = root->appendNew<Value>(proc, Add, Origin(), offset, arg); Value* result = root->appendNew<Value>(proc, Add, Origin(), offsetArg, offsetFP); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int64_t>(proc, 1, 2)); } } void testStackSlot() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(1))); void* stackSlot = compileAndRun<void*>(proc); CHECK(stackSlot < &proc); CHECK(stackSlot >= bitwise_cast<char*>(&proc) - 10000); } void testLoadFromFramePointer() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<Value>(proc, FramePointer, Origin()))); void* fp = compileAndRun<void*>(proc); void* myFP = __builtin_frame_address(0); CHECK(fp <= myFP); CHECK(fp >= bitwise_cast<char*>(myFP) - 10000); } void testStoreLoadStackSlot(int value) { Procedure proc; BasicBlock* root = proc.addBlock(); SlotBaseValue* stack = root->appendNew<SlotBaseValue>(proc, Origin(), proc.addStackSlot(sizeof(int))); root->appendNew<MemoryValue>( proc, Store, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), stack); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), stack)); CHECK(compileAndRun<int>(proc, value) == value); } template<typename LoadedType, typename EffectiveType> EffectiveType modelLoad(EffectiveType value) { union { EffectiveType original; LoadedType loaded; } u; u.original = value; if (std::is_signed<LoadedType>::value) return static_cast<EffectiveType>(u.loaded); return static_cast<EffectiveType>(static_cast<typename std::make_unsigned<EffectiveType>::type>(u.loaded)); } template<> float modelLoad<float, float>(float value) { return value; } template<> double modelLoad<double, double>(double value) { return value; } template<B3::Type type, typename CType, typename InputType> void testLoad(B3::Opcode opcode, InputType value) { // Simple load from an absolute address. { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, opcode, type, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &value))); CHECK(isIdentical(compileAndRun<CType>(proc), modelLoad<CType>(value))); } // Simple load from an address in a register. { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, opcode, type, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); CHECK(isIdentical(compileAndRun<CType>(proc, &value), modelLoad<CType>(value))); } // Simple load from an address in a register, at an offset. { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, opcode, type, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), sizeof(InputType))); CHECK(isIdentical(compileAndRun<CType>(proc, &value - 1), modelLoad<CType>(value))); } // Load from a simple base-index with various scales. for (unsigned logScale = 0; logScale <= 3; ++logScale) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, opcode, type, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), root->appendNew<Const32Value>(proc, Origin(), logScale))))); CHECK(isIdentical(compileAndRun<CType>(proc, &value - 2, (sizeof(InputType) * 2) >> logScale), modelLoad<CType>(value))); } // Load from a simple base-index with various scales, but commuted. for (unsigned logScale = 0; logScale <= 3; ++logScale) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>( proc, opcode, type, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), root->appendNew<Const32Value>(proc, Origin(), logScale)), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(isIdentical(compileAndRun<CType>(proc, &value - 2, (sizeof(InputType) * 2) >> logScale), modelLoad<CType>(value))); } } template<typename T> void testLoad(B3::Opcode opcode, int32_t value) { return testLoad<Int32, T>(opcode, value); } template<B3::Type type, typename T> void testLoad(T value) { return testLoad<type, T>(Load, value); } void testStoreFloat(double input) { // Simple store from an address in a register. { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* argumentAsFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument); Value* destinationAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<MemoryValue>(proc, Store, Origin(), argumentAsFloat, destinationAddress); root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); float output = 0.; CHECK(!compileAndRun<int64_t>(proc, input, &output)); CHECK(isIdentical(static_cast<float>(input), output)); } // Simple indexed store. { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* argumentAsFloat = root->appendNew<Value>(proc, DoubleToFloat, Origin(), argument); Value* destinationBaseAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* index = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* scaledIndex = root->appendNew<Value>( proc, Shl, Origin(), index, root->appendNew<Const32Value>(proc, Origin(), 2)); Value* destinationAddress = root->appendNew<Value>(proc, Add, Origin(), scaledIndex, destinationBaseAddress); root->appendNew<MemoryValue>(proc, Store, Origin(), argumentAsFloat, destinationAddress); root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); float output = 0.; CHECK(!compileAndRun<int64_t>(proc, input, &output - 1, 1)); CHECK(isIdentical(static_cast<float>(input), output)); } } void 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->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); float output = 0.; CHECK(!compileAndRun<int64_t>(proc, input, &output)); CHECK(isIdentical(static_cast<float>(input), output)); } void testSpillGP() { Procedure proc; BasicBlock* root = proc.addBlock(); Vector<Value*> sources; sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); for (unsigned i = 0; i < 30; ++i) { sources.append( root->appendNew<Value>(proc, Add, Origin(), sources[sources.size() - 1], sources[sources.size() - 2]) ); } Value* total = root->appendNew<Const64Value>(proc, Origin(), 0); for (Value* value : sources) total = root->appendNew<Value>(proc, Add, Origin(), total, value); root->appendNew<ControlValue>(proc, Return, Origin(), total); compileAndRun<int>(proc, 1, 2); } void testSpillFP() { Procedure proc; BasicBlock* root = proc.addBlock(); Vector<Value*> sources; sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)); sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)); for (unsigned i = 0; i < 30; ++i) { sources.append( root->appendNew<Value>(proc, Add, Origin(), sources[sources.size() - 1], sources[sources.size() - 2]) ); } Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.); for (Value* value : sources) total = root->appendNew<Value>(proc, Add, Origin(), total, value); root->appendNew<ControlValue>(proc, Return, Origin(), total); compileAndRun<double>(proc, 1.1, 2.5); } void testInt32ToDoublePartialRegisterStall() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* loop = proc.addBlock(); BasicBlock* done = proc.addBlock(); // Head. Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.); Value* counter = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); UpsilonValue* originalTotal = root->appendNew<UpsilonValue>(proc, Origin(), total); UpsilonValue* originalCounter = root->appendNew<UpsilonValue>(proc, Origin(), counter); root->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop)); // Loop. Value* loopCounter = loop->appendNew<Value>(proc, Phi, Int64, Origin()); Value* loopTotal = loop->appendNew<Value>(proc, Phi, Double, Origin()); originalCounter->setPhi(loopCounter); originalTotal->setPhi(loopTotal); Value* truncatedCounter = loop->appendNew<Value>(proc, Trunc, Origin(), loopCounter); Value* doubleCounter = loop->appendNew<Value>(proc, IToD, Origin(), truncatedCounter); Value* updatedTotal = loop->appendNew<Value>(proc, Add, Origin(), doubleCounter, loopTotal); UpsilonValue* updatedTotalUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), updatedTotal); updatedTotalUpsilon->setPhi(loopTotal); Value* decCounter = loop->appendNew<Value>(proc, Sub, Origin(), loopCounter, loop->appendNew<Const64Value>(proc, Origin(), 1)); UpsilonValue* decCounterUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), decCounter); decCounterUpsilon->setPhi(loopCounter); loop->appendNew<ControlValue>( proc, Branch, Origin(), decCounter, FrequentedBlock(loop), FrequentedBlock(done)); // Tail. done->appendNew<ControlValue>(proc, Return, Origin(), updatedTotal); CHECK(isIdentical(compileAndRun<double>(proc, 100000), 5000050000.)); } void testInt32ToDoublePartialRegisterWithoutStall() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* loop = proc.addBlock(); BasicBlock* done = proc.addBlock(); // Head. Value* total = root->appendNew<ConstDoubleValue>(proc, Origin(), 0.); Value* counter = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); UpsilonValue* originalTotal = root->appendNew<UpsilonValue>(proc, Origin(), total); UpsilonValue* originalCounter = root->appendNew<UpsilonValue>(proc, Origin(), counter); uint64_t forPaddingInput; Value* forPaddingInputAddress = root->appendNew<ConstPtrValue>(proc, Origin(), &forPaddingInput); uint64_t forPaddingOutput; Value* forPaddingOutputAddress = root->appendNew<ConstPtrValue>(proc, Origin(), &forPaddingOutput); root->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop)); // Loop. Value* loopCounter = loop->appendNew<Value>(proc, Phi, Int64, Origin()); Value* loopTotal = loop->appendNew<Value>(proc, Phi, Double, Origin()); originalCounter->setPhi(loopCounter); originalTotal->setPhi(loopTotal); Value* truncatedCounter = loop->appendNew<Value>(proc, Trunc, Origin(), loopCounter); Value* doubleCounter = loop->appendNew<Value>(proc, IToD, Origin(), truncatedCounter); Value* updatedTotal = loop->appendNew<Value>(proc, Add, Origin(), doubleCounter, loopTotal); // Add enough padding instructions to avoid a stall. Value* loadPadding = loop->appendNew<MemoryValue>(proc, Load, Int64, Origin(), forPaddingInputAddress); Value* padding = loop->appendNew<Value>(proc, BitXor, Origin(), loadPadding, loopCounter); padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, BitXor, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, BitXor, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, Add, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, BitOr, Origin(), padding, loopCounter); padding = loop->appendNew<Value>(proc, Sub, Origin(), padding, loopCounter); loop->appendNew<MemoryValue>(proc, Store, Origin(), padding, forPaddingOutputAddress); UpsilonValue* updatedTotalUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), updatedTotal); updatedTotalUpsilon->setPhi(loopTotal); Value* decCounter = loop->appendNew<Value>(proc, Sub, Origin(), loopCounter, loop->appendNew<Const64Value>(proc, Origin(), 1)); UpsilonValue* decCounterUpsilon = loop->appendNew<UpsilonValue>(proc, Origin(), decCounter); decCounterUpsilon->setPhi(loopCounter); loop->appendNew<ControlValue>( proc, Branch, Origin(), decCounter, FrequentedBlock(loop), FrequentedBlock(done)); // Tail. done->appendNew<ControlValue>(proc, Return, Origin(), updatedTotal); CHECK(isIdentical(compileAndRun<double>(proc, 100000), 5000050000.)); } void testBranch() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchPtr() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code, static_cast<intptr_t>(42)) == 1); CHECK(invoke<int>(*code, static_cast<intptr_t>(0)) == 0); } void testDiamond() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); BasicBlock* done = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>( proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done)); UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>( proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done)); Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin()); thenResult->setPhi(phi); elseResult->setPhi(phi); done->appendNew<ControlValue>(proc, Return, Origin(), phi); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchNotEqual() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, NotEqual, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), 0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchNotEqualCommute() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, NotEqual, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchNotEqualNotEqual() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, NotEqual, Origin(), root->appendNew<Value>( proc, NotEqual, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), 0)), root->appendNew<Const32Value>(proc, Origin(), 0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchEqual() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), 0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 0)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 1)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchEqualEqual() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), 0)), root->appendNew<Const32Value>(proc, Origin(), 0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchEqualCommute() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 0)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 1)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchEqualEqual1() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), 0)), root->appendNew<Const32Value>(proc, Origin(), 1)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 0)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 1)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 1); CHECK(invoke<int>(*code, 0) == 0); } void testBranchEqualOrUnorderedArgs(double a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argumentA, argumentB), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc, a, b) == expected); } void testBranchEqualOrUnorderedArgs(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argumentA = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argumentB = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argumentA, argumentB), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc, &a, &b) == expected); } void testBranchNotEqualAndOrderedArgs(double a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* equalOrUnordered = root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argumentA, argumentB); Value* notEqualAndOrdered = root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0), equalOrUnordered); root->appendNew<ControlValue>( proc, Branch, Origin(), notEqualAndOrdered, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (!std::isunordered(a, b) && a != b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc, a, b) == expected); } void testBranchNotEqualAndOrderedArgs(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argumentA = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argumentB = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* equalOrUnordered = root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argumentA, argumentB); Value* notEqualAndOrdered = root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0), equalOrUnordered); root->appendNew<ControlValue>( proc, Branch, Origin(), notEqualAndOrdered, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (!std::isunordered(a, b) && a != b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc, &a, &b) == expected); } void testBranchEqualOrUnorderedDoubleArgImm(double a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argumentA, argumentB), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc, a) == expected); } void testBranchEqualOrUnorderedFloatArgImm(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argumentA = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argumentB = root->appendNew<ConstFloatValue>(proc, Origin(), b); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argumentA, argumentB), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc, &a) == expected); } void testBranchEqualOrUnorderedDoubleImms(double a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argumentA = root->appendNew<ConstDoubleValue>(proc, Origin(), a); Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argumentA, argumentB), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc) == expected); } void testBranchEqualOrUnorderedFloatImms(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argumentA = root->appendNew<ConstFloatValue>(proc, Origin(), a); Value* argumentB = root->appendNew<ConstFloatValue>(proc, Origin(), b); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argumentA, argumentB), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc) == expected); } void testBranchEqualOrUnorderedFloatWithUselessDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* argument1 = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2 = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* argument1AsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argument1); Value* argument2AsDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argument2); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, EqualOrUnordered, Origin(), argument1AsDouble, argument2AsDouble), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 42)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), -13)); int64_t expected = (std::isunordered(a, b) || a == b) ? 42 : -13; CHECK(compileAndRun<int64_t>(proc, &a, &b) == expected); } void testBranchFold(int value) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Const32Value>(proc, Origin(), value), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(compileAndRun<int>(proc) == !!value); } void testDiamondFold(int value) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); BasicBlock* done = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Const32Value>(proc, Origin(), value), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>( proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done)); UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>( proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done)); Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin()); thenResult->setPhi(phi); elseResult->setPhi(phi); done->appendNew<ControlValue>(proc, Return, Origin(), phi); CHECK(compileAndRun<int>(proc) == !!value); } void testBranchNotEqualFoldPtr(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, NotEqual, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), value), root->appendNew<ConstPtrValue>(proc, Origin(), 0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(compileAndRun<int>(proc) == !!value); } void testBranchEqualFoldPtr(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), value), root->appendNew<ConstPtrValue>(proc, Origin(), 0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(compileAndRun<int>(proc) == !value); } void testBranchLoadPtr() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); intptr_t cond; cond = 42; CHECK(invoke<int>(*code, &cond) == 1); cond = 0; CHECK(invoke<int>(*code, &cond) == 0); } void testBranchLoad32() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); int32_t cond; cond = 42; CHECK(invoke<int>(*code, &cond) == 1); cond = 0; CHECK(invoke<int>(*code, &cond) == 0); } void testBranchLoad8S() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<MemoryValue>( proc, Load8S, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); int8_t cond; cond = -1; CHECK(invoke<int>(*code, &cond) == 1); cond = 0; CHECK(invoke<int>(*code, &cond) == 0); } void testBranchLoad8Z() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<MemoryValue>( proc, Load8Z, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); uint8_t cond; cond = 1; CHECK(invoke<int>(*code, &cond) == 1); cond = 0; CHECK(invoke<int>(*code, &cond) == 0); } void testBranchLoad16S() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<MemoryValue>( proc, Load16S, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); int16_t cond; cond = -1; CHECK(invoke<int>(*code, &cond) == 1); cond = 0; CHECK(invoke<int>(*code, &cond) == 0); } void testBranchLoad16Z() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<MemoryValue>( proc, Load16Z, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); uint16_t cond; cond = 1; CHECK(invoke<int>(*code, &cond) == 1); cond = 0; CHECK(invoke<int>(*code, &cond) == 0); } void testComplex(unsigned numVars, unsigned numConstructs) { double before = monotonicallyIncreasingTimeMS(); Procedure proc; BasicBlock* current = proc.addBlock(); Const32Value* one = current->appendNew<Const32Value>(proc, Origin(), 1); Vector<int32_t> varSlots; for (unsigned i = numVars; i--;) varSlots.append(i); Vector<Value*> vars; for (int32_t& varSlot : varSlots) { Value* varSlotPtr = current->appendNew<ConstPtrValue>(proc, Origin(), &varSlot); vars.append(current->appendNew<MemoryValue>(proc, Load, Int32, Origin(), varSlotPtr)); } for (unsigned i = 0; i < numConstructs; ++i) { if (i & 1) { // Control flow diamond. unsigned predicateVarIndex = ((i >> 1) + 2) % numVars; unsigned thenIncVarIndex = ((i >> 1) + 0) % numVars; unsigned elseIncVarIndex = ((i >> 1) + 1) % numVars; BasicBlock* thenBlock = proc.addBlock(); BasicBlock* elseBlock = proc.addBlock(); BasicBlock* continuation = proc.addBlock(); current->appendNew<ControlValue>( proc, Branch, Origin(), vars[predicateVarIndex], FrequentedBlock(thenBlock), FrequentedBlock(elseBlock)); UpsilonValue* thenThenResult = thenBlock->appendNew<UpsilonValue>( proc, Origin(), thenBlock->appendNew<Value>(proc, Add, Origin(), vars[thenIncVarIndex], one)); UpsilonValue* thenElseResult = thenBlock->appendNew<UpsilonValue>( proc, Origin(), vars[elseIncVarIndex]); thenBlock->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation)); UpsilonValue* elseElseResult = elseBlock->appendNew<UpsilonValue>( proc, Origin(), elseBlock->appendNew<Value>(proc, Add, Origin(), vars[elseIncVarIndex], one)); UpsilonValue* elseThenResult = elseBlock->appendNew<UpsilonValue>( proc, Origin(), vars[thenIncVarIndex]); elseBlock->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation)); Value* thenPhi = continuation->appendNew<Value>(proc, Phi, Int32, Origin()); thenThenResult->setPhi(thenPhi); elseThenResult->setPhi(thenPhi); vars[thenIncVarIndex] = thenPhi; Value* elsePhi = continuation->appendNew<Value>(proc, Phi, Int32, Origin()); thenElseResult->setPhi(elsePhi); elseElseResult->setPhi(elsePhi); vars[elseIncVarIndex] = thenPhi; current = continuation; } else { // Loop. BasicBlock* loopEntry = proc.addBlock(); BasicBlock* loopReentry = proc.addBlock(); BasicBlock* loopBody = proc.addBlock(); BasicBlock* loopExit = proc.addBlock(); BasicBlock* loopSkip = proc.addBlock(); BasicBlock* continuation = proc.addBlock(); Value* startIndex = vars[((i >> 1) + 1) % numVars]; Value* startSum = current->appendNew<Const32Value>(proc, Origin(), 0); current->appendNew<ControlValue>( proc, Branch, Origin(), startIndex, FrequentedBlock(loopEntry), FrequentedBlock(loopSkip)); UpsilonValue* startIndexForBody = loopEntry->appendNew<UpsilonValue>( proc, Origin(), startIndex); UpsilonValue* startSumForBody = loopEntry->appendNew<UpsilonValue>( proc, Origin(), startSum); loopEntry->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loopBody)); Value* bodyIndex = loopBody->appendNew<Value>(proc, Phi, Int32, Origin()); startIndexForBody->setPhi(bodyIndex); Value* bodySum = loopBody->appendNew<Value>(proc, Phi, Int32, Origin()); startSumForBody->setPhi(bodySum); Value* newBodyIndex = loopBody->appendNew<Value>(proc, Sub, Origin(), bodyIndex, one); Value* newBodySum = loopBody->appendNew<Value>( proc, Add, Origin(), bodySum, loopBody->appendNew<MemoryValue>( proc, Load, Int32, Origin(), loopBody->appendNew<Value>( proc, Add, Origin(), loopBody->appendNew<ConstPtrValue>(proc, Origin(), varSlots.data()), loopBody->appendNew<Value>( proc, Shl, Origin(), loopBody->appendNew<Value>( proc, ZExt32, Origin(), loopBody->appendNew<Value>( proc, BitAnd, Origin(), newBodyIndex, loopBody->appendNew<Const32Value>( proc, Origin(), numVars - 1))), loopBody->appendNew<Const32Value>(proc, Origin(), 2))))); loopBody->appendNew<ControlValue>( proc, Branch, Origin(), newBodyIndex, FrequentedBlock(loopReentry), FrequentedBlock(loopExit)); loopReentry->appendNew<UpsilonValue>(proc, Origin(), newBodyIndex, bodyIndex); loopReentry->appendNew<UpsilonValue>(proc, Origin(), newBodySum, bodySum); loopReentry->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loopBody)); UpsilonValue* exitSum = loopExit->appendNew<UpsilonValue>(proc, Origin(), newBodySum); loopExit->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation)); UpsilonValue* skipSum = loopSkip->appendNew<UpsilonValue>(proc, Origin(), startSum); loopSkip->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation)); Value* finalSum = continuation->appendNew<Value>(proc, Phi, Int32, Origin()); exitSum->setPhi(finalSum); skipSum->setPhi(finalSum); current = continuation; vars[((i >> 1) + 0) % numVars] = finalSum; } } current->appendNew<ControlValue>(proc, Return, Origin(), vars[0]); compile(proc); double after = monotonicallyIncreasingTimeMS(); dataLog(toCString(" That took ", after - before, " ms.\n")); } void testSimplePatchpoint() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); CHECK(params[2].isGPR()); add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr()); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testSimplePatchpointWithoutOuputClobbersGPArgs() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 42); Value* const2 = root->appendNew<Const64Value>(proc, Origin(), 13); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin()); patchpoint->clobberLate(RegisterSet(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1)); patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), params[0].gpr()); jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), params[1].gpr()); jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), GPRInfo::argumentGPR0); jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), GPRInfo::argumentGPR1); }); Value* result = root->appendNew<Value>(proc, Add, Origin(), arg1, arg2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testSimplePatchpointWithOuputClobbersGPArgs() { // We can't predict where the output will be but we want to be sure it is not // one of the clobbered registers which is a bit hard to test. // // What we do is force the hand of our register allocator by clobbering absolutely // everything but 1. The only valid allocation is to give it to the result and // spill everything else. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 42); Value* const2 = root->appendNew<Const64Value>(proc, Origin(), 13); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int64, Origin()); RegisterSet clobberAll = RegisterSet::allGPRs(); clobberAll.exclude(RegisterSet::stackRegisters()); clobberAll.exclude(RegisterSet::reservedHardwareRegisters()); clobberAll.clear(GPRInfo::argumentGPR2); patchpoint->clobberLate(clobberAll); patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); CHECK(params[2].isGPR()); jit.move(params[1].gpr(), params[0].gpr()); jit.add64(params[2].gpr(), params[0].gpr()); clobberAll.forEach([&] (Reg reg) { jit.move(CCallHelpers::TrustedImm32(0x00ff00ff), reg.gpr()); }); }); Value* result = root->appendNew<Value>(proc, Add, Origin(), patchpoint, root->appendNew<Value>(proc, Add, Origin(), arg1, arg2)); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int>(proc, 1, 2) == 58); } void testSimplePatchpointWithoutOuputClobbersFPArgs() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* const1 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5); Value* const2 = root->appendNew<ConstDoubleValue>(proc, Origin(), 13.1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin()); patchpoint->clobberLate(RegisterSet(FPRInfo::argumentFPR0, FPRInfo::argumentFPR1)); patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isFPR()); CHECK(params[1].isFPR()); jit.moveZeroToDouble(params[0].fpr()); jit.moveZeroToDouble(params[1].fpr()); jit.moveZeroToDouble(FPRInfo::argumentFPR0); jit.moveZeroToDouble(FPRInfo::argumentFPR1); }); Value* result = root->appendNew<Value>(proc, Add, Origin(), arg1, arg2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<double>(proc, 1.5, 2.5) == 4); } void testSimplePatchpointWithOuputClobbersFPArgs() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* const1 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5); Value* const2 = root->appendNew<ConstDoubleValue>(proc, Origin(), 13.1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Double, Origin()); RegisterSet clobberAll = RegisterSet::allFPRs(); clobberAll.exclude(RegisterSet::stackRegisters()); clobberAll.exclude(RegisterSet::reservedHardwareRegisters()); clobberAll.clear(FPRInfo::argumentFPR2); patchpoint->clobberLate(clobberAll); patchpoint->append(ConstrainedValue(const1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(const2, ValueRep::SomeRegister)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0].isFPR()); CHECK(params[1].isFPR()); CHECK(params[2].isFPR()); jit.addDouble(params[1].fpr(), params[2].fpr(), params[0].fpr()); clobberAll.forEach([&] (Reg reg) { jit.moveZeroToDouble(reg.fpr()); }); }); Value* result = root->appendNew<Value>(proc, Add, Origin(), patchpoint, root->appendNew<Value>(proc, Add, Origin(), arg1, arg2)); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<double>(proc, 1.5, 2.5) == 59.6); } void testPatchpointWithEarlyClobber() { auto test = [] (GPRReg registerToClobber, bool arg1InArgGPR, bool arg2InArgGPR) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); patchpoint->clobberEarly(RegisterSet(registerToClobber)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { CHECK((params[1].gpr() == GPRInfo::argumentGPR0) == arg1InArgGPR); CHECK((params[2].gpr() == GPRInfo::argumentGPR1) == arg2InArgGPR); add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr()); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); }; test(GPRInfo::nonArgGPR0, true, true); test(GPRInfo::argumentGPR0, false, true); test(GPRInfo::argumentGPR1, true, false); } void testPatchpointCallArg() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(ConstrainedValue(arg1, ValueRep::stackArgument(0))); patchpoint->append(ConstrainedValue(arg2, ValueRep::stackArgument(8))); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0].isGPR()); CHECK(params[1].isStack()); CHECK(params[2].isStack()); jit.load32( CCallHelpers::Address(GPRInfo::callFrameRegister, params[1].offsetFromFP()), params[0].gpr()); jit.add32( CCallHelpers::Address(GPRInfo::callFrameRegister, params[2].offsetFromFP()), params[0].gpr()); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testPatchpointFixedRegister() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(ConstrainedValue(arg1, ValueRep(GPRInfo::regT0))); patchpoint->append(ConstrainedValue(arg2, ValueRep(GPRInfo::regT1))); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0].isGPR()); CHECK(params[1] == ValueRep(GPRInfo::regT0)); CHECK(params[2] == ValueRep(GPRInfo::regT1)); add32(jit, GPRInfo::regT0, GPRInfo::regT1, params[0].gpr()); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testPatchpointAny(ValueRep rep) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(ConstrainedValue(arg1, rep)); patchpoint->append(ConstrainedValue(arg2, rep)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); // We shouldn't have spilled the inputs, so we assert that they're in registers. CHECK(params.size() == 3); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); CHECK(params[2].isGPR()); add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr()); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testPatchpointGPScratch() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(arg1, ValueRep::SomeRegister); patchpoint->append(arg2, ValueRep::SomeRegister); patchpoint->numGPScratchRegisters = 2; patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); // We shouldn't have spilled the inputs, so we assert that they're in registers. CHECK(params.size() == 3); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); CHECK(params[2].isGPR()); CHECK(params.gpScratch(0) != InvalidGPRReg); CHECK(params.gpScratch(0) != params[0].gpr()); CHECK(params.gpScratch(0) != params[1].gpr()); CHECK(params.gpScratch(0) != params[2].gpr()); CHECK(params.gpScratch(1) != InvalidGPRReg); CHECK(params.gpScratch(1) != params.gpScratch(0)); CHECK(params.gpScratch(1) != params[0].gpr()); CHECK(params.gpScratch(1) != params[1].gpr()); CHECK(params.gpScratch(1) != params[2].gpr()); CHECK(!params.unavailableRegisters().get(params.gpScratch(0))); CHECK(!params.unavailableRegisters().get(params.gpScratch(1))); add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr()); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testPatchpointFPScratch() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(arg1, ValueRep::SomeRegister); patchpoint->append(arg2, ValueRep::SomeRegister); patchpoint->numFPScratchRegisters = 2; patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); // We shouldn't have spilled the inputs, so we assert that they're in registers. CHECK(params.size() == 3); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); CHECK(params[2].isGPR()); CHECK(params.fpScratch(0) != InvalidFPRReg); CHECK(params.fpScratch(1) != InvalidFPRReg); CHECK(params.fpScratch(1) != params.fpScratch(0)); CHECK(!params.unavailableRegisters().get(params.fpScratch(0))); CHECK(!params.unavailableRegisters().get(params.fpScratch(1))); add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr()); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testPatchpointLotsOfLateAnys() { Procedure proc; BasicBlock* root = proc.addBlock(); Vector<int> things; for (unsigned i = 200; i--;) things.append(i); Vector<Value*> values; for (int& thing : things) { Value* value = root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &thing)); values.append(value); } PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->clobber(RegisterSet::macroScratchRegisters()); for (Value* value : values) patchpoint->append(ConstrainedValue(value, ValueRep::LateColdAny)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); // We shouldn't have spilled the inputs, so we assert that they're in registers. CHECK(params.size() == things.size() + 1); CHECK(params[0].isGPR()); jit.move(CCallHelpers::TrustedImm32(0), params[0].gpr()); for (unsigned i = 1; i < params.size(); ++i) { if (params[i].isGPR()) { CHECK(params[i] != params[0]); jit.add32(params[i].gpr(), params[0].gpr()); } else { CHECK(params[i].isStack()); jit.add32(CCallHelpers::Address(GPRInfo::callFrameRegister, params[i].offsetFromFP()), params[0].gpr()); } } }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc) == (things.size() * (things.size() - 1)) / 2); } void testPatchpointAnyImm(ValueRep rep) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 42); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(ConstrainedValue(arg1, rep)); patchpoint->append(ConstrainedValue(arg2, rep)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); CHECK(params[2].isConstant()); CHECK(params[2].value() == 42); jit.add32( CCallHelpers::TrustedImm32(static_cast<int32_t>(params[2].value())), params[1].gpr(), params[0].gpr()); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1) == 43); } void testPatchpointManyImms() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), 42); Value* arg2 = root->appendNew<Const64Value>(proc, Origin(), 43); Value* arg3 = root->appendNew<Const64Value>(proc, Origin(), 43000000000000ll); Value* arg4 = root->appendNew<ConstDoubleValue>(proc, Origin(), 42.5); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin()); patchpoint->append(ConstrainedValue(arg1, ValueRep::WarmAny)); patchpoint->append(ConstrainedValue(arg2, ValueRep::WarmAny)); patchpoint->append(ConstrainedValue(arg3, ValueRep::WarmAny)); patchpoint->append(ConstrainedValue(arg4, ValueRep::WarmAny)); patchpoint->setGenerator( [&] (CCallHelpers&, const StackmapGenerationParams& params) { CHECK(params.size() == 4); CHECK(params[0] == ValueRep::constant(42)); CHECK(params[1] == ValueRep::constant(43)); CHECK(params[2] == ValueRep::constant(43000000000000ll)); CHECK(params[3] == ValueRep::constant(bitwise_cast<int64_t>(42.5))); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(!compileAndRun<int>(proc)); } void testPatchpointWithRegisterResult() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); patchpoint->resultConstraint = ValueRep::reg(GPRInfo::nonArgGPR0); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0] == ValueRep::reg(GPRInfo::nonArgGPR0)); CHECK(params[1].isGPR()); CHECK(params[2].isGPR()); add32(jit, params[1].gpr(), params[2].gpr(), GPRInfo::nonArgGPR0); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testPatchpointWithStackArgumentResult() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); patchpoint->resultConstraint = ValueRep::stackArgument(0); patchpoint->clobber(RegisterSet::macroScratchRegisters()); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0] == ValueRep::stack(-static_cast<intptr_t>(proc.frameSize()))); CHECK(params[1].isGPR()); CHECK(params[2].isGPR()); jit.add32(params[1].gpr(), params[2].gpr(), jit.scratchRegister()); jit.store32(jit.scratchRegister(), CCallHelpers::Address(CCallHelpers::stackPointerRegister, 0)); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<int>(proc, 1, 2) == 3); } void testPatchpointWithAnyResult() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Double, Origin()); patchpoint->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); patchpoint->resultConstraint = ValueRep::WarmAny; patchpoint->clobberLate(RegisterSet::allFPRs()); patchpoint->clobber(RegisterSet::macroScratchRegisters()); patchpoint->clobber(RegisterSet(GPRInfo::regT0)); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 3); CHECK(params[0].isStack()); CHECK(params[1].isGPR()); CHECK(params[2].isGPR()); add32(jit, params[1].gpr(), params[2].gpr(), GPRInfo::regT0); jit.convertInt32ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0); jit.storeDouble(FPRInfo::fpRegT0, CCallHelpers::Address(GPRInfo::callFrameRegister, params[0].offsetFromFP())); }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); CHECK(compileAndRun<double>(proc, 1, 2) == 3); } void testSimpleCheck() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); CheckValue* check = root->appendNew<CheckValue>(proc, Check, Origin(), arg); check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code, 0) == 0); CHECK(invoke<int>(*code, 1) == 42); } void testCheckFalse() { Procedure proc; BasicBlock* root = proc.addBlock(); CheckValue* check = root->appendNew<CheckValue>( proc, Check, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); check->setGenerator( [&] (CCallHelpers&, const StackmapGenerationParams&) { CHECK(!"This should not have executed"); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code) == 0); } void testCheckTrue() { Procedure proc; BasicBlock* root = proc.addBlock(); CheckValue* check = root->appendNew<CheckValue>( proc, Check, Origin(), root->appendNew<Const32Value>(proc, Origin(), 1)); check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.value()->opcode() == Patchpoint); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code) == 42); } void testCheckLessThan() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); CheckValue* check = root->appendNew<CheckValue>( proc, Check, Origin(), root->appendNew<Value>( proc, LessThan, Origin(), arg, root->appendNew<Const32Value>(proc, Origin(), 42))); check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(invoke<int>(*code, 42) == 0); CHECK(invoke<int>(*code, 1000) == 0); CHECK(invoke<int>(*code, 41) == 42); CHECK(invoke<int>(*code, 0) == 42); CHECK(invoke<int>(*code, -1) == 42); } void testCheckMegaCombo() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* index = root->appendNew<Value>( proc, ZExt32, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* ptr = root->appendNew<Value>( proc, Add, Origin(), base, root->appendNew<Value>( proc, Shl, Origin(), index, root->appendNew<Const32Value>(proc, Origin(), 1))); CheckValue* check = root->appendNew<CheckValue>( proc, Check, Origin(), root->appendNew<Value>( proc, LessThan, Origin(), root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr), root->appendNew<Const32Value>(proc, Origin(), 42))); check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); int8_t value; value = 42; CHECK(invoke<int>(*code, &value - 2, 1) == 0); value = 127; CHECK(invoke<int>(*code, &value - 2, 1) == 0); value = 41; CHECK(invoke<int>(*code, &value - 2, 1) == 42); value = 0; CHECK(invoke<int>(*code, &value - 2, 1) == 42); value = -1; CHECK(invoke<int>(*code, &value - 2, 1) == 42); } void testCheckTrickyMegaCombo() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* index = root->appendNew<Value>( proc, ZExt32, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)), root->appendNew<Const32Value>(proc, Origin(), 1))); Value* ptr = root->appendNew<Value>( proc, Add, Origin(), base, root->appendNew<Value>( proc, Shl, Origin(), index, root->appendNew<Const32Value>(proc, Origin(), 1))); CheckValue* check = root->appendNew<CheckValue>( proc, Check, Origin(), root->appendNew<Value>( proc, LessThan, Origin(), root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr), root->appendNew<Const32Value>(proc, Origin(), 42))); check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); int8_t value; value = 42; CHECK(invoke<int>(*code, &value - 2, 0) == 0); value = 127; CHECK(invoke<int>(*code, &value - 2, 0) == 0); value = 41; CHECK(invoke<int>(*code, &value - 2, 0) == 42); value = 0; CHECK(invoke<int>(*code, &value - 2, 0) == 42); value = -1; CHECK(invoke<int>(*code, &value - 2, 0) == 42); } void testCheckTwoMegaCombos() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* index = root->appendNew<Value>( proc, ZExt32, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* ptr = root->appendNew<Value>( proc, Add, Origin(), base, root->appendNew<Value>( proc, Shl, Origin(), index, root->appendNew<Const32Value>(proc, Origin(), 1))); Value* predicate = root->appendNew<Value>( proc, LessThan, Origin(), root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr), root->appendNew<Const32Value>(proc, Origin(), 42)); CheckValue* check = root->appendNew<CheckValue>(proc, Check, Origin(), predicate); check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); CheckValue* check2 = root->appendNew<CheckValue>(proc, Check, Origin(), predicate); check2->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(43), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); int8_t value; value = 42; CHECK(invoke<int>(*code, &value - 2, 1) == 0); value = 127; CHECK(invoke<int>(*code, &value - 2, 1) == 0); value = 41; CHECK(invoke<int>(*code, &value - 2, 1) == 42); value = 0; CHECK(invoke<int>(*code, &value - 2, 1) == 42); value = -1; CHECK(invoke<int>(*code, &value - 2, 1) == 42); } void testCheckTwoNonRedundantMegaCombos() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* index = root->appendNew<Value>( proc, ZExt32, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* branchPredicate = root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)), root->appendNew<Const32Value>(proc, Origin(), 0xff)); Value* ptr = root->appendNew<Value>( proc, Add, Origin(), base, root->appendNew<Value>( proc, Shl, Origin(), index, root->appendNew<Const32Value>(proc, Origin(), 1))); Value* checkPredicate = root->appendNew<Value>( proc, LessThan, Origin(), root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr), root->appendNew<Const32Value>(proc, Origin(), 42)); root->appendNew<ControlValue>( proc, Branch, Origin(), branchPredicate, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); CheckValue* check = thenCase->appendNew<CheckValue>(proc, Check, Origin(), checkPredicate); check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 43)); CheckValue* check2 = elseCase->appendNew<CheckValue>(proc, Check, Origin(), checkPredicate); check2->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(!params.size()); // This should always work because a function this simple should never have callee // saves. jit.move(CCallHelpers::TrustedImm32(44), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 45)); auto code = compile(proc); int8_t value; value = 42; CHECK(invoke<int>(*code, &value - 2, 1, true) == 43); value = 127; CHECK(invoke<int>(*code, &value - 2, 1, true) == 43); value = 41; CHECK(invoke<int>(*code, &value - 2, 1, true) == 42); value = 0; CHECK(invoke<int>(*code, &value - 2, 1, true) == 42); value = -1; CHECK(invoke<int>(*code, &value - 2, 1, true) == 42); value = 42; CHECK(invoke<int>(*code, &value - 2, 1, false) == 45); value = 127; CHECK(invoke<int>(*code, &value - 2, 1, false) == 45); value = 41; CHECK(invoke<int>(*code, &value - 2, 1, false) == 44); value = 0; CHECK(invoke<int>(*code, &value - 2, 1, false) == 44); value = -1; CHECK(invoke<int>(*code, &value - 2, 1, false) == 44); } void testCheckAddImm() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 42); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); checkAdd->append(arg1); checkAdd->append(arg2); checkAdd->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isConstant()); CHECK(params[1].value() == 42); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1); jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkAdd)); auto code = compile(proc); CHECK(invoke<double>(*code, 0) == 42.0); CHECK(invoke<double>(*code, 1) == 43.0); CHECK(invoke<double>(*code, 42) == 84.0); CHECK(invoke<double>(*code, 2147483647) == 2147483689.0); } void testCheckAddImmCommute() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 42); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg2, arg1); checkAdd->append(arg1); checkAdd->append(arg2); checkAdd->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isConstant()); CHECK(params[1].value() == 42); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1); jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkAdd)); auto code = compile(proc); CHECK(invoke<double>(*code, 0) == 42.0); CHECK(invoke<double>(*code, 1) == 43.0); CHECK(invoke<double>(*code, 42) == 84.0); CHECK(invoke<double>(*code, 2147483647) == 2147483689.0); } void testCheckAddImmSomeRegister() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 42); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); checkAdd->appendSomeRegister(arg1); checkAdd->appendSomeRegister(arg2); checkAdd->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkAdd)); auto code = compile(proc); CHECK(invoke<double>(*code, 0) == 42.0); CHECK(invoke<double>(*code, 1) == 43.0); CHECK(invoke<double>(*code, 42) == 84.0); CHECK(invoke<double>(*code, 2147483647) == 2147483689.0); } void testCheckAdd() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); checkAdd->appendSomeRegister(arg1); checkAdd->appendSomeRegister(arg2); checkAdd->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkAdd)); auto code = compile(proc); CHECK(invoke<double>(*code, 0, 42) == 42.0); CHECK(invoke<double>(*code, 1, 42) == 43.0); CHECK(invoke<double>(*code, 42, 42) == 84.0); CHECK(invoke<double>(*code, 2147483647, 42) == 2147483689.0); } void testCheckAdd64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); checkAdd->appendSomeRegister(arg1); checkAdd->appendSomeRegister(arg2); checkAdd->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkAdd)); auto code = compile(proc); CHECK(invoke<double>(*code, 0ll, 42ll) == 42.0); CHECK(invoke<double>(*code, 1ll, 42ll) == 43.0); CHECK(invoke<double>(*code, 42ll, 42ll) == 84.0); CHECK(invoke<double>(*code, 9223372036854775807ll, 42ll) == static_cast<double>(9223372036854775807ll) + 42.0); } void testCheckAddFold(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); checkAdd->setGenerator( [&] (CCallHelpers&, const StackmapGenerationParams&) { CHECK(!"Should have been folded"); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd); auto code = compile(proc); CHECK(invoke<int>(*code) == a + b); } void testCheckAddFoldFail(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); checkAdd->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams&) { AllowMacroScratchRegisterUsage allowScratch(jit); jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd); auto code = compile(proc); CHECK(invoke<int>(*code) == 42); } void testCheckAddArgumentAliasing64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); // Pretend to use all the args. PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin()); useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); // Last use of first arg (here, arg1). CheckValue* checkAdd1 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); checkAdd1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); // Last use of second arg (here, arg2). CheckValue* checkAdd2 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg3, arg2); checkAdd2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); // Keep arg3 live. PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); // Only use of checkAdd1 and checkAdd2. CheckValue* checkAdd3 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), checkAdd1, checkAdd2); checkAdd3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd3); CHECK(compileAndRun<int64_t>(proc, 1, 2, 3) == 8); } void testCheckAddArgumentAliasing32() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* arg3 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)); // Pretend to use all the args. PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin()); useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); // Last use of first arg (here, arg1). CheckValue* checkAdd1 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); checkAdd1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); // Last use of second arg (here, arg3). CheckValue* checkAdd2 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg2, arg3); checkAdd2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); // Keep arg3 live. PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); // Only use of checkAdd1 and checkAdd2. CheckValue* checkAdd3 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), checkAdd1, checkAdd2); checkAdd3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd3); CHECK(compileAndRun<int32_t>(proc, 1, 2, 3) == 8); } void testCheckAddSelfOverflow64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg, arg); checkAdd->append(arg); checkAdd->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); jit.move(params[0].gpr(), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); // Make sure the arg is not the destination of the operation. PatchpointValue* opaqueUse = root->appendNew<PatchpointValue>(proc, Void, Origin()); opaqueUse->append(ConstrainedValue(arg, ValueRep::SomeRegister)); opaqueUse->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd); auto code = compile(proc); CHECK(invoke<int64_t>(*code, 0ll) == 0); CHECK(invoke<int64_t>(*code, 1ll) == 2); CHECK(invoke<int64_t>(*code, std::numeric_limits<int64_t>::max()) == std::numeric_limits<int64_t>::max()); } void testCheckAddSelfOverflow32() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg, arg); checkAdd->append(arg); checkAdd->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); jit.move(params[0].gpr(), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); // Make sure the arg is not the destination of the operation. PatchpointValue* opaqueUse = root->appendNew<PatchpointValue>(proc, Void, Origin()); opaqueUse->append(ConstrainedValue(arg, ValueRep::SomeRegister)); opaqueUse->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd); auto code = compile(proc); CHECK(invoke<int32_t>(*code, 0ll) == 0); CHECK(invoke<int32_t>(*code, 1ll) == 2); CHECK(invoke<int32_t>(*code, std::numeric_limits<int32_t>::max()) == std::numeric_limits<int32_t>::max()); } void testCheckSubImm() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 42); CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2); checkSub->append(arg1); checkSub->append(arg2); checkSub->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isConstant()); CHECK(params[1].value() == 42); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1); jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkSub)); auto code = compile(proc); CHECK(invoke<double>(*code, 0) == -42.0); CHECK(invoke<double>(*code, 1) == -41.0); CHECK(invoke<double>(*code, 42) == 0.0); CHECK(invoke<double>(*code, -2147483647) == -2147483689.0); } void testCheckSubBadImm() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); int32_t badImm = std::numeric_limits<int>::min(); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), badImm); CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2); checkSub->append(arg1); checkSub->append(arg2); checkSub->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); if (params[1].isConstant()) { CHECK(params[1].value() == badImm); jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(badImm), FPRInfo::fpRegT1); } else { CHECK(params[1].isGPR()); jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1); } jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkSub)); auto code = compile(proc); CHECK(invoke<double>(*code, 0) == -static_cast<double>(badImm)); CHECK(invoke<double>(*code, -1) == -static_cast<double>(badImm) - 1); CHECK(invoke<double>(*code, 1) == -static_cast<double>(badImm) + 1); CHECK(invoke<double>(*code, 42) == -static_cast<double>(badImm) + 42); } void testCheckSub() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2); checkSub->append(arg1); checkSub->append(arg2); checkSub->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkSub)); auto code = compile(proc); CHECK(invoke<double>(*code, 0, 42) == -42.0); CHECK(invoke<double>(*code, 1, 42) == -41.0); CHECK(invoke<double>(*code, 42, 42) == 0.0); CHECK(invoke<double>(*code, -2147483647, 42) == -2147483689.0); } NEVER_INLINE double doubleSub(double a, double b) { return a - b; } void testCheckSub64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2); checkSub->append(arg1); checkSub->append(arg2); checkSub->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkSub)); auto code = compile(proc); CHECK(invoke<double>(*code, 0ll, 42ll) == -42.0); CHECK(invoke<double>(*code, 1ll, 42ll) == -41.0); CHECK(invoke<double>(*code, 42ll, 42ll) == 0.0); CHECK(invoke<double>(*code, -9223372036854775807ll, 42ll) == doubleSub(static_cast<double>(-9223372036854775807ll), 42.0)); } void testCheckSubFold(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b); CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2); checkSub->setGenerator( [&] (CCallHelpers&, const StackmapGenerationParams&) { CHECK(!"Should have been folded"); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkSub); auto code = compile(proc); CHECK(invoke<int>(*code) == a - b); } void testCheckSubFoldFail(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b); CheckValue* checkSub = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2); checkSub->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams&) { AllowMacroScratchRegisterUsage allowScratch(jit); jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkSub); auto code = compile(proc); CHECK(invoke<int>(*code) == 42); } void testCheckNeg() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), 0); Value* arg2 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); CheckValue* checkNeg = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2); checkNeg->append(arg2); checkNeg->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 1); CHECK(params[0].isGPR()); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT1); jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkNeg)); auto code = compile(proc); CHECK(invoke<double>(*code, 0) == 0.0); CHECK(invoke<double>(*code, 1) == -1.0); CHECK(invoke<double>(*code, 42) == -42.0); CHECK(invoke<double>(*code, -2147483647 - 1) == 2147483648.0); } void testCheckNeg64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const64Value>(proc, Origin(), 0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); CheckValue* checkNeg = root->appendNew<CheckValue>(proc, CheckSub, Origin(), arg1, arg2); checkNeg->append(arg2); checkNeg->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 1); CHECK(params[0].isGPR()); jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT1); jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkNeg)); auto code = compile(proc); CHECK(invoke<double>(*code, 0ll) == 0.0); CHECK(invoke<double>(*code, 1ll) == -1.0); CHECK(invoke<double>(*code, 42ll) == -42.0); CHECK(invoke<double>(*code, -9223372036854775807ll - 1) == 9223372036854775808.0); } void testCheckMul() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul->append(arg1); checkMul->append(arg2); checkMul->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkMul)); auto code = compile(proc); CHECK(invoke<double>(*code, 0, 42) == 0.0); CHECK(invoke<double>(*code, 1, 42) == 42.0); CHECK(invoke<double>(*code, 42, 42) == 42.0 * 42.0); CHECK(invoke<double>(*code, 2147483647, 42) == 2147483647.0 * 42.0); } void testCheckMulMemory() { Procedure proc; BasicBlock* root = proc.addBlock(); int left; int right; Value* arg1 = root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &left)); Value* arg2 = root->appendNew<MemoryValue>( proc, Load, Int32, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), &right)); CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul->append(arg1); checkMul->append(arg2); checkMul->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkMul)); auto code = compile(proc); left = 0; right = 42; CHECK(invoke<double>(*code) == 0.0); left = 1; right = 42; CHECK(invoke<double>(*code) == 42.0); left = 42; right = 42; CHECK(invoke<double>(*code) == 42.0 * 42.0); left = 2147483647; right = 42; CHECK(invoke<double>(*code) == 2147483647.0 * 42.0); } void testCheckMul2() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), 2); CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul->append(arg1); checkMul->append(arg2); checkMul->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isConstant()); CHECK(params[1].value() == 2); jit.convertInt32ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(2), FPRInfo::fpRegT1); jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkMul)); auto code = compile(proc); CHECK(invoke<double>(*code, 0) == 0.0); CHECK(invoke<double>(*code, 1) == 2.0); CHECK(invoke<double>(*code, 42) == 42.0 * 2.0); CHECK(invoke<double>(*code, 2147483647) == 2147483647.0 * 2.0); } void testCheckMul64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul->append(arg1); checkMul->append(arg2); checkMul->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkMul)); auto code = compile(proc); CHECK(invoke<double>(*code, 0, 42) == 0.0); CHECK(invoke<double>(*code, 1, 42) == 42.0); CHECK(invoke<double>(*code, 42, 42) == 42.0 * 42.0); CHECK(invoke<double>(*code, 9223372036854775807ll, 42) == static_cast<double>(9223372036854775807ll) * 42.0); } void testCheckMulFold(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b); CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul->setGenerator( [&] (CCallHelpers&, const StackmapGenerationParams&) { CHECK(!"Should have been folded"); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkMul); auto code = compile(proc); CHECK(invoke<int>(*code) == a * b); } void testCheckMulFoldFail(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Const32Value>(proc, Origin(), a); Value* arg2 = root->appendNew<Const32Value>(proc, Origin(), b); CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams&) { AllowMacroScratchRegisterUsage allowScratch(jit); jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkMul); auto code = compile(proc); CHECK(invoke<int>(*code) == 42); } void testCheckMulArgumentAliasing64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); // Pretend to use all the args. PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin()); useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); // Last use of first arg (here, arg1). CheckValue* checkMul1 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); // Last use of second arg (here, arg2). CheckValue* checkMul2 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg3, arg2); checkMul2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); // Keep arg3 live. PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); // Only use of checkMul1 and checkMul2. CheckValue* checkMul3 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), checkMul1, checkMul2); checkMul3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkMul3); CHECK(compileAndRun<int64_t>(proc, 2, 3, 4) == 72); } void testCheckMulArgumentAliasing32() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* arg3 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)); // Pretend to use all the args. PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin()); useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); // Last use of first arg (here, arg1). CheckValue* checkMul1 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); // Last use of second arg (here, arg3). CheckValue* checkMul2 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg2, arg3); checkMul2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); // Keep arg3 live. PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); // Only use of checkMul1 and checkMul2. CheckValue* checkMul3 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), checkMul1, checkMul2); checkMul3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); root->appendNew<ControlValue>(proc, Return, Origin(), checkMul3); CHECK(compileAndRun<int32_t>(proc, 2, 3, 4) == 72); } void testCheckMul64SShr() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1 = root->appendNew<Value>( proc, SShr, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const32Value>(proc, Origin(), 1)); Value* arg2 = root->appendNew<Value>( proc, SShr, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), root->appendNew<Const32Value>(proc, Origin(), 1)); CheckValue* checkMul = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); checkMul->append(arg1); checkMul->append(arg2); checkMul->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 2); CHECK(params[0].isGPR()); CHECK(params[1].isGPR()); jit.convertInt64ToDouble(params[0].gpr(), FPRInfo::fpRegT0); jit.convertInt64ToDouble(params[1].gpr(), FPRInfo::fpRegT1); jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, IToD, Origin(), checkMul)); auto code = compile(proc); CHECK(invoke<double>(*code, 0ll, 42ll) == 0.0); CHECK(invoke<double>(*code, 1ll, 42ll) == 0.0); CHECK(invoke<double>(*code, 42ll, 42ll) == (42.0 / 2.0) * (42.0 / 2.0)); CHECK(invoke<double>(*code, 10000000000ll, 10000000000ll) == 25000000000000000000.0); } template<typename LeftFunctor, typename RightFunctor, typename InputType> void genericTestCompare( B3::Opcode opcode, const LeftFunctor& leftFunctor, const RightFunctor& rightFunctor, InputType left, InputType right, int result) { // Using a compare. { Procedure proc; BasicBlock* root = proc.addBlock(); Value* leftValue = leftFunctor(root, proc); Value* rightValue = rightFunctor(root, proc); Value* comparisonResult = root->appendNew<Value>(proc, opcode, Origin(), leftValue, rightValue); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, NotEqual, Origin(), comparisonResult, root->appendIntConstant(proc, Origin(), comparisonResult->type(), 0))); CHECK(compileAndRun<int>(proc, left, right) == result); } // Using a branch. { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* leftValue = leftFunctor(root, proc); Value* rightValue = rightFunctor(root, proc); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>(proc, opcode, Origin(), leftValue, rightValue), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); // We use a patchpoint on the then case to ensure that this doesn't get if-converted. PatchpointValue* patchpoint = thenCase->appendNew<PatchpointValue>(proc, Int32, Origin()); patchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params.size() == 1); CHECK(params[0].isGPR()); jit.move(CCallHelpers::TrustedImm32(1), params[0].gpr()); }); thenCase->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); CHECK(compileAndRun<int>(proc, left, right) == result); } } template<typename InputType> InputType modelCompare(B3::Opcode opcode, InputType left, InputType right) { switch (opcode) { case Equal: return left == right; case NotEqual: return left != right; case LessThan: return left < right; case GreaterThan: return left > right; case LessEqual: return left <= right; case GreaterEqual: return left >= right; case Above: return static_cast<typename std::make_unsigned<InputType>::type>(left) > static_cast<typename std::make_unsigned<InputType>::type>(right); case Below: return static_cast<typename std::make_unsigned<InputType>::type>(left) < static_cast<typename std::make_unsigned<InputType>::type>(right); case AboveEqual: return static_cast<typename std::make_unsigned<InputType>::type>(left) >= static_cast<typename std::make_unsigned<InputType>::type>(right); case BelowEqual: return static_cast<typename std::make_unsigned<InputType>::type>(left) <= static_cast<typename std::make_unsigned<InputType>::type>(right); case BitAnd: return !!(left & right); default: RELEASE_ASSERT_NOT_REACHED(); return 0; } } template<typename T> void testCompareLoad(B3::Opcode opcode, B3::Opcode loadOpcode, int left, int right) { int result = modelCompare(opcode, modelLoad<T>(left), right); // Test addr-to-tmp int slot = left; genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<MemoryValue>( proc, loadOpcode, Int32, Origin(), block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Value>( proc, Trunc, Origin(), block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); }, left, right, result); // Test addr-to-imm slot = left; genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<MemoryValue>( proc, loadOpcode, Int32, Origin(), block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const32Value>(proc, Origin(), right); }, left, right, result); result = modelCompare(opcode, left, modelLoad<T>(right)); // Test tmp-to-addr slot = right; genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Value>( proc, Trunc, Origin(), block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<MemoryValue>( proc, loadOpcode, Int32, Origin(), block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); }, left, right, result); // Test imm-to-addr slot = right; genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const32Value>(proc, Origin(), left); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<MemoryValue>( proc, loadOpcode, Int32, Origin(), block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); }, left, right, result); // Test addr-to-addr, with the same addr. slot = left; Value* value; genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { value = block->appendNew<MemoryValue>( proc, loadOpcode, Int32, Origin(), block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); return value; }, [&] (BasicBlock*, Procedure&) { return value; }, left, left, modelCompare(opcode, modelLoad<T>(left), modelLoad<T>(left))); } void testCompareImpl(B3::Opcode opcode, int64_t left, int64_t right) { int64_t result = modelCompare(opcode, left, right); int32_t int32Result = modelCompare(opcode, static_cast<int32_t>(left), static_cast<int32_t>(right)); // Test tmp-to-tmp. genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); }, left, right, result); genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Value>( proc, Trunc, Origin(), block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Value>( proc, Trunc, Origin(), block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); }, left, right, int32Result); // Test imm-to-tmp. genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const64Value>(proc, Origin(), left); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); }, left, right, result); genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const32Value>(proc, Origin(), left); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Value>( proc, Trunc, Origin(), block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); }, left, right, int32Result); // Test tmp-to-imm. genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const64Value>(proc, Origin(), right); }, left, right, result); genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Value>( proc, Trunc, Origin(), block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const32Value>(proc, Origin(), right); }, left, right, int32Result); // Test imm-to-imm. genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const64Value>(proc, Origin(), left); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const64Value>(proc, Origin(), right); }, left, right, result); genericTestCompare( opcode, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const32Value>(proc, Origin(), left); }, [&] (BasicBlock* block, Procedure& proc) { return block->appendNew<Const32Value>(proc, Origin(), right); }, left, right, int32Result); testCompareLoad<int32_t>(opcode, Load, left, right); testCompareLoad<int8_t>(opcode, Load8S, left, right); testCompareLoad<uint8_t>(opcode, Load8Z, left, right); testCompareLoad<int16_t>(opcode, Load16S, left, right); testCompareLoad<uint16_t>(opcode, Load16Z, left, right); } void testCompare(B3::Opcode opcode, int64_t left, int64_t right) { testCompareImpl(opcode, left, right); testCompareImpl(opcode, left, right + 1); testCompareImpl(opcode, left, right - 1); } void testEqualDouble(double left, double right, bool result) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1))); CHECK(compileAndRun<bool>(proc, left, right) == result); } int simpleFunction(int a, int b) { return a + b; } void testCallSimple(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<CCallValue>( proc, Int32, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); CHECK(compileAndRun<int>(proc, a, b) == a + b); } void testCallRare(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* common = proc.addBlock(); BasicBlock* rare = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), FrequentedBlock(rare, FrequencyClass::Rare), FrequentedBlock(common)); common->appendNew<ControlValue>( proc, Return, Origin(), common->appendNew<Const32Value>(proc, Origin(), 0)); rare->appendNew<ControlValue>( proc, Return, Origin(), rare->appendNew<CCallValue>( proc, Int32, Origin(), rare->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)), rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); CHECK(compileAndRun<int>(proc, true, a, b) == a + b); } void testCallRareLive(int a, int b, int c) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* common = proc.addBlock(); BasicBlock* rare = proc.addBlock(); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), FrequentedBlock(rare, FrequencyClass::Rare), FrequentedBlock(common)); common->appendNew<ControlValue>( proc, Return, Origin(), common->appendNew<Const32Value>(proc, Origin(), 0)); rare->appendNew<ControlValue>( proc, Return, Origin(), rare->appendNew<Value>( proc, Add, Origin(), rare->appendNew<CCallValue>( proc, Int32, Origin(), rare->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)), rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)), rare->appendNew<Value>( proc, Trunc, Origin(), rare->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)))); CHECK(compileAndRun<int>(proc, true, a, b, c) == a + b + c); } void testCallSimplePure(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<CCallValue>( proc, Int32, Origin(), Effects::none(), root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); CHECK(compileAndRun<int>(proc, a, b) == a + b); } int functionWithHellaArguments(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, int s, int t, int u, int v, int w, int x, int y, int z) { return (a << 0) + (b << 1) + (c << 2) + (d << 3) + (e << 4) + (f << 5) + (g << 6) + (h << 7) + (i << 8) + (j << 9) + (k << 10) + (l << 11) + (m << 12) + (n << 13) + (o << 14) + (p << 15) + (q << 16) + (r << 17) + (s << 18) + (t << 19) + (u << 20) + (v << 21) + (w << 22) + (x << 23) + (y << 24) + (z << 25); } void testCallFunctionWithHellaArguments() { Procedure proc; BasicBlock* root = proc.addBlock(); Vector<Value*> args; for (unsigned i = 0; i < 26; ++i) args.append(root->appendNew<Const32Value>(proc, Origin(), i + 1)); CCallValue* call = root->appendNew<CCallValue>( proc, Int32, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaArguments))); call->children().appendVector(args); root->appendNew<ControlValue>(proc, Return, Origin(), call); CHECK(compileAndRun<int>(proc) == functionWithHellaArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)); } void testReturnDouble(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<ConstDoubleValue>(proc, Origin(), value)); CHECK(isIdentical(compileAndRun<double>(proc), value)); } void testReturnFloat(float value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<ConstFloatValue>(proc, Origin(), value)); CHECK(isIdentical(compileAndRun<float>(proc), value)); } double simpleFunctionDouble(double a, double b) { return a + b; } void testCallSimpleDouble(double a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<CCallValue>( proc, Double, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunctionDouble)), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1))); CHECK(compileAndRun<double>(proc, a, b) == a + b); } float simpleFunctionFloat(float a, float b) { return a + b; } void testCallSimpleFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<CCallValue>( proc, Float, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunctionFloat)), floatValue1, floatValue2)); CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), a + b)); } double functionWithHellaDoubleArguments(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j, double k, double l, double m, double n, double o, double p, double q, double r, double s, double t, double u, double v, double w, double x, double y, double z) { return a * pow(2, 0) + b * pow(2, 1) + c * pow(2, 2) + d * pow(2, 3) + e * pow(2, 4) + f * pow(2, 5) + g * pow(2, 6) + h * pow(2, 7) + i * pow(2, 8) + j * pow(2, 9) + k * pow(2, 10) + l * pow(2, 11) + m * pow(2, 12) + n * pow(2, 13) + o * pow(2, 14) + p * pow(2, 15) + q * pow(2, 16) + r * pow(2, 17) + s * pow(2, 18) + t * pow(2, 19) + u * pow(2, 20) + v * pow(2, 21) + w * pow(2, 22) + x * pow(2, 23) + y * pow(2, 24) + z * pow(2, 25); } void testCallFunctionWithHellaDoubleArguments() { Procedure proc; BasicBlock* root = proc.addBlock(); Vector<Value*> args; for (unsigned i = 0; i < 26; ++i) args.append(root->appendNew<ConstDoubleValue>(proc, Origin(), i + 1)); CCallValue* call = root->appendNew<CCallValue>( proc, Double, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaDoubleArguments))); call->children().appendVector(args); root->appendNew<ControlValue>(proc, Return, Origin(), call); CHECK(compileAndRun<double>(proc) == functionWithHellaDoubleArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)); } float functionWithHellaFloatArguments(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l, float m, float n, float o, float p, float q, float r, float s, float t, float u, float v, float w, float x, float y, float z) { return a * pow(2, 0) + b * pow(2, 1) + c * pow(2, 2) + d * pow(2, 3) + e * pow(2, 4) + f * pow(2, 5) + g * pow(2, 6) + h * pow(2, 7) + i * pow(2, 8) + j * pow(2, 9) + k * pow(2, 10) + l * pow(2, 11) + m * pow(2, 12) + n * pow(2, 13) + o * pow(2, 14) + p * pow(2, 15) + q * pow(2, 16) + r * pow(2, 17) + s * pow(2, 18) + t * pow(2, 19) + u * pow(2, 20) + v * pow(2, 21) + w * pow(2, 22) + x * pow(2, 23) + y * pow(2, 24) + z * pow(2, 25); } void testCallFunctionWithHellaFloatArguments() { Procedure proc; BasicBlock* root = proc.addBlock(); Vector<Value*> args; for (unsigned i = 0; i < 26; ++i) args.append(root->appendNew<ConstFloatValue>(proc, Origin(), i + 1)); CCallValue* call = root->appendNew<CCallValue>( proc, Float, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaFloatArguments))); call->children().appendVector(args); root->appendNew<ControlValue>(proc, Return, Origin(), call); CHECK(compileAndRun<float>(proc) == functionWithHellaFloatArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)); } void testChillDiv(int num, int den, int res) { // Test non-constant. { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, ChillDiv, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun<int>(proc, num, den) == res); } // Test constant. { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, ChillDiv, Origin(), root->appendNew<Const32Value>(proc, Origin(), num), root->appendNew<Const32Value>(proc, Origin(), den))); CHECK(compileAndRun<int>(proc) == res); } } void testChillDivTwice(int num1, int den1, int num2, int den2, int res) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Value>( proc, ChillDiv, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))), root->appendNew<Value>( proc, ChillDiv, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))))); CHECK(compileAndRun<int>(proc, num1, den1, num2, den2) == res); } void testChillDiv64(int64_t num, int64_t den, int64_t res) { if (!is64Bit()) return; // Test non-constant. { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, ChillDiv, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); CHECK(compileAndRun<int64_t>(proc, num, den) == res); } // Test constant. { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, ChillDiv, Origin(), root->appendNew<Const64Value>(proc, Origin(), num), root->appendNew<Const64Value>(proc, Origin(), den))); CHECK(compileAndRun<int64_t>(proc) == res); } } void testModArg(int64_t value) { if (!value) return; Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument, argument); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(!compileAndRun<int64_t>(proc, value)); } void testModArgs(int64_t numerator, int64_t denominator) { if (!denominator) return; if (numerator == std::numeric_limits<int64_t>::min() && denominator == -1) return; Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == numerator % denominator); } void testModImms(int64_t numerator, int64_t denominator) { if (!denominator) return; if (numerator == std::numeric_limits<int64_t>::min() && denominator == -1) return; Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator); Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator); Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == numerator % denominator); } void testModArg32(int32_t value) { if (!value) return; Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument, argument); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(!compileAndRun<int32_t>(proc, value)); } void testModArgs32(int32_t numerator, int32_t denominator) { if (!denominator) return; if (numerator == std::numeric_limits<int32_t>::min() && denominator == -1) return; Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == numerator % denominator); } void testModImms32(int32_t numerator, int32_t denominator) { if (!denominator) return; if (numerator == std::numeric_limits<int32_t>::min() && denominator == -1) return; Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator); Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator); Value* result = root->appendNew<Value>(proc, Mod, Origin(), argument1, argument2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == numerator % denominator); } void testChillModArg(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(!compileAndRun<int64_t>(proc, value)); } void testChillModArgs(int64_t numerator, int64_t denominator) { 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, ChillMod, Origin(), argument1, argument2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator)); } void testChillModImms(int64_t numerator, int64_t denominator) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator); Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator); Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator)); } void testChillModArg32(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(!compileAndRun<int32_t>(proc, value)); } void testChillModArgs32(int32_t numerator, int32_t denominator) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator)); } void testChillModImms32(int32_t numerator, int32_t denominator) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator); Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator); Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2); root->appendNew<ControlValue>(proc, Return, Origin(), result); CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator)); } void testSwitch(unsigned degree, unsigned gap = 1) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* terminate = proc.addBlock(); terminate->appendNew<ControlValue>( proc, Return, Origin(), terminate->appendNew<Const32Value>(proc, Origin(), 0)); SwitchValue* switchValue = root->appendNew<SwitchValue>( proc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), FrequentedBlock(terminate)); for (unsigned i = 0; i < degree; ++i) { BasicBlock* newBlock = proc.addBlock(); newBlock->appendNew<ControlValue>( proc, Return, Origin(), newBlock->appendNew<ArgumentRegValue>( proc, Origin(), (i & 1) ? GPRInfo::argumentGPR2 : GPRInfo::argumentGPR1)); switchValue->appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock))); } auto code = compile(proc); for (unsigned i = 0; i < degree; ++i) { CHECK(invoke<int32_t>(*code, i * gap, 42, 11) == ((i & 1) ? 11 : 42)); if (gap > 1) { CHECK(!invoke<int32_t>(*code, i * gap + 1, 42, 11)); CHECK(!invoke<int32_t>(*code, i * gap - 1, 42, 11)); } } CHECK(!invoke<int32_t>(*code, -1, 42, 11)); CHECK(!invoke<int32_t>(*code, degree * gap, 42, 11)); CHECK(!invoke<int32_t>(*code, degree * gap + 1, 42, 11)); } void testSwitchChillDiv(unsigned degree, unsigned gap = 1) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* left = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); Value* right = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); BasicBlock* terminate = proc.addBlock(); terminate->appendNew<ControlValue>( proc, Return, Origin(), terminate->appendNew<Const32Value>(proc, Origin(), 0)); SwitchValue* switchValue = root->appendNew<SwitchValue>( proc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), FrequentedBlock(terminate)); for (unsigned i = 0; i < degree; ++i) { BasicBlock* newBlock = proc.addBlock(); newBlock->appendNew<ControlValue>( proc, Return, Origin(), newBlock->appendNew<Value>( proc, ChillDiv, Origin(), (i & 1) ? right : left, (i & 1) ? left : right)); switchValue->appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock))); } auto code = compile(proc); for (unsigned i = 0; i < degree; ++i) { CHECK(invoke<int32_t>(*code, i * gap, 42, 11) == ((i & 1) ? 11/42 : 42/11)); if (gap > 1) { CHECK(!invoke<int32_t>(*code, i * gap + 1, 42, 11)); CHECK(!invoke<int32_t>(*code, i * gap - 1, 42, 11)); } } CHECK(!invoke<int32_t>(*code, -1, 42, 11)); CHECK(!invoke<int32_t>(*code, degree * gap, 42, 11)); CHECK(!invoke<int32_t>(*code, degree * gap + 1, 42, 11)); } void testSwitchTargettingSameBlock() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* terminate = proc.addBlock(); terminate->appendNew<ControlValue>( proc, Return, Origin(), terminate->appendNew<Const32Value>(proc, Origin(), 5)); SwitchValue* switchValue = root->appendNew<SwitchValue>( proc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), FrequentedBlock(terminate)); BasicBlock* otherTarget = proc.addBlock(); otherTarget->appendNew<ControlValue>( proc, Return, Origin(), otherTarget->appendNew<Const32Value>(proc, Origin(), 42)); switchValue->appendCase(SwitchCase(3, FrequentedBlock(otherTarget))); switchValue->appendCase(SwitchCase(13, FrequentedBlock(otherTarget))); auto code = compile(proc); for (unsigned i = 0; i < 20; ++i) { int32_t expected = (i == 3 || i == 13) ? 42 : 5; CHECK(invoke<int32_t>(*code, i) == expected); } } void testSwitchTargettingSameBlockFoldPathConstant() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* terminate = proc.addBlock(); terminate->appendNew<ControlValue>( proc, Return, Origin(), terminate->appendNew<Const32Value>(proc, Origin(), 42)); Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); SwitchValue* switchValue = root->appendNew<SwitchValue>( proc, Origin(), argument, FrequentedBlock(terminate)); BasicBlock* otherTarget = proc.addBlock(); otherTarget->appendNew<ControlValue>( proc, Return, Origin(), argument); switchValue->appendCase(SwitchCase(3, FrequentedBlock(otherTarget))); switchValue->appendCase(SwitchCase(13, FrequentedBlock(otherTarget))); auto code = compile(proc); for (unsigned i = 0; i < 20; ++i) { int32_t expected = (i == 3 || i == 13) ? i : 42; CHECK(invoke<int32_t>(*code, i) == expected); } } void testTruncFold(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<Const64Value>(proc, Origin(), value))); CHECK(compileAndRun<int>(proc) == static_cast<int>(value)); } void testZExt32(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, ZExt32, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(compileAndRun<uint64_t>(proc, value) == static_cast<uint64_t>(static_cast<uint32_t>(value))); } void testZExt32Fold(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, ZExt32, Origin(), root->appendNew<Const32Value>(proc, Origin(), value))); CHECK(compileAndRun<uint64_t>(proc, value) == static_cast<uint64_t>(static_cast<uint32_t>(value))); } void testSExt32(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt32, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value)); } void testSExt32Fold(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt32, Origin(), root->appendNew<Const32Value>(proc, Origin(), value))); CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value)); } void testTruncZExt32(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<Value>( proc, ZExt32, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))))); CHECK(compileAndRun<int32_t>(proc, value) == value); } void testTruncSExt32(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<Value>( proc, SExt32, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))))); CHECK(compileAndRun<int32_t>(proc, value) == value); } void testSExt8(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt8, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value))); } void testSExt8Fold(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt8, Origin(), root->appendNew<Const32Value>(proc, Origin(), value))); CHECK(compileAndRun<int32_t>(proc) == static_cast<int32_t>(static_cast<int8_t>(value))); } void testSExt8SExt8(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt8, Origin(), root->appendNew<Value>( proc, SExt8, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))))); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value))); } void testSExt8SExt16(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt8, Origin(), root->appendNew<Value>( proc, SExt16, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))))); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value))); } void testSExt8BitAnd(int32_t value, int32_t mask) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt8, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), mask)))); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value & mask))); } void testBitAndSExt8(int32_t value, int32_t mask) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, SExt8, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), root->appendNew<Const32Value>(proc, Origin(), mask))); CHECK(compileAndRun<int32_t>(proc, value) == (static_cast<int32_t>(static_cast<int8_t>(value)) & mask)); } void testSExt16(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt16, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value))); } void testSExt16Fold(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt16, Origin(), root->appendNew<Const32Value>(proc, Origin(), value))); CHECK(compileAndRun<int32_t>(proc) == static_cast<int32_t>(static_cast<int16_t>(value))); } void testSExt16SExt16(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt16, Origin(), root->appendNew<Value>( proc, SExt16, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))))); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value))); } void testSExt16SExt8(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt16, Origin(), root->appendNew<Value>( proc, SExt8, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))))); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int8_t>(value))); } void testSExt16BitAnd(int32_t value, int32_t mask) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt16, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), mask)))); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<int32_t>(static_cast<int16_t>(value & mask))); } void testBitAndSExt16(int32_t value, int32_t mask) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, SExt16, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), root->appendNew<Const32Value>(proc, Origin(), mask))); CHECK(compileAndRun<int32_t>(proc, value) == (static_cast<int32_t>(static_cast<int16_t>(value)) & mask)); } void testSExt32BitAnd(int32_t value, int32_t mask) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SExt32, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), mask)))); CHECK(compileAndRun<int64_t>(proc, value) == static_cast<int64_t>(value & mask)); } void testBitAndSExt32(int32_t value, int64_t mask) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, SExt32, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), root->appendNew<Const64Value>(proc, Origin(), mask))); CHECK(compileAndRun<int64_t>(proc, value) == (static_cast<int64_t>(value) & mask)); } void testBasicSelect() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ConstPtrValue>(proc, Origin(), 42)), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); auto code = compile(proc); CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1); CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462); CHECK(invoke<intptr_t>(*code, 43, 1, 2) == 2); CHECK(invoke<intptr_t>(*code, 43, 642462, 32533) == 32533); } void testSelectTest() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); auto code = compile(proc); CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1); CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462); CHECK(invoke<intptr_t>(*code, 0, 1, 2) == 2); CHECK(invoke<intptr_t>(*code, 0, 642462, 32533) == 32533); } void testSelectCompareDouble() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, LessThan, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); auto code = compile(proc); CHECK(invoke<intptr_t>(*code, -1.0, 1.0, 1, 2) == 1); CHECK(invoke<intptr_t>(*code, 42.5, 42.51, 642462, 32533) == 642462); CHECK(invoke<intptr_t>(*code, PNaN, 0.0, 1, 2) == 2); CHECK(invoke<intptr_t>(*code, 42.51, 42.5, 642462, 32533) == 32533); CHECK(invoke<intptr_t>(*code, 42.52, 42.52, 524978245, 352) == 352); } template<B3::Opcode opcode> void testSelectCompareFloat(float a, float b, bool (*operation)(float, float)) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, opcode, Origin(), floatValue1, floatValue2), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42, -5), operation(a, b) ? 42 : -5)); } void testSelectCompareFloat(float a, float b) { testSelectCompareFloat<Equal>(a, b, [](float a, float b) -> bool { return a == b; }); testSelectCompareFloat<NotEqual>(a, b, [](float a, float b) -> bool { return a != b; }); testSelectCompareFloat<LessThan>(a, b, [](float a, float b) -> bool { return a < b; }); testSelectCompareFloat<GreaterThan>(a, b, [](float a, float b) -> bool { return a > b; }); testSelectCompareFloat<LessEqual>(a, b, [](float a, float b) -> bool { return a <= b; }); testSelectCompareFloat<GreaterEqual>(a, b, [](float a, float b) -> bool { return a >= b; }); testSelectCompareFloat<EqualOrUnordered>(a, b, [](float a, float b) -> bool { return a != a || b != b || a == b; }); } template<B3::Opcode opcode> void testSelectCompareFloatToDouble(float a, float b, bool (*operation)(float, float)) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* doubleValue1 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue1); Value* doubleValue2 = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue2); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, opcode, Origin(), doubleValue1, doubleValue2), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))); CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42, -5), operation(a, b) ? 42 : -5)); } void testSelectCompareFloatToDouble(float a, float b) { testSelectCompareFloatToDouble<Equal>(a, b, [](float a, float b) -> bool { return a == b; }); testSelectCompareFloatToDouble<NotEqual>(a, b, [](float a, float b) -> bool { return a != b; }); testSelectCompareFloatToDouble<LessThan>(a, b, [](float a, float b) -> bool { return a < b; }); testSelectCompareFloatToDouble<GreaterThan>(a, b, [](float a, float b) -> bool { return a > b; }); testSelectCompareFloatToDouble<LessEqual>(a, b, [](float a, float b) -> bool { return a <= b; }); testSelectCompareFloatToDouble<GreaterEqual>(a, b, [](float a, float b) -> bool { return a >= b; }); testSelectCompareFloatToDouble<EqualOrUnordered>(a, b, [](float a, float b) -> bool { return a != a || b != b || a == b; }); } void testSelectDouble() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ConstPtrValue>(proc, Origin(), 42)), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1))); auto code = compile(proc); CHECK(invoke<double>(*code, 42, 1.5, 2.6) == 1.5); CHECK(invoke<double>(*code, 42, 642462.7, 32533.8) == 642462.7); CHECK(invoke<double>(*code, 43, 1.9, 2.0) == 2.0); CHECK(invoke<double>(*code, 43, 642462.1, 32533.2) == 32533.2); } void testSelectDoubleTest() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1))); auto code = compile(proc); CHECK(invoke<double>(*code, 42, 1.5, 2.6) == 1.5); CHECK(invoke<double>(*code, 42, 642462.7, 32533.8) == 642462.7); CHECK(invoke<double>(*code, 0, 1.9, 2.0) == 2.0); CHECK(invoke<double>(*code, 0, 642462.1, 32533.2) == 32533.2); } void testSelectDoubleCompareDouble() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, LessThan, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1)), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3))); auto code = compile(proc); CHECK(invoke<double>(*code, -1.0, 1.0, 1.1, 2.2) == 1.1); CHECK(invoke<double>(*code, 42.5, 42.51, 642462.3, 32533.4) == 642462.3); CHECK(invoke<double>(*code, PNaN, 0.0, 1.5, 2.6) == 2.6); CHECK(invoke<double>(*code, 42.51, 42.5, 642462.7, 32533.8) == 32533.8); CHECK(invoke<double>(*code, 42.52, 42.52, 524978245.9, 352.0) == 352.0); } void testSelectDoubleCompareFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, LessThan, Origin(), floatValue1, floatValue2), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1))); CHECK(isIdentical(compileAndRun<double>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), 42.1, -M_PI), a < b ? 42.1 : -M_PI)); } void testSelectFloatCompareFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument1int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument2int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); Value* argument3int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)); Value* argument4int32 = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)); Value* floatValue1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument1int32); Value* floatValue2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument2int32); Value* floatValue3 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument3int32); Value* floatValue4 = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument4int32); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, LessThan, Origin(), floatValue1, floatValue2), floatValue3, floatValue4)); CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), bitwise_cast<int32_t>(1.1f), bitwise_cast<int32_t>(-42.f)), a < b ? 1.1f : -42.f)); } template<B3::Opcode opcode> void testSelectDoubleCompareDouble(bool (*operation)(double, double)) { { // Compare arguments and selected arguments are all different. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2); Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, opcode, Origin(), arg0, arg1), arg2, arg3)); auto code = compile(proc); for (auto& left : floatingPointOperands<double>()) { for (auto& right : floatingPointOperands<double>()) { double expected = operation(left.value, right.value) ? 42.5 : -66.5; CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, -66.5), expected)); } } } { // Compare arguments and selected arguments are all different. "thenCase" is live after operation. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2); Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3); Value* result = root->appendNew<Value>(proc, Select, Origin(), root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1), arg2, arg3); PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); for (auto& left : floatingPointOperands<double>()) { for (auto& right : floatingPointOperands<double>()) { double expected = operation(left.value, right.value) ? 42.5 : -66.5; CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, -66.5), expected)); } } } { // Compare arguments and selected arguments are all different. "elseCase" is live after operation. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2); Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3); Value* result = root->appendNew<Value>(proc, Select, Origin(), root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1), arg2, arg3); PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepValuesLive->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); for (auto& left : floatingPointOperands<double>()) { for (auto& right : floatingPointOperands<double>()) { double expected = operation(left.value, right.value) ? 42.5 : -66.5; CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, -66.5), expected)); } } } { // Compare arguments and selected arguments are all different. Both cases are live after operation. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2); Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3); Value* result = root->appendNew<Value>(proc, Select, Origin(), root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1), arg2, arg3); PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepValuesLive->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); for (auto& left : floatingPointOperands<double>()) { for (auto& right : floatingPointOperands<double>()) { double expected = operation(left.value, right.value) ? 42.5 : -66.5; CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, -66.5), expected)); } } } { // The left argument is the same as the "elseCase" argument. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, opcode, Origin(), arg0, arg1), arg2, arg0)); auto code = compile(proc); for (auto& left : floatingPointOperands<double>()) { for (auto& right : floatingPointOperands<double>()) { double expected = operation(left.value, right.value) ? 42.5 : left.value; CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, left.value), expected)); } } } { // The left argument is the same as the "elseCase" argument. "thenCase" is live after operation. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2); Value* result = root->appendNew<Value>(proc, Select, Origin(), root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1), arg2, arg0); PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); for (auto& left : floatingPointOperands<double>()) { for (auto& right : floatingPointOperands<double>()) { double expected = operation(left.value, right.value) ? 42.5 : left.value; CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, left.value), expected)); } } } } void testSelectDoubleCompareDoubleWithAliasing() { testSelectDoubleCompareDouble<Equal>([](double a, double b) -> bool { return a == b; }); testSelectDoubleCompareDouble<NotEqual>([](double a, double b) -> bool { return a != b; }); testSelectDoubleCompareDouble<LessThan>([](double a, double b) -> bool { return a < b; }); testSelectDoubleCompareDouble<GreaterThan>([](double a, double b) -> bool { return a > b; }); testSelectDoubleCompareDouble<LessEqual>([](double a, double b) -> bool { return a <= b; }); testSelectDoubleCompareDouble<GreaterEqual>([](double a, double b) -> bool { return a >= b; }); testSelectDoubleCompareDouble<EqualOrUnordered>([](double a, double b) -> bool { return a != a || b != b || a == b; }); } template<B3::Opcode opcode> void testSelectFloatCompareFloat(bool (*operation)(float, float)) { { // Compare arguments and selected arguments are all different. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); Value* arg3 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, opcode, Origin(), arg0, arg1), arg2, arg3)); auto code = compile(proc); for (auto& left : floatingPointOperands<float>()) { for (auto& right : floatingPointOperands<float>()) { float expected = operation(left.value, right.value) ? 42.5 : -66.5; CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(-66.5f)), expected)); } } } { // Compare arguments and selected arguments are all different. "thenCase" is live after operation. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); Value* arg3 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))); Value* result = root->appendNew<Value>(proc, Select, Origin(), root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1), arg2, arg3); PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); for (auto& left : floatingPointOperands<float>()) { for (auto& right : floatingPointOperands<float>()) { float expected = operation(left.value, right.value) ? 42.5 : -66.5; CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(-66.5f)), expected)); } } } { // Compare arguments and selected arguments are all different. "elseCase" is live after operation. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); Value* arg3 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))); Value* result = root->appendNew<Value>(proc, Select, Origin(), root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1), arg2, arg3); PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepValuesLive->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); for (auto& left : floatingPointOperands<float>()) { for (auto& right : floatingPointOperands<float>()) { float expected = operation(left.value, right.value) ? 42.5 : -66.5; CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(-66.5f)), expected)); } } } { // Compare arguments and selected arguments are all different. Both cases are live after operation. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); Value* arg3 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))); Value* result = root->appendNew<Value>(proc, Select, Origin(), root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1), arg2, arg3); PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepValuesLive->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); for (auto& left : floatingPointOperands<float>()) { for (auto& right : floatingPointOperands<float>()) { float expected = operation(left.value, right.value) ? 42.5 : -66.5; CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(-66.5f)), expected)); } } } { // The left argument is the same as the "elseCase" argument. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, opcode, Origin(), arg0, arg1), arg2, arg0)); auto code = compile(proc); for (auto& left : floatingPointOperands<float>()) { for (auto& right : floatingPointOperands<float>()) { float expected = operation(left.value, right.value) ? 42.5 : left.value; CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(left.value)), expected)); } } } { // The left argument is the same as the "elseCase" argument. "thenCase" is live after operation. Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(), root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); Value* result = root->appendNew<Value>(proc, Select, Origin(), root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1), arg2, arg0); PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin()); keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); for (auto& left : floatingPointOperands<float>()) { for (auto& right : floatingPointOperands<float>()) { float expected = operation(left.value, right.value) ? 42.5 : left.value; CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(left.value)), expected)); } } } } void testSelectFloatCompareFloatWithAliasing() { testSelectFloatCompareFloat<Equal>([](float a, float b) -> bool { return a == b; }); testSelectFloatCompareFloat<NotEqual>([](float a, float b) -> bool { return a != b; }); testSelectFloatCompareFloat<LessThan>([](float a, float b) -> bool { return a < b; }); testSelectFloatCompareFloat<GreaterThan>([](float a, float b) -> bool { return a > b; }); testSelectFloatCompareFloat<LessEqual>([](float a, float b) -> bool { return a <= b; }); testSelectFloatCompareFloat<GreaterEqual>([](float a, float b) -> bool { return a >= b; }); testSelectFloatCompareFloat<EqualOrUnordered>([](float a, float b) -> bool { return a != a || b != b || a == b; }); } void testSelectFold(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<ConstPtrValue>(proc, Origin(), value), root->appendNew<ConstPtrValue>(proc, Origin(), 42)), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); auto code = compile(proc); CHECK(invoke<intptr_t>(*code, 1, 2) == (value == 42 ? 1 : 2)); CHECK(invoke<intptr_t>(*code, 642462, 32533) == (value == 42 ? 642462 : 32533)); } void testSelectInvert() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, Equal, Origin(), root->appendNew<Value>( proc, NotEqual, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<ConstPtrValue>(proc, Origin(), 42)), root->appendNew<Const32Value>(proc, Origin(), 0)), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))); auto code = compile(proc); CHECK(invoke<intptr_t>(*code, 42, 1, 2) == 1); CHECK(invoke<intptr_t>(*code, 42, 642462, 32533) == 642462); CHECK(invoke<intptr_t>(*code, 43, 1, 2) == 2); CHECK(invoke<intptr_t>(*code, 43, 642462, 32533) == 32533); } void testCheckSelect() { Procedure proc; BasicBlock* root = proc.addBlock(); CheckValue* check = root->appendNew<CheckValue>( proc, Check, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>( proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), 0xff)), root->appendNew<ConstPtrValue>(proc, Origin(), -42), root->appendNew<ConstPtrValue>(proc, Origin(), 35)), root->appendNew<ConstPtrValue>(proc, Origin(), 42))); unsigned generationCount = 0; check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams&) { AllowMacroScratchRegisterUsage allowScratch(jit); generationCount++; jit.move(CCallHelpers::TrustedImm32(666), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(generationCount == 1); CHECK(invoke<int>(*code, true) == 0); CHECK(invoke<int>(*code, false) == 666); } void testCheckSelectCheckSelect() { Procedure proc; BasicBlock* root = proc.addBlock(); CheckValue* check = root->appendNew<CheckValue>( proc, Check, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>( proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew<Const32Value>(proc, Origin(), 0xff)), root->appendNew<ConstPtrValue>(proc, Origin(), -42), root->appendNew<ConstPtrValue>(proc, Origin(), 35)), root->appendNew<ConstPtrValue>(proc, Origin(), 42))); unsigned generationCount = 0; check->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams&) { AllowMacroScratchRegisterUsage allowScratch(jit); generationCount++; jit.move(CCallHelpers::TrustedImm32(666), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); CheckValue* check2 = root->appendNew<CheckValue>( proc, Check, Origin(), root->appendNew<Value>( proc, Add, Origin(), root->appendNew<Value>( proc, Select, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>( proc, Origin(), GPRInfo::argumentGPR1)), root->appendNew<Const32Value>(proc, Origin(), 0xff)), root->appendNew<ConstPtrValue>(proc, Origin(), -43), root->appendNew<ConstPtrValue>(proc, Origin(), 36)), root->appendNew<ConstPtrValue>(proc, Origin(), 43))); unsigned generationCount2 = 0; check2->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams&) { AllowMacroScratchRegisterUsage allowScratch(jit); generationCount2++; jit.move(CCallHelpers::TrustedImm32(667), GPRInfo::returnValueGPR); jit.emitFunctionEpilogue(); jit.ret(); }); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); auto code = compile(proc); CHECK(generationCount == 1); CHECK(generationCount2 == 1); CHECK(invoke<int>(*code, true, true) == 0); CHECK(invoke<int>(*code, false, true) == 666); CHECK(invoke<int>(*code, true, false) == 667); } double b3Pow(double x, int y) { if (y < 0 || y > 1000) return pow(x, y); double result = 1; while (y) { if (y & 1) result *= x; x *= x; y >>= 1; } return result; } void testPowDoubleByIntegerLoop(double xOperand, int32_t yOperand) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* x = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); Value* y = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); auto result = powDoubleInt32(proc, root, Origin(), x, y); BasicBlock* continuation = result.first; continuation->appendNew<ControlValue>(proc, Return, Origin(), result.second); CHECK(isIdentical(compileAndRun<double>(proc, xOperand, yOperand), b3Pow(xOperand, yOperand))); } void testTruncOrHigh() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const64Value>(proc, Origin(), 0x100000000)))); int64_t value = 0x123456781234; CHECK(compileAndRun<int>(proc, value) == 0x56781234); } void testTruncOrLow() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const64Value>(proc, Origin(), 0x1000000)))); int64_t value = 0x123456781234; CHECK(compileAndRun<int>(proc, value) == 0x57781234); } void testBitAndOrHigh() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const64Value>(proc, Origin(), 0x8)), root->appendNew<Const64Value>(proc, Origin(), 0x777777777777))); int64_t value = 0x123456781234; CHECK(compileAndRun<int64_t>(proc, value) == 0x123456701234ll); } void testBitAndOrLow() { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, BitAnd, Origin(), root->appendNew<Value>( proc, BitOr, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const64Value>(proc, Origin(), 0x1)), root->appendNew<Const64Value>(proc, Origin(), 0x777777777777))); int64_t value = 0x123456781234; CHECK(compileAndRun<int64_t>(proc, value) == 0x123456701235ll); } void testBranch64Equal(int64_t left, int64_t right) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); bool trueResult = true; thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<MemoryValue>( proc, Load8Z, Origin(), thenCase->appendNew<ConstPtrValue>(proc, Origin(), &trueResult))); bool elseResult = false; elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<MemoryValue>( proc, Load8Z, Origin(), elseCase->appendNew<ConstPtrValue>(proc, Origin(), &elseResult))); CHECK(compileAndRun<bool>(proc, left, right) == (left == right)); } void testBranch64EqualImm(int64_t left, int64_t right) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* arg2 = root->appendNew<ConstPtrValue>(proc, Origin(), right); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); bool trueResult = true; thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<MemoryValue>( proc, Load8Z, Origin(), thenCase->appendNew<ConstPtrValue>(proc, Origin(), &trueResult))); bool elseResult = false; elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<MemoryValue>( proc, Load8Z, Origin(), elseCase->appendNew<ConstPtrValue>(proc, Origin(), &elseResult))); CHECK(compileAndRun<bool>(proc, left) == (left == right)); } void testBranch64EqualMem(int64_t left, int64_t right) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* arg1 = root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); bool trueResult = true; thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<MemoryValue>( proc, Load8Z, Origin(), thenCase->appendNew<ConstPtrValue>(proc, Origin(), &trueResult))); bool elseResult = false; elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<MemoryValue>( proc, Load8Z, Origin(), elseCase->appendNew<ConstPtrValue>(proc, Origin(), &elseResult))); CHECK(compileAndRun<bool>(proc, &left, right) == (left == right)); } void testBranch64EqualMemImm(int64_t left, int64_t right) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* arg1 = root->appendNew<MemoryValue>( proc, Load, pointerType(), Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew<ConstPtrValue>(proc, Origin(), right); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>(proc, Equal, Origin(), arg1, arg2), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); bool trueResult = true; thenCase->appendNew<ControlValue>( proc, Return, Origin(), thenCase->appendNew<MemoryValue>( proc, Load8Z, Origin(), thenCase->appendNew<ConstPtrValue>(proc, Origin(), &trueResult))); bool elseResult = false; elseCase->appendNew<ControlValue>( proc, Return, Origin(), elseCase->appendNew<MemoryValue>( proc, Load8Z, Origin(), elseCase->appendNew<ConstPtrValue>(proc, Origin(), &elseResult))); CHECK(compileAndRun<bool>(proc, &left) == (left == right)); } void testStore8Load8Z(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); int8_t byte; Value* ptr = root->appendNew<ConstPtrValue>(proc, Origin(), &byte); root->appendNew<MemoryValue>( proc, Store8, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), ptr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>(proc, Load8Z, Origin(), ptr)); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<uint8_t>(value)); } void testStore16Load16Z(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); int16_t byte; Value* ptr = root->appendNew<ConstPtrValue>(proc, Origin(), &byte); root->appendNew<MemoryValue>( proc, Store16, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), ptr); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<MemoryValue>(proc, Load16Z, Origin(), ptr)); CHECK(compileAndRun<int32_t>(proc, value) == static_cast<uint16_t>(value)); } void testSShrShl32(int32_t value, int32_t sshrAmount, int32_t shlAmount) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SShr, 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(), shlAmount)), root->appendNew<Const32Value>(proc, Origin(), sshrAmount))); CHECK( compileAndRun<int32_t>(proc, value) == ((value << (shlAmount & 31)) >> (sshrAmount & 31))); } void testSShrShl64(int64_t value, int32_t sshrAmount, int32_t shlAmount) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SShr, Origin(), root->appendNew<Value>( proc, Shl, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew<Const32Value>(proc, Origin(), shlAmount)), root->appendNew<Const32Value>(proc, Origin(), sshrAmount))); CHECK( compileAndRun<int64_t>(proc, value) == ((value << (shlAmount & 63)) >> (sshrAmount & 63))); } template<typename T> void testComputeDivisionMagic(T value, T magicMultiplier, unsigned shift) { DivisionMagic<T> magic = computeDivisionMagic(value); CHECK(magic.magicMultiplier == magicMultiplier); CHECK(magic.shift == shift); } void testTrivialInfiniteLoop() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* loop = proc.addBlock(); root->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop)); loop->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loop)); compile(proc); } void testFoldPathEqual() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenBlock = proc.addBlock(); BasicBlock* elseBlock = proc.addBlock(); Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Branch, Origin(), arg, FrequentedBlock(thenBlock), FrequentedBlock(elseBlock)); thenBlock->appendNew<ControlValue>( proc, Return, Origin(), thenBlock->appendNew<Value>( proc, Equal, Origin(), arg, thenBlock->appendNew<ConstPtrValue>(proc, Origin(), 0))); elseBlock->appendNew<ControlValue>( proc, Return, Origin(), elseBlock->appendNew<Value>( proc, Equal, Origin(), arg, elseBlock->appendNew<ConstPtrValue>(proc, Origin(), 0))); auto code = compile(proc); CHECK(invoke<intptr_t>(*code, 0) == 1); CHECK(invoke<intptr_t>(*code, 1) == 0); CHECK(invoke<intptr_t>(*code, 42) == 0); } void testLShiftSelf32() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, Shl, Origin(), arg, arg)); auto code = compile(proc); auto check = [&] (int32_t value) { CHECK(invoke<int32_t>(*code, value) == value << (value & 31)); }; check(0); check(1); check(31); check(32); } void testRShiftSelf32() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, SShr, Origin(), arg, arg)); auto code = compile(proc); auto check = [&] (int32_t value) { CHECK(invoke<int32_t>(*code, value) == value >> (value & 31)); }; check(0); check(1); check(31); check(32); } void testURShiftSelf32() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>(proc, ZShr, Origin(), arg, arg)); auto code = compile(proc); auto check = [&] (uint32_t value) { CHECK(invoke<uint32_t>(*code, value) == value >> (value & 31)); }; check(0); check(1); check(31); check(32); } void testLShiftSelf64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, Shl, Origin(), arg, root->appendNew<Value>(proc, Trunc, Origin(), arg))); auto code = compile(proc); auto check = [&] (int64_t value) { CHECK(invoke<int64_t>(*code, value) == value << (value & 63)); }; check(0); check(1); check(31); check(32); check(63); check(64); } void testRShiftSelf64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, SShr, Origin(), arg, root->appendNew<Value>(proc, Trunc, Origin(), arg))); auto code = compile(proc); auto check = [&] (int64_t value) { CHECK(invoke<int64_t>(*code, value) == value >> (value & 63)); }; check(0); check(1); check(31); check(32); check(63); check(64); } void testURShiftSelf64() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew<ControlValue>( proc, Return, Origin(), root->appendNew<Value>( proc, ZShr, Origin(), arg, root->appendNew<Value>(proc, Trunc, Origin(), arg))); auto code = compile(proc); auto check = [&] (uint64_t value) { CHECK(invoke<uint64_t>(*code, value) == value >> (value & 63)); }; check(0); check(1); check(31); check(32); check(63); check(64); } void testPatchpointDoubleRegs() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0); PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Double, Origin()); patchpoint->append(arg, ValueRep(FPRInfo::fpRegT0)); patchpoint->resultConstraint = ValueRep(FPRInfo::fpRegT0); unsigned numCalls = 0; patchpoint->setGenerator( [&] (CCallHelpers&, const StackmapGenerationParams&) { numCalls++; }); root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); auto code = compile(proc); CHECK(numCalls == 1); CHECK(invoke<double>(*code, 42.5) == 42.5); } void testSpillDefSmallerThanUse() { Procedure proc; BasicBlock* root = proc.addBlock(); // Move32. Value* arg32 = root->appendNew<Value>( proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg64 = root->appendNew<Value>(proc, ZExt32, Origin(), arg32); // Make sure arg64 is on the stack. PatchpointValue* forceSpill = root->appendNew<PatchpointValue>(proc, Int64, Origin()); RegisterSet clobberSet = RegisterSet::allGPRs(); clobberSet.exclude(RegisterSet::stackRegisters()); clobberSet.exclude(RegisterSet::reservedHardwareRegisters()); clobberSet.clear(GPRInfo::returnValueGPR); // Force the return value for aliasing below. forceSpill->clobberLate(clobberSet); forceSpill->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); jit.xor64(params[0].gpr(), params[0].gpr()); }); // On x86, Sub admit an address for any operand. If it uses the stack, the top bits must be zero. Value* result = root->appendNew<Value>(proc, Sub, Origin(), forceSpill, arg64); root->appendNew<ControlValue>(proc, Return, Origin(), result); auto code = compile(proc); CHECK(invoke<int64_t>(*code, 0xffffffff00000000) == 0); } void testSpillUseLargerThanDef() { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); BasicBlock* tail = proc.addBlock(); RegisterSet clobberSet = RegisterSet::allGPRs(); clobberSet.exclude(RegisterSet::stackRegisters()); clobberSet.exclude(RegisterSet::reservedHardwareRegisters()); Value* condition = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew<ControlValue>( proc, Branch, Origin(), root->appendNew<Value>( proc, Trunc, Origin(), condition), FrequentedBlock(thenCase), FrequentedBlock(elseCase)); Value* truncated = thenCase->appendNew<Value>(proc, ZExt32, Origin(), thenCase->appendNew<Value>(proc, Trunc, Origin(), argument)); UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>(proc, Origin(), truncated); thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(tail)); UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(proc, Origin(), argument); elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(tail)); for (unsigned i = 0; i < 100; ++i) { PatchpointValue* preventTailDuplication = tail->appendNew<PatchpointValue>(proc, Void, Origin()); preventTailDuplication->clobberLate(clobberSet); preventTailDuplication->setGenerator([] (CCallHelpers&, const StackmapGenerationParams&) { }); } PatchpointValue* forceSpill = tail->appendNew<PatchpointValue>(proc, Void, Origin()); forceSpill->clobberLate(clobberSet); forceSpill->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams&) { AllowMacroScratchRegisterUsage allowScratch(jit); clobberSet.forEach([&] (Reg reg) { jit.move(CCallHelpers::TrustedImm64(0xffffffffffffffff), reg.gpr()); }); }); Value* phi = tail->appendNew<Value>(proc, Phi, Int64, Origin()); thenResult->setPhi(phi); elseResult->setPhi(phi); tail->appendNew<ControlValue>(proc, Return, Origin(), phi); auto code = compile(proc); CHECK(invoke<uint64_t>(*code, 1, 0xffffffff00000000) == 0); CHECK(invoke<uint64_t>(*code, 0, 0xffffffff00000000) == 0xffffffff00000000); // A second time since the previous run is still on the stack. CHECK(invoke<uint64_t>(*code, 1, 0xffffffff00000000) == 0); } void testLateRegister() { Procedure proc; BasicBlock* root = proc.addBlock(); // This works by making all but 1 register be input to the first patchpoint as LateRegister. // The other 1 register is just a regular Register input. We assert our result is the regular // register input. There would be no other way for the register allocator to arrange things // because LateRegister interferes with the result. // Then, the second patchpoint takes the result of the first as an argument and asks for // it in a register that was a LateRegister. This is to incentivize the register allocator // to use that LateRegister as the result for the first patchpoint. But of course it can not do that. // So it must issue a mov after the first patchpoint from the first's result into the second's input. RegisterSet regs = RegisterSet::allGPRs(); regs.exclude(RegisterSet::stackRegisters()); regs.exclude(RegisterSet::reservedHardwareRegisters()); Vector<Value*> lateUseArgs; unsigned result = 0; for (GPRReg reg = CCallHelpers::firstRegister(); reg <= CCallHelpers::lastRegister(); reg = CCallHelpers::nextRegister(reg)) { if (!regs.get(reg)) continue; result++; if (reg == GPRInfo::regT0) continue; Value* value = root->appendNew<Const64Value>(proc, Origin(), 1); lateUseArgs.append(value); } Value* regularUse = root->appendNew<Const64Value>(proc, Origin(), 1); PatchpointValue* firstPatchpoint = root->appendNew<PatchpointValue>(proc, Int64, Origin()); { unsigned i = 0; for (GPRReg reg = CCallHelpers::firstRegister(); reg <= CCallHelpers::lastRegister(); reg = CCallHelpers::nextRegister(reg)) { if (!regs.get(reg)) continue; if (reg == GPRInfo::regT0) continue; Value* value = lateUseArgs[i++]; firstPatchpoint->append(value, ValueRep::lateReg(reg)); } firstPatchpoint->append(regularUse, ValueRep::reg(GPRInfo::regT0)); } firstPatchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params[0].gpr() == GPRInfo::regT0); // Note that regT0 should also start off as 1, so we're implicitly starting our add with 1, which is also an argument. unsigned skipped = 0; for (unsigned i = 1; i < params.size(); i++) { if (params[i].gpr() == params[0].gpr()) { skipped = i; continue; } jit.add64(params[i].gpr(), params[0].gpr()); } CHECK(!!skipped); }); PatchpointValue* secondPatchpoint = root->appendNew<PatchpointValue>(proc, Int64, Origin()); secondPatchpoint->append(firstPatchpoint, ValueRep::reg(GPRInfo::regT1)); secondPatchpoint->setGenerator( [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { AllowMacroScratchRegisterUsage allowScratch(jit); CHECK(params[1].gpr() == GPRInfo::regT1); jit.nop(); jit.nop(); jit.move(params[1].gpr(), params[0].gpr()); jit.nop(); jit.nop(); }); root->appendNew<ControlValue>(proc, Return, Origin(), secondPatchpoint); auto code = compile(proc); CHECK(invoke<uint64_t>(*code) == result); } // Make sure the compiler does not try to optimize anything out. NEVER_INLINE double zero() { return 0.; } double negativeZero() { return -zero(); } #define RUN(test) do { \ if (!shouldRun(#test)) \ break; \ tasks.append( \ createSharedTask<void()>( \ [&] () { \ dataLog(#test "...\n"); \ test; \ dataLog(#test ": OK!\n"); \ })); \ } while (false); #define RUN_UNARY(test, values) \ for (auto a : values) { \ CString testStr = toCString(#test, "(", a.name, ")"); \ if (!shouldRun(testStr.data())) \ continue; \ tasks.append(createSharedTask<void()>( \ [=] () { \ dataLog(toCString(testStr, "...\n")); \ test(a.value); \ dataLog(toCString(testStr, ": OK!\n")); \ })); \ } #define RUN_BINARY(test, valuesA, valuesB) \ for (auto a : valuesA) { \ for (auto b : valuesB) { \ CString testStr = toCString(#test, "(", a.name, ", ", b.name, ")"); \ if (!shouldRun(testStr.data())) \ continue; \ tasks.append(createSharedTask<void()>( \ [=] () { \ dataLog(toCString(testStr, "...\n")); \ test(a.value, b.value); \ dataLog(toCString(testStr, ": OK!\n")); \ })); \ } \ } void run(const char* filter) { JSC::initializeThreading(); vm = &VM::create(LargeHeap).leakRef(); Deque<RefPtr<SharedTask<void()>>> tasks; auto shouldRun = [&] (const char* testName) -> bool { return !filter || !!strcasestr(testName, filter); }; RUN(test42()); RUN(testLoad42()); RUN(testLoadOffsetImm9Max()); RUN(testLoadOffsetImm9MaxPlusOne()); RUN(testLoadOffsetImm9MaxPlusTwo()); RUN(testLoadOffsetImm9Min()); RUN(testLoadOffsetImm9MinMinusOne()); RUN(testLoadOffsetScaledUnsignedImm12Max()); RUN(testLoadOffsetScaledUnsignedOverImm12Max()); RUN(testArg(43)); RUN(testReturnConst64(5)); RUN(testReturnConst64(-42)); RUN(testAddArg(111)); RUN(testAddArgs(1, 1)); RUN(testAddArgs(1, 2)); RUN(testAddArgImm(1, 2)); RUN(testAddArgImm(0, 2)); RUN(testAddArgImm(1, 0)); RUN(testAddImmArg(1, 2)); RUN(testAddImmArg(0, 2)); RUN(testAddImmArg(1, 0)); RUN_BINARY(testAddArgMem, int64Operands(), int64Operands()); RUN_BINARY(testAddMemArg, int64Operands(), int64Operands()); RUN_BINARY(testAddImmMem, int64Operands(), int64Operands()); RUN_UNARY(testAddArg32, int32Operands()); RUN(testAddArgs32(1, 1)); RUN(testAddArgs32(1, 2)); RUN_BINARY(testAddArgMem32, int32Operands(), int32Operands()); RUN_BINARY(testAddMemArg32, int32Operands(), int32Operands()); RUN_BINARY(testAddImmMem32, int32Operands(), int32Operands()); RUN(testAddArgZeroImmZDef()); RUN(testAddLoadTwice()); RUN(testAddArgDouble(M_PI)); RUN(testAddArgsDouble(M_PI, 1)); RUN(testAddArgsDouble(M_PI, -M_PI)); RUN(testAddArgImmDouble(M_PI, 1)); RUN(testAddArgImmDouble(M_PI, 0)); RUN(testAddArgImmDouble(M_PI, negativeZero())); RUN(testAddArgImmDouble(0, 0)); RUN(testAddArgImmDouble(0, negativeZero())); RUN(testAddArgImmDouble(negativeZero(), 0)); RUN(testAddArgImmDouble(negativeZero(), negativeZero())); RUN(testAddImmArgDouble(M_PI, 1)); RUN(testAddImmArgDouble(M_PI, 0)); RUN(testAddImmArgDouble(M_PI, negativeZero())); RUN(testAddImmArgDouble(0, 0)); RUN(testAddImmArgDouble(0, negativeZero())); RUN(testAddImmArgDouble(negativeZero(), 0)); RUN(testAddImmArgDouble(negativeZero(), negativeZero())); RUN(testAddImmsDouble(M_PI, 1)); RUN(testAddImmsDouble(M_PI, 0)); RUN(testAddImmsDouble(M_PI, negativeZero())); RUN(testAddImmsDouble(0, 0)); RUN(testAddImmsDouble(0, negativeZero())); RUN(testAddImmsDouble(negativeZero(), negativeZero())); RUN_UNARY(testAddArgFloat, floatingPointOperands<float>()); RUN_BINARY(testAddArgsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testAddArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testAddImmArgFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testAddImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_UNARY(testAddArgFloatWithUselessDoubleConversion, floatingPointOperands<float>()); RUN_BINARY(testAddArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testAddArgsFloatWithEffectfulDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testMulArg(5)); RUN(testMulAddArg(5)); RUN(testMulAddArg(85)); RUN(testMulArgStore(5)); RUN(testMulArgStore(85)); RUN(testMulArgs(1, 1)); RUN(testMulArgs(1, 2)); RUN(testMulArgs(3, 3)); RUN(testMulArgImm(1, 2)); RUN(testMulArgImm(1, 4)); RUN(testMulArgImm(1, 8)); RUN(testMulArgImm(1, 16)); RUN(testMulArgImm(1, 0x80000000llu)); RUN(testMulArgImm(1, 0x800000000000llu)); RUN(testMulArgImm(7, 2)); RUN(testMulArgImm(7, 4)); RUN(testMulArgImm(7, 8)); RUN(testMulArgImm(7, 16)); RUN(testMulArgImm(7, 0x80000000llu)); RUN(testMulArgImm(7, 0x800000000000llu)); RUN(testMulArgImm(-42, 2)); RUN(testMulArgImm(-42, 4)); RUN(testMulArgImm(-42, 8)); RUN(testMulArgImm(-42, 16)); RUN(testMulArgImm(-42, 0x80000000llu)); RUN(testMulArgImm(-42, 0x800000000000llu)); RUN(testMulArgImm(0, 2)); RUN(testMulArgImm(1, 0)); RUN(testMulArgImm(3, 3)); RUN(testMulArgImm(3, -1)); RUN(testMulArgImm(-3, -1)); RUN(testMulArgImm(0, -1)); RUN(testMulImmArg(1, 2)); RUN(testMulImmArg(0, 2)); RUN(testMulImmArg(1, 0)); RUN(testMulImmArg(3, 3)); RUN(testMulArgs32(1, 1)); RUN(testMulArgs32(1, 2)); RUN(testMulLoadTwice()); RUN(testMulAddArgsLeft()); RUN(testMulAddArgsRight()); RUN(testMulAddArgsLeft32()); RUN(testMulAddArgsRight32()); RUN(testMulSubArgsLeft()); RUN(testMulSubArgsRight()); RUN(testMulSubArgsLeft32()); RUN(testMulSubArgsRight32()); RUN(testMulNegArgs()); RUN(testMulNegArgs32()); RUN_UNARY(testMulArgDouble, floatingPointOperands<double>()); RUN_BINARY(testMulArgsDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testMulArgImmDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testMulImmArgDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testMulImmsDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_UNARY(testMulArgFloat, floatingPointOperands<float>()); RUN_BINARY(testMulArgsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testMulArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testMulImmArgFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testMulImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_UNARY(testMulArgFloatWithUselessDoubleConversion, floatingPointOperands<float>()); RUN_BINARY(testMulArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testMulArgsFloatWithEffectfulDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testDivArgDouble(M_PI)); RUN(testDivArgsDouble(M_PI, 1)); RUN(testDivArgsDouble(M_PI, -M_PI)); RUN(testDivArgImmDouble(M_PI, 1)); RUN(testDivArgImmDouble(M_PI, 0)); RUN(testDivArgImmDouble(M_PI, negativeZero())); RUN(testDivArgImmDouble(0, 0)); RUN(testDivArgImmDouble(0, negativeZero())); RUN(testDivArgImmDouble(negativeZero(), 0)); RUN(testDivArgImmDouble(negativeZero(), negativeZero())); RUN(testDivImmArgDouble(M_PI, 1)); RUN(testDivImmArgDouble(M_PI, 0)); RUN(testDivImmArgDouble(M_PI, negativeZero())); RUN(testDivImmArgDouble(0, 0)); RUN(testDivImmArgDouble(0, negativeZero())); RUN(testDivImmArgDouble(negativeZero(), 0)); RUN(testDivImmArgDouble(negativeZero(), negativeZero())); RUN(testDivImmsDouble(M_PI, 1)); RUN(testDivImmsDouble(M_PI, 0)); RUN(testDivImmsDouble(M_PI, negativeZero())); RUN(testDivImmsDouble(0, 0)); RUN(testDivImmsDouble(0, negativeZero())); RUN(testDivImmsDouble(negativeZero(), negativeZero())); RUN_UNARY(testDivArgFloat, floatingPointOperands<float>()); RUN_BINARY(testDivArgsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testDivArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testDivImmArgFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testDivImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_UNARY(testDivArgFloatWithUselessDoubleConversion, floatingPointOperands<float>()); RUN_BINARY(testDivArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testDivArgsFloatWithEffectfulDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_UNARY(testModArgDouble, floatingPointOperands<double>()); RUN_BINARY(testModArgsDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testModArgImmDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testModImmArgDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testModImmsDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_UNARY(testModArgFloat, floatingPointOperands<float>()); RUN_BINARY(testModArgsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testModArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testModImmArgFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testModImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testSubArg(24)); RUN(testSubArgs(1, 1)); RUN(testSubArgs(1, 2)); RUN(testSubArgs(13, -42)); RUN(testSubArgs(-13, 42)); RUN(testSubArgImm(1, 1)); RUN(testSubArgImm(1, 2)); RUN(testSubArgImm(13, -42)); RUN(testSubArgImm(-13, 42)); RUN(testSubArgImm(42, 0)); RUN(testSubImmArg(1, 1)); RUN(testSubImmArg(1, 2)); RUN(testSubImmArg(13, -42)); RUN(testSubImmArg(-13, 42)); RUN_BINARY(testSubArgMem, int64Operands(), int64Operands()); RUN_BINARY(testSubMemArg, int64Operands(), int64Operands()); RUN_BINARY(testSubImmMem, int32Operands(), int32Operands()); RUN_BINARY(testSubMemImm, int32Operands(), int32Operands()); RUN_UNARY(testNegValueSubOne, int32Operands()); RUN(testSubArgs32(1, 1)); RUN(testSubArgs32(1, 2)); RUN(testSubArgs32(13, -42)); RUN(testSubArgs32(-13, 42)); RUN(testSubArgImm32(1, 1)); RUN(testSubArgImm32(1, 2)); RUN(testSubArgImm32(13, -42)); RUN(testSubArgImm32(-13, 42)); RUN(testSubImmArg32(1, 1)); RUN(testSubImmArg32(1, 2)); RUN(testSubImmArg32(13, -42)); RUN(testSubImmArg32(-13, 42)); RUN_BINARY(testSubArgMem32, int32Operands(), int32Operands()); RUN_BINARY(testSubMemArg32, int32Operands(), int32Operands()); RUN_BINARY(testSubImmMem32, int32Operands(), int32Operands()); RUN_BINARY(testSubMemImm32, int32Operands(), int32Operands()); RUN_UNARY(testNegValueSubOne32, int64Operands()); RUN_UNARY(testSubArgDouble, floatingPointOperands<double>()); RUN_BINARY(testSubArgsDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testSubArgImmDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testSubImmArgDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testSubImmsDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_UNARY(testSubArgFloat, floatingPointOperands<float>()); RUN_BINARY(testSubArgsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testSubArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testSubImmArgFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testSubImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_UNARY(testSubArgFloatWithUselessDoubleConversion, floatingPointOperands<float>()); RUN_BINARY(testSubArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testSubArgsFloatWithEffectfulDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testBitAndArgs(43, 43)); RUN(testBitAndArgs(43, 0)); RUN(testBitAndArgs(10, 3)); RUN(testBitAndArgs(42, 0xffffffffffffffff)); RUN(testBitAndSameArg(43)); RUN(testBitAndSameArg(0)); RUN(testBitAndSameArg(3)); RUN(testBitAndSameArg(0xffffffffffffffff)); RUN(testBitAndImms(43, 43)); RUN(testBitAndImms(43, 0)); RUN(testBitAndImms(10, 3)); RUN(testBitAndImms(42, 0xffffffffffffffff)); RUN(testBitAndArgImm(43, 43)); RUN(testBitAndArgImm(43, 0)); RUN(testBitAndArgImm(10, 3)); RUN(testBitAndArgImm(42, 0xffffffffffffffff)); RUN(testBitAndArgImm(42, 0xff)); RUN(testBitAndArgImm(300, 0xff)); RUN(testBitAndArgImm(-300, 0xff)); RUN(testBitAndArgImm(42, 0xffff)); RUN(testBitAndArgImm(40000, 0xffff)); RUN(testBitAndArgImm(-40000, 0xffff)); RUN(testBitAndImmArg(43, 43)); RUN(testBitAndImmArg(43, 0)); RUN(testBitAndImmArg(10, 3)); RUN(testBitAndImmArg(42, 0xffffffffffffffff)); RUN(testBitAndBitAndArgImmImm(2, 7, 3)); RUN(testBitAndBitAndArgImmImm(1, 6, 6)); RUN(testBitAndBitAndArgImmImm(0xffff, 24, 7)); RUN(testBitAndImmBitAndArgImm(7, 2, 3)); RUN(testBitAndImmBitAndArgImm(6, 1, 6)); RUN(testBitAndImmBitAndArgImm(24, 0xffff, 7)); RUN(testBitAndArgs32(43, 43)); RUN(testBitAndArgs32(43, 0)); RUN(testBitAndArgs32(10, 3)); RUN(testBitAndArgs32(42, 0xffffffff)); RUN(testBitAndSameArg32(43)); RUN(testBitAndSameArg32(0)); RUN(testBitAndSameArg32(3)); RUN(testBitAndSameArg32(0xffffffff)); RUN(testBitAndImms32(43, 43)); RUN(testBitAndImms32(43, 0)); RUN(testBitAndImms32(10, 3)); RUN(testBitAndImms32(42, 0xffffffff)); RUN(testBitAndArgImm32(43, 43)); RUN(testBitAndArgImm32(43, 0)); RUN(testBitAndArgImm32(10, 3)); RUN(testBitAndArgImm32(42, 0xffffffff)); RUN(testBitAndImmArg32(43, 43)); RUN(testBitAndImmArg32(43, 0)); RUN(testBitAndImmArg32(10, 3)); RUN(testBitAndImmArg32(42, 0xffffffff)); RUN(testBitAndImmArg32(42, 0xff)); RUN(testBitAndImmArg32(300, 0xff)); RUN(testBitAndImmArg32(-300, 0xff)); RUN(testBitAndImmArg32(42, 0xffff)); RUN(testBitAndImmArg32(40000, 0xffff)); RUN(testBitAndImmArg32(-40000, 0xffff)); RUN(testBitAndBitAndArgImmImm32(2, 7, 3)); RUN(testBitAndBitAndArgImmImm32(1, 6, 6)); RUN(testBitAndBitAndArgImmImm32(0xffff, 24, 7)); RUN(testBitAndImmBitAndArgImm32(7, 2, 3)); RUN(testBitAndImmBitAndArgImm32(6, 1, 6)); RUN(testBitAndImmBitAndArgImm32(24, 0xffff, 7)); RUN_BINARY(testBitAndWithMaskReturnsBooleans, int64Operands(), int64Operands()); RUN_UNARY(testBitAndArgDouble, floatingPointOperands<double>()); RUN_BINARY(testBitAndArgsDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testBitAndArgImmDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testBitAndImmsDouble, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_UNARY(testBitAndArgFloat, floatingPointOperands<float>()); RUN_BINARY(testBitAndArgsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testBitAndArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testBitAndImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testBitAndArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testBitOrArgs(43, 43)); RUN(testBitOrArgs(43, 0)); RUN(testBitOrArgs(10, 3)); RUN(testBitOrArgs(42, 0xffffffffffffffff)); RUN(testBitOrSameArg(43)); RUN(testBitOrSameArg(0)); RUN(testBitOrSameArg(3)); RUN(testBitOrSameArg(0xffffffffffffffff)); RUN(testBitOrImms(43, 43)); RUN(testBitOrImms(43, 0)); RUN(testBitOrImms(10, 3)); RUN(testBitOrImms(42, 0xffffffffffffffff)); RUN(testBitOrArgImm(43, 43)); RUN(testBitOrArgImm(43, 0)); RUN(testBitOrArgImm(10, 3)); RUN(testBitOrArgImm(42, 0xffffffffffffffff)); RUN(testBitOrImmArg(43, 43)); RUN(testBitOrImmArg(43, 0)); RUN(testBitOrImmArg(10, 3)); RUN(testBitOrImmArg(42, 0xffffffffffffffff)); RUN(testBitOrBitOrArgImmImm(2, 7, 3)); RUN(testBitOrBitOrArgImmImm(1, 6, 6)); RUN(testBitOrBitOrArgImmImm(0xffff, 24, 7)); RUN(testBitOrImmBitOrArgImm(7, 2, 3)); RUN(testBitOrImmBitOrArgImm(6, 1, 6)); RUN(testBitOrImmBitOrArgImm(24, 0xffff, 7)); RUN(testBitOrArgs32(43, 43)); RUN(testBitOrArgs32(43, 0)); RUN(testBitOrArgs32(10, 3)); RUN(testBitOrArgs32(42, 0xffffffff)); RUN(testBitOrSameArg32(43)); RUN(testBitOrSameArg32(0)); RUN(testBitOrSameArg32(3)); RUN(testBitOrSameArg32(0xffffffff)); RUN(testBitOrImms32(43, 43)); RUN(testBitOrImms32(43, 0)); RUN(testBitOrImms32(10, 3)); RUN(testBitOrImms32(42, 0xffffffff)); RUN(testBitOrArgImm32(43, 43)); RUN(testBitOrArgImm32(43, 0)); RUN(testBitOrArgImm32(10, 3)); RUN(testBitOrArgImm32(42, 0xffffffff)); RUN(testBitOrImmArg32(43, 43)); RUN(testBitOrImmArg32(43, 0)); RUN(testBitOrImmArg32(10, 3)); RUN(testBitOrImmArg32(42, 0xffffffff)); RUN(testBitOrBitOrArgImmImm32(2, 7, 3)); RUN(testBitOrBitOrArgImmImm32(1, 6, 6)); RUN(testBitOrBitOrArgImmImm32(0xffff, 24, 7)); RUN(testBitOrImmBitOrArgImm32(7, 2, 3)); RUN(testBitOrImmBitOrArgImm32(6, 1, 6)); RUN(testBitOrImmBitOrArgImm32(24, 0xffff, 7)); RUN_BINARY(testBitXorArgs, int64Operands(), int64Operands()); RUN_UNARY(testBitXorSameArg, int64Operands()); RUN_BINARY(testBitXorImms, int64Operands(), int64Operands()); RUN_BINARY(testBitXorArgImm, int64Operands(), int64Operands()); RUN_BINARY(testBitXorImmArg, int64Operands(), int64Operands()); RUN(testBitXorBitXorArgImmImm(2, 7, 3)); RUN(testBitXorBitXorArgImmImm(1, 6, 6)); RUN(testBitXorBitXorArgImmImm(0xffff, 24, 7)); RUN(testBitXorImmBitXorArgImm(7, 2, 3)); RUN(testBitXorImmBitXorArgImm(6, 1, 6)); RUN(testBitXorImmBitXorArgImm(24, 0xffff, 7)); RUN(testBitXorArgs32(43, 43)); RUN(testBitXorArgs32(43, 0)); RUN(testBitXorArgs32(10, 3)); RUN(testBitXorArgs32(42, 0xffffffff)); RUN(testBitXorSameArg32(43)); RUN(testBitXorSameArg32(0)); RUN(testBitXorSameArg32(3)); RUN(testBitXorSameArg32(0xffffffff)); RUN(testBitXorImms32(43, 43)); RUN(testBitXorImms32(43, 0)); RUN(testBitXorImms32(10, 3)); RUN(testBitXorImms32(42, 0xffffffff)); RUN(testBitXorArgImm32(43, 43)); RUN(testBitXorArgImm32(43, 0)); RUN(testBitXorArgImm32(10, 3)); RUN(testBitXorArgImm32(42, 0xffffffff)); RUN(testBitXorImmArg32(43, 43)); RUN(testBitXorImmArg32(43, 0)); RUN(testBitXorImmArg32(10, 3)); RUN(testBitXorImmArg32(42, 0xffffffff)); RUN(testBitXorBitXorArgImmImm32(2, 7, 3)); RUN(testBitXorBitXorArgImmImm32(1, 6, 6)); RUN(testBitXorBitXorArgImmImm32(0xffff, 24, 7)); RUN(testBitXorImmBitXorArgImm32(7, 2, 3)); RUN(testBitXorImmBitXorArgImm32(6, 1, 6)); RUN(testBitXorImmBitXorArgImm32(24, 0xffff, 7)); RUN_UNARY(testBitNotArg, int64Operands()); RUN_UNARY(testBitNotImm, int64Operands()); RUN_UNARY(testBitNotMem, int64Operands()); RUN_UNARY(testBitNotArg32, int32Operands()); RUN_UNARY(testBitNotImm32, int32Operands()); RUN_UNARY(testBitNotMem32, int32Operands()); RUN_BINARY(testBitNotOnBooleanAndBranch32, int32Operands(), int32Operands()); RUN(testShlArgs(1, 0)); RUN(testShlArgs(1, 1)); RUN(testShlArgs(1, 62)); RUN(testShlArgs(0xffffffffffffffff, 0)); RUN(testShlArgs(0xffffffffffffffff, 1)); RUN(testShlArgs(0xffffffffffffffff, 63)); RUN(testShlImms(1, 0)); RUN(testShlImms(1, 1)); RUN(testShlImms(1, 62)); RUN(testShlImms(1, 65)); RUN(testShlImms(0xffffffffffffffff, 0)); RUN(testShlImms(0xffffffffffffffff, 1)); RUN(testShlImms(0xffffffffffffffff, 63)); RUN(testShlArgImm(1, 0)); RUN(testShlArgImm(1, 1)); RUN(testShlArgImm(1, 62)); RUN(testShlArgImm(1, 65)); RUN(testShlArgImm(0xffffffffffffffff, 0)); RUN(testShlArgImm(0xffffffffffffffff, 1)); RUN(testShlArgImm(0xffffffffffffffff, 63)); RUN(testShlArg32(2)); RUN(testShlArgs32(1, 0)); RUN(testShlArgs32(1, 1)); RUN(testShlArgs32(1, 62)); RUN(testShlImms32(1, 33)); RUN(testShlArgs32(0xffffffff, 0)); RUN(testShlArgs32(0xffffffff, 1)); RUN(testShlArgs32(0xffffffff, 63)); RUN(testShlImms32(1, 0)); RUN(testShlImms32(1, 1)); RUN(testShlImms32(1, 62)); RUN(testShlImms32(1, 33)); RUN(testShlImms32(0xffffffff, 0)); RUN(testShlImms32(0xffffffff, 1)); RUN(testShlImms32(0xffffffff, 63)); RUN(testShlArgImm32(1, 0)); RUN(testShlArgImm32(1, 1)); RUN(testShlArgImm32(1, 62)); RUN(testShlArgImm32(0xffffffff, 0)); RUN(testShlArgImm32(0xffffffff, 1)); RUN(testShlArgImm32(0xffffffff, 63)); RUN(testSShrArgs(1, 0)); RUN(testSShrArgs(1, 1)); RUN(testSShrArgs(1, 62)); RUN(testSShrArgs(0xffffffffffffffff, 0)); RUN(testSShrArgs(0xffffffffffffffff, 1)); RUN(testSShrArgs(0xffffffffffffffff, 63)); RUN(testSShrImms(1, 0)); RUN(testSShrImms(1, 1)); RUN(testSShrImms(1, 62)); RUN(testSShrImms(1, 65)); RUN(testSShrImms(0xffffffffffffffff, 0)); RUN(testSShrImms(0xffffffffffffffff, 1)); RUN(testSShrImms(0xffffffffffffffff, 63)); RUN(testSShrArgImm(1, 0)); RUN(testSShrArgImm(1, 1)); RUN(testSShrArgImm(1, 62)); RUN(testSShrArgImm(1, 65)); RUN(testSShrArgImm(0xffffffffffffffff, 0)); RUN(testSShrArgImm(0xffffffffffffffff, 1)); RUN(testSShrArgImm(0xffffffffffffffff, 63)); RUN(testSShrArg32(32)); RUN(testSShrArgs32(1, 0)); RUN(testSShrArgs32(1, 1)); RUN(testSShrArgs32(1, 62)); RUN(testSShrArgs32(1, 33)); RUN(testSShrArgs32(0xffffffff, 0)); RUN(testSShrArgs32(0xffffffff, 1)); RUN(testSShrArgs32(0xffffffff, 63)); RUN(testSShrImms32(1, 0)); RUN(testSShrImms32(1, 1)); RUN(testSShrImms32(1, 62)); RUN(testSShrImms32(1, 33)); RUN(testSShrImms32(0xffffffff, 0)); RUN(testSShrImms32(0xffffffff, 1)); RUN(testSShrImms32(0xffffffff, 63)); RUN(testSShrArgImm32(1, 0)); RUN(testSShrArgImm32(1, 1)); RUN(testSShrArgImm32(1, 62)); RUN(testSShrArgImm32(0xffffffff, 0)); RUN(testSShrArgImm32(0xffffffff, 1)); RUN(testSShrArgImm32(0xffffffff, 63)); RUN(testZShrArgs(1, 0)); RUN(testZShrArgs(1, 1)); RUN(testZShrArgs(1, 62)); RUN(testZShrArgs(0xffffffffffffffff, 0)); RUN(testZShrArgs(0xffffffffffffffff, 1)); RUN(testZShrArgs(0xffffffffffffffff, 63)); RUN(testZShrImms(1, 0)); RUN(testZShrImms(1, 1)); RUN(testZShrImms(1, 62)); RUN(testZShrImms(1, 65)); RUN(testZShrImms(0xffffffffffffffff, 0)); RUN(testZShrImms(0xffffffffffffffff, 1)); RUN(testZShrImms(0xffffffffffffffff, 63)); RUN(testZShrArgImm(1, 0)); RUN(testZShrArgImm(1, 1)); RUN(testZShrArgImm(1, 62)); RUN(testZShrArgImm(1, 65)); RUN(testZShrArgImm(0xffffffffffffffff, 0)); RUN(testZShrArgImm(0xffffffffffffffff, 1)); RUN(testZShrArgImm(0xffffffffffffffff, 63)); RUN(testZShrArg32(32)); RUN(testZShrArgs32(1, 0)); RUN(testZShrArgs32(1, 1)); RUN(testZShrArgs32(1, 62)); RUN(testZShrArgs32(1, 33)); RUN(testZShrArgs32(0xffffffff, 0)); RUN(testZShrArgs32(0xffffffff, 1)); RUN(testZShrArgs32(0xffffffff, 63)); RUN(testZShrImms32(1, 0)); RUN(testZShrImms32(1, 1)); RUN(testZShrImms32(1, 62)); RUN(testZShrImms32(1, 33)); RUN(testZShrImms32(0xffffffff, 0)); RUN(testZShrImms32(0xffffffff, 1)); RUN(testZShrImms32(0xffffffff, 63)); RUN(testZShrArgImm32(1, 0)); RUN(testZShrArgImm32(1, 1)); RUN(testZShrArgImm32(1, 62)); RUN(testZShrArgImm32(0xffffffff, 0)); RUN(testZShrArgImm32(0xffffffff, 1)); RUN(testZShrArgImm32(0xffffffff, 63)); RUN_UNARY(testClzArg64, int64Operands()); RUN_UNARY(testClzMem64, int64Operands()); RUN_UNARY(testClzArg32, int32Operands()); RUN_UNARY(testClzMem32, int64Operands()); RUN_UNARY(testAbsArg, floatingPointOperands<double>()); RUN_UNARY(testAbsImm, floatingPointOperands<double>()); RUN_UNARY(testAbsMem, floatingPointOperands<double>()); RUN_UNARY(testAbsAbsArg, floatingPointOperands<double>()); RUN_UNARY(testAbsBitwiseCastArg, floatingPointOperands<double>()); RUN_UNARY(testBitwiseCastAbsBitwiseCastArg, floatingPointOperands<double>()); RUN_UNARY(testAbsArg, floatingPointOperands<float>()); RUN_UNARY(testAbsImm, floatingPointOperands<float>()); RUN_UNARY(testAbsMem, floatingPointOperands<float>()); RUN_UNARY(testAbsAbsArg, floatingPointOperands<float>()); RUN_UNARY(testAbsBitwiseCastArg, floatingPointOperands<float>()); RUN_UNARY(testBitwiseCastAbsBitwiseCastArg, floatingPointOperands<float>()); RUN_UNARY(testAbsArgWithUselessDoubleConversion, floatingPointOperands<float>()); RUN_UNARY(testAbsArgWithEffectfulDoubleConversion, floatingPointOperands<float>()); RUN_UNARY(testCeilArg, floatingPointOperands<double>()); RUN_UNARY(testCeilImm, floatingPointOperands<double>()); RUN_UNARY(testCeilMem, floatingPointOperands<double>()); RUN_UNARY(testCeilCeilArg, floatingPointOperands<double>()); RUN_UNARY(testFloorCeilArg, floatingPointOperands<double>()); RUN_UNARY(testCeilIToD64, int64Operands()); RUN_UNARY(testCeilIToD32, int32Operands()); RUN_UNARY(testCeilArg, floatingPointOperands<float>()); RUN_UNARY(testCeilImm, floatingPointOperands<float>()); RUN_UNARY(testCeilMem, floatingPointOperands<float>()); RUN_UNARY(testCeilCeilArg, floatingPointOperands<float>()); RUN_UNARY(testFloorCeilArg, floatingPointOperands<float>()); RUN_UNARY(testCeilArgWithUselessDoubleConversion, floatingPointOperands<float>()); RUN_UNARY(testCeilArgWithEffectfulDoubleConversion, floatingPointOperands<float>()); RUN_UNARY(testFloorArg, floatingPointOperands<double>()); RUN_UNARY(testFloorImm, floatingPointOperands<double>()); RUN_UNARY(testFloorMem, floatingPointOperands<double>()); RUN_UNARY(testFloorFloorArg, floatingPointOperands<double>()); RUN_UNARY(testCeilFloorArg, floatingPointOperands<double>()); RUN_UNARY(testFloorIToD64, int64Operands()); RUN_UNARY(testFloorIToD32, int32Operands()); RUN_UNARY(testFloorArg, floatingPointOperands<float>()); RUN_UNARY(testFloorImm, floatingPointOperands<float>()); RUN_UNARY(testFloorMem, floatingPointOperands<float>()); RUN_UNARY(testFloorFloorArg, floatingPointOperands<float>()); RUN_UNARY(testCeilFloorArg, floatingPointOperands<float>()); RUN_UNARY(testFloorArgWithUselessDoubleConversion, floatingPointOperands<float>()); RUN_UNARY(testFloorArgWithEffectfulDoubleConversion, floatingPointOperands<float>()); RUN_UNARY(testSqrtArg, floatingPointOperands<double>()); RUN_UNARY(testSqrtImm, floatingPointOperands<double>()); RUN_UNARY(testSqrtMem, floatingPointOperands<double>()); RUN_UNARY(testSqrtArg, floatingPointOperands<float>()); RUN_UNARY(testSqrtImm, floatingPointOperands<float>()); RUN_UNARY(testSqrtMem, floatingPointOperands<float>()); RUN_UNARY(testSqrtArgWithUselessDoubleConversion, floatingPointOperands<float>()); RUN_UNARY(testSqrtArgWithEffectfulDoubleConversion, floatingPointOperands<float>()); RUN_BINARY(testCompareTwoFloatToDouble, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testCompareOneFloatToDouble, floatingPointOperands<float>(), floatingPointOperands<double>()); RUN_BINARY(testCompareFloatToDoubleThroughPhi, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_UNARY(testDoubleToFloatThroughPhi, floatingPointOperands<float>()); RUN_UNARY(testDoubleProducerPhiToFloatConversion, floatingPointOperands<float>()); RUN_UNARY(testDoubleProducerPhiToFloatConversionWithDoubleConsumer, floatingPointOperands<float>()); RUN_BINARY(testDoubleProducerPhiWithNonFloatConst, floatingPointOperands<float>(), floatingPointOperands<double>()); RUN_UNARY(testDoubleArgToInt64BitwiseCast, floatingPointOperands<double>()); RUN_UNARY(testDoubleImmToInt64BitwiseCast, floatingPointOperands<double>()); RUN_UNARY(testTwoBitwiseCastOnDouble, floatingPointOperands<double>()); RUN_UNARY(testBitwiseCastOnDoubleInMemory, floatingPointOperands<double>()); RUN_UNARY(testBitwiseCastOnDoubleInMemoryIndexed, floatingPointOperands<double>()); RUN_UNARY(testInt64BArgToDoubleBitwiseCast, int64Operands()); RUN_UNARY(testInt64BImmToDoubleBitwiseCast, int64Operands()); RUN_UNARY(testTwoBitwiseCastOnInt64, int64Operands()); RUN_UNARY(testBitwiseCastOnInt64InMemory, int64Operands()); RUN_UNARY(testBitwiseCastOnInt64InMemoryIndexed, int64Operands()); RUN_UNARY(testFloatImmToInt32BitwiseCast, floatingPointOperands<float>()); RUN_UNARY(testBitwiseCastOnFloatInMemory, floatingPointOperands<float>()); RUN_UNARY(testInt32BArgToFloatBitwiseCast, int32Operands()); RUN_UNARY(testInt32BImmToFloatBitwiseCast, int32Operands()); RUN_UNARY(testTwoBitwiseCastOnInt32, int32Operands()); RUN_UNARY(testBitwiseCastOnInt32InMemory, int32Operands()); RUN_UNARY(testConvertDoubleToFloatArg, floatingPointOperands<double>()); RUN_UNARY(testConvertDoubleToFloatImm, floatingPointOperands<double>()); RUN_UNARY(testConvertDoubleToFloatMem, floatingPointOperands<double>()); RUN_UNARY(testConvertFloatToDoubleArg, floatingPointOperands<float>()); RUN_UNARY(testConvertFloatToDoubleImm, floatingPointOperands<float>()); RUN_UNARY(testConvertFloatToDoubleMem, floatingPointOperands<float>()); RUN_UNARY(testConvertDoubleToFloatToDoubleToFloat, floatingPointOperands<double>()); RUN_UNARY(testStoreFloat, floatingPointOperands<double>()); RUN_UNARY(testStoreDoubleConstantAsFloat, floatingPointOperands<double>()); RUN_UNARY(testLoadFloatConvertDoubleConvertFloatStoreFloat, floatingPointOperands<float>()); RUN_UNARY(testFroundArg, floatingPointOperands<double>()); RUN_UNARY(testFroundMem, floatingPointOperands<double>()); RUN(testIToD64Arg()); RUN(testIToF64Arg()); RUN(testIToD32Arg()); RUN(testIToF32Arg()); RUN(testIToD64Mem()); RUN(testIToF64Mem()); RUN(testIToD32Mem()); RUN(testIToF32Mem()); RUN_UNARY(testIToD64Imm, int64Operands()); RUN_UNARY(testIToF64Imm, int64Operands()); RUN_UNARY(testIToD32Imm, int32Operands()); RUN_UNARY(testIToF32Imm, int32Operands()); RUN(testIToDReducedToIToF64Arg()); RUN(testIToDReducedToIToF32Arg()); RUN(testStore32(44)); RUN(testStoreConstant(49)); RUN(testStoreConstantPtr(49)); RUN(testStore8Arg()); RUN(testStore8Imm()); RUN(testStorePartial8BitRegisterOnX86()); RUN(testStore16Arg()); RUN(testStore16Imm()); RUN(testTrunc((static_cast<int64_t>(1) << 40) + 42)); RUN(testAdd1(45)); RUN(testAdd1Ptr(51)); RUN(testAdd1Ptr(bitwise_cast<intptr_t>(vm))); RUN(testNeg32(52)); RUN(testNegPtr(53)); RUN(testStoreAddLoad32(46)); RUN(testStoreAddLoadImm32(46)); RUN(testStoreAddLoad64(4600)); RUN(testStoreAddLoadImm64(4600)); RUN(testStoreAddLoad8(4, Load8Z)); RUN(testStoreAddLoadImm8(4, Load8Z)); RUN(testStoreAddLoad8(4, Load8S)); RUN(testStoreAddLoadImm8(4, Load8S)); RUN(testStoreAddLoad16(6, Load16Z)); RUN(testStoreAddLoadImm16(6, Load16Z)); RUN(testStoreAddLoad16(6, Load16S)); RUN(testStoreAddLoadImm16(6, Load16S)); RUN(testStoreAddLoad32Index(46)); RUN(testStoreAddLoadImm32Index(46)); RUN(testStoreAddLoad64Index(4600)); RUN(testStoreAddLoadImm64Index(4600)); RUN(testStoreAddLoad8Index(4, Load8Z)); RUN(testStoreAddLoadImm8Index(4, Load8Z)); RUN(testStoreAddLoad8Index(4, Load8S)); RUN(testStoreAddLoadImm8Index(4, Load8S)); RUN(testStoreAddLoad16Index(6, Load16Z)); RUN(testStoreAddLoadImm16Index(6, Load16Z)); RUN(testStoreAddLoad16Index(6, Load16S)); RUN(testStoreAddLoadImm16Index(6, Load16S)); RUN(testStoreSubLoad(46)); RUN(testStoreAddLoadInterference(52)); RUN(testStoreAddAndLoad(47, 0xffff)); RUN(testStoreAddAndLoad(470000, 0xffff)); RUN(testStoreNegLoad32(54)); RUN(testStoreNegLoadPtr(55)); RUN(testAdd1Uncommuted(48)); RUN(testLoadOffset()); RUN(testLoadOffsetNotConstant()); RUN(testLoadOffsetUsingAdd()); RUN(testLoadOffsetUsingAddInterference()); RUN(testLoadOffsetUsingAddNotConstant()); RUN(testLoadAddrShift(0)); RUN(testLoadAddrShift(1)); RUN(testLoadAddrShift(2)); RUN(testLoadAddrShift(3)); RUN(testFramePointer()); RUN(testOverrideFramePointer()); RUN(testStackSlot()); RUN(testLoadFromFramePointer()); RUN(testStoreLoadStackSlot(50)); RUN(testBranch()); RUN(testBranchPtr()); RUN(testDiamond()); RUN(testBranchNotEqual()); RUN(testBranchNotEqualCommute()); RUN(testBranchNotEqualNotEqual()); RUN(testBranchEqual()); RUN(testBranchEqualEqual()); RUN(testBranchEqualCommute()); RUN(testBranchEqualEqual1()); RUN_BINARY(testBranchEqualOrUnorderedArgs, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testBranchEqualOrUnorderedArgs, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testBranchNotEqualAndOrderedArgs, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testBranchNotEqualAndOrderedArgs, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testBranchEqualOrUnorderedDoubleArgImm, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testBranchEqualOrUnorderedFloatArgImm, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testBranchEqualOrUnorderedDoubleImms, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testBranchEqualOrUnorderedFloatImms, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testBranchEqualOrUnorderedFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testBranchNotEqualAndOrderedArgs, floatingPointOperands<double>(), floatingPointOperands<double>()); RUN_BINARY(testBranchNotEqualAndOrderedArgs, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testBranchFold(42)); RUN(testBranchFold(0)); RUN(testDiamondFold(42)); RUN(testDiamondFold(0)); RUN(testBranchNotEqualFoldPtr(42)); RUN(testBranchNotEqualFoldPtr(0)); RUN(testBranchEqualFoldPtr(42)); RUN(testBranchEqualFoldPtr(0)); RUN(testBranchLoadPtr()); RUN(testBranchLoad32()); RUN(testBranchLoad8S()); RUN(testBranchLoad8Z()); RUN(testBranchLoad16S()); RUN(testBranchLoad16Z()); RUN(testComplex(64, 128)); RUN(testComplex(4, 128)); RUN(testComplex(4, 256)); RUN(testComplex(4, 384)); RUN(testSimplePatchpoint()); RUN(testSimplePatchpointWithoutOuputClobbersGPArgs()); RUN(testSimplePatchpointWithOuputClobbersGPArgs()); RUN(testSimplePatchpointWithoutOuputClobbersFPArgs()); RUN(testSimplePatchpointWithOuputClobbersFPArgs()); RUN(testPatchpointWithEarlyClobber()); RUN(testPatchpointCallArg()); RUN(testPatchpointFixedRegister()); RUN(testPatchpointAny(ValueRep::WarmAny)); RUN(testPatchpointAny(ValueRep::ColdAny)); RUN(testPatchpointGPScratch()); RUN(testPatchpointFPScratch()); RUN(testPatchpointLotsOfLateAnys()); RUN(testPatchpointAnyImm(ValueRep::WarmAny)); RUN(testPatchpointAnyImm(ValueRep::ColdAny)); RUN(testPatchpointAnyImm(ValueRep::LateColdAny)); RUN(testPatchpointManyImms()); RUN(testPatchpointWithRegisterResult()); RUN(testPatchpointWithStackArgumentResult()); RUN(testPatchpointWithAnyResult()); RUN(testSimpleCheck()); RUN(testCheckFalse()); RUN(testCheckTrue()); RUN(testCheckLessThan()); RUN(testCheckMegaCombo()); RUN(testCheckTrickyMegaCombo()); RUN(testCheckTwoMegaCombos()); RUN(testCheckTwoNonRedundantMegaCombos()); RUN(testCheckAddImm()); RUN(testCheckAddImmCommute()); RUN(testCheckAddImmSomeRegister()); RUN(testCheckAdd()); RUN(testCheckAdd64()); RUN(testCheckAddFold(100, 200)); RUN(testCheckAddFoldFail(2147483647, 100)); RUN(testCheckAddArgumentAliasing64()); RUN(testCheckAddArgumentAliasing32()); RUN(testCheckAddSelfOverflow64()); RUN(testCheckAddSelfOverflow32()); RUN(testCheckSubImm()); RUN(testCheckSubBadImm()); RUN(testCheckSub()); RUN(testCheckSub64()); RUN(testCheckSubFold(100, 200)); RUN(testCheckSubFoldFail(-2147483647, 100)); RUN(testCheckNeg()); RUN(testCheckNeg64()); RUN(testCheckMul()); RUN(testCheckMulMemory()); RUN(testCheckMul2()); RUN(testCheckMul64()); RUN(testCheckMulFold(100, 200)); RUN(testCheckMulFoldFail(2147483647, 100)); RUN(testCheckMulArgumentAliasing64()); RUN(testCheckMulArgumentAliasing32()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(Equal, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(NotEqual, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(LessThan, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(GreaterThan, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(LessEqual, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(GreaterEqual, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(Below, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(Above, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(BelowEqual, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(AboveEqual, a, b); }, int64Operands(), int64Operands()); RUN_BINARY([](int32_t a, int32_t b) { testCompare(BitAnd, a, b); }, int64Operands(), int64Operands()); RUN(testEqualDouble(42, 42, true)); RUN(testEqualDouble(0, -0, true)); RUN(testEqualDouble(42, 43, false)); RUN(testEqualDouble(PNaN, 42, false)); RUN(testEqualDouble(42, PNaN, false)); RUN(testEqualDouble(PNaN, PNaN, false)); RUN(testLoad<Int32>(60)); RUN(testLoad<Int32>(-60)); RUN(testLoad<Int32>(1000)); RUN(testLoad<Int32>(-1000)); RUN(testLoad<Int32>(1000000)); RUN(testLoad<Int32>(-1000000)); RUN(testLoad<Int32>(1000000000)); RUN(testLoad<Int32>(-1000000000)); RUN_UNARY(testLoad<Int64>, int64Operands()); RUN_UNARY(testLoad<Float>, floatingPointOperands<float>()); RUN_UNARY(testLoad<Double>, floatingPointOperands<double>()); RUN(testLoad<int8_t>(Load8S, 60)); RUN(testLoad<int8_t>(Load8S, -60)); RUN(testLoad<int8_t>(Load8S, 1000)); RUN(testLoad<int8_t>(Load8S, -1000)); RUN(testLoad<int8_t>(Load8S, 1000000)); RUN(testLoad<int8_t>(Load8S, -1000000)); RUN(testLoad<int8_t>(Load8S, 1000000000)); RUN(testLoad<int8_t>(Load8S, -1000000000)); RUN(testLoad<uint8_t>(Load8Z, 60)); RUN(testLoad<uint8_t>(Load8Z, -60)); RUN(testLoad<uint8_t>(Load8Z, 1000)); RUN(testLoad<uint8_t>(Load8Z, -1000)); RUN(testLoad<uint8_t>(Load8Z, 1000000)); RUN(testLoad<uint8_t>(Load8Z, -1000000)); RUN(testLoad<uint8_t>(Load8Z, 1000000000)); RUN(testLoad<uint8_t>(Load8Z, -1000000000)); RUN(testLoad<int16_t>(Load16S, 60)); RUN(testLoad<int16_t>(Load16S, -60)); RUN(testLoad<int16_t>(Load16S, 1000)); RUN(testLoad<int16_t>(Load16S, -1000)); RUN(testLoad<int16_t>(Load16S, 1000000)); RUN(testLoad<int16_t>(Load16S, -1000000)); RUN(testLoad<int16_t>(Load16S, 1000000000)); RUN(testLoad<int16_t>(Load16S, -1000000000)); RUN(testLoad<uint16_t>(Load16Z, 60)); RUN(testLoad<uint16_t>(Load16Z, -60)); RUN(testLoad<uint16_t>(Load16Z, 1000)); RUN(testLoad<uint16_t>(Load16Z, -1000)); RUN(testLoad<uint16_t>(Load16Z, 1000000)); RUN(testLoad<uint16_t>(Load16Z, -1000000)); RUN(testLoad<uint16_t>(Load16Z, 1000000000)); RUN(testLoad<uint16_t>(Load16Z, -1000000000)); RUN(testSpillGP()); RUN(testSpillFP()); RUN(testInt32ToDoublePartialRegisterStall()); RUN(testInt32ToDoublePartialRegisterWithoutStall()); RUN(testCallSimple(1, 2)); RUN(testCallRare(1, 2)); RUN(testCallRareLive(1, 2, 3)); RUN(testCallSimplePure(1, 2)); RUN(testCallFunctionWithHellaArguments()); RUN(testReturnDouble(0.0)); RUN(testReturnDouble(negativeZero())); RUN(testReturnDouble(42.5)); RUN_UNARY(testReturnFloat, floatingPointOperands<float>()); RUN(testCallSimpleDouble(1, 2)); RUN(testCallFunctionWithHellaDoubleArguments()); RUN_BINARY(testCallSimpleFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testCallFunctionWithHellaFloatArguments()); RUN(testChillDiv(4, 2, 2)); RUN(testChillDiv(1, 0, 0)); RUN(testChillDiv(0, 0, 0)); RUN(testChillDiv(1, -1, -1)); RUN(testChillDiv(-2147483647 - 1, 0, 0)); RUN(testChillDiv(-2147483647 - 1, 1, -2147483647 - 1)); RUN(testChillDiv(-2147483647 - 1, -1, -2147483647 - 1)); RUN(testChillDiv(-2147483647 - 1, 2, -1073741824)); RUN(testChillDiv64(4, 2, 2)); RUN(testChillDiv64(1, 0, 0)); RUN(testChillDiv64(0, 0, 0)); RUN(testChillDiv64(1, -1, -1)); RUN(testChillDiv64(-9223372036854775807ll - 1, 0, 0)); RUN(testChillDiv64(-9223372036854775807ll - 1, 1, -9223372036854775807ll - 1)); RUN(testChillDiv64(-9223372036854775807ll - 1, -1, -9223372036854775807ll - 1)); RUN(testChillDiv64(-9223372036854775807ll - 1, 2, -4611686018427387904)); RUN(testChillDivTwice(4, 2, 6, 2, 5)); RUN(testChillDivTwice(4, 0, 6, 2, 3)); RUN(testChillDivTwice(4, 2, 6, 0, 2)); RUN_UNARY(testModArg, int64Operands()); RUN_BINARY(testModArgs, int64Operands(), int64Operands()); RUN_BINARY(testModImms, int64Operands(), int64Operands()); RUN_UNARY(testModArg32, int32Operands()); RUN_BINARY(testModArgs32, int32Operands(), int32Operands()); RUN_BINARY(testModImms32, int32Operands(), int32Operands()); RUN_UNARY(testChillModArg, int64Operands()); RUN_BINARY(testChillModArgs, int64Operands(), int64Operands()); RUN_BINARY(testChillModImms, int64Operands(), int64Operands()); RUN_UNARY(testChillModArg32, int32Operands()); RUN_BINARY(testChillModArgs32, int32Operands(), int32Operands()); RUN_BINARY(testChillModImms32, int32Operands(), int32Operands()); RUN(testSwitch(0, 1)); RUN(testSwitch(1, 1)); RUN(testSwitch(2, 1)); RUN(testSwitch(2, 2)); RUN(testSwitch(10, 1)); RUN(testSwitch(10, 2)); RUN(testSwitch(100, 1)); RUN(testSwitch(100, 100)); RUN(testSwitchChillDiv(0, 1)); RUN(testSwitchChillDiv(1, 1)); RUN(testSwitchChillDiv(2, 1)); RUN(testSwitchChillDiv(2, 2)); RUN(testSwitchChillDiv(10, 1)); RUN(testSwitchChillDiv(10, 2)); RUN(testSwitchChillDiv(100, 1)); RUN(testSwitchChillDiv(100, 100)); RUN(testSwitchTargettingSameBlock()); RUN(testSwitchTargettingSameBlockFoldPathConstant()); RUN(testTrunc(0)); RUN(testTrunc(1)); RUN(testTrunc(-1)); RUN(testTrunc(1000000000000ll)); RUN(testTrunc(-1000000000000ll)); RUN(testTruncFold(0)); RUN(testTruncFold(1)); RUN(testTruncFold(-1)); RUN(testTruncFold(1000000000000ll)); RUN(testTruncFold(-1000000000000ll)); RUN(testZExt32(0)); RUN(testZExt32(1)); RUN(testZExt32(-1)); RUN(testZExt32(1000000000ll)); RUN(testZExt32(-1000000000ll)); RUN(testZExt32Fold(0)); RUN(testZExt32Fold(1)); RUN(testZExt32Fold(-1)); RUN(testZExt32Fold(1000000000ll)); RUN(testZExt32Fold(-1000000000ll)); RUN(testSExt32(0)); RUN(testSExt32(1)); RUN(testSExt32(-1)); RUN(testSExt32(1000000000ll)); RUN(testSExt32(-1000000000ll)); RUN(testSExt32Fold(0)); RUN(testSExt32Fold(1)); RUN(testSExt32Fold(-1)); RUN(testSExt32Fold(1000000000ll)); RUN(testSExt32Fold(-1000000000ll)); RUN(testTruncZExt32(0)); RUN(testTruncZExt32(1)); RUN(testTruncZExt32(-1)); RUN(testTruncZExt32(1000000000ll)); RUN(testTruncZExt32(-1000000000ll)); RUN(testTruncSExt32(0)); RUN(testTruncSExt32(1)); RUN(testTruncSExt32(-1)); RUN(testTruncSExt32(1000000000ll)); RUN(testTruncSExt32(-1000000000ll)); RUN(testSExt8(0)); RUN(testSExt8(1)); RUN(testSExt8(42)); RUN(testSExt8(-1)); RUN(testSExt8(0xff)); RUN(testSExt8(0x100)); RUN(testSExt8Fold(0)); RUN(testSExt8Fold(1)); RUN(testSExt8Fold(42)); RUN(testSExt8Fold(-1)); RUN(testSExt8Fold(0xff)); RUN(testSExt8Fold(0x100)); RUN(testSExt8SExt8(0)); RUN(testSExt8SExt8(1)); RUN(testSExt8SExt8(42)); RUN(testSExt8SExt8(-1)); RUN(testSExt8SExt8(0xff)); RUN(testSExt8SExt8(0x100)); RUN(testSExt8SExt16(0)); RUN(testSExt8SExt16(1)); RUN(testSExt8SExt16(42)); RUN(testSExt8SExt16(-1)); RUN(testSExt8SExt16(0xff)); RUN(testSExt8SExt16(0x100)); RUN(testSExt8SExt16(0xffff)); RUN(testSExt8SExt16(0x10000)); RUN(testSExt8BitAnd(0, 0)); RUN(testSExt8BitAnd(1, 0)); RUN(testSExt8BitAnd(42, 0)); RUN(testSExt8BitAnd(-1, 0)); RUN(testSExt8BitAnd(0xff, 0)); RUN(testSExt8BitAnd(0x100, 0)); RUN(testSExt8BitAnd(0xffff, 0)); RUN(testSExt8BitAnd(0x10000, 0)); RUN(testSExt8BitAnd(0, 0xf)); RUN(testSExt8BitAnd(1, 0xf)); RUN(testSExt8BitAnd(42, 0xf)); RUN(testSExt8BitAnd(-1, 0xf)); RUN(testSExt8BitAnd(0xff, 0xf)); RUN(testSExt8BitAnd(0x100, 0xf)); RUN(testSExt8BitAnd(0xffff, 0xf)); RUN(testSExt8BitAnd(0x10000, 0xf)); RUN(testSExt8BitAnd(0, 0xff)); RUN(testSExt8BitAnd(1, 0xff)); RUN(testSExt8BitAnd(42, 0xff)); RUN(testSExt8BitAnd(-1, 0xff)); RUN(testSExt8BitAnd(0xff, 0xff)); RUN(testSExt8BitAnd(0x100, 0xff)); RUN(testSExt8BitAnd(0xffff, 0xff)); RUN(testSExt8BitAnd(0x10000, 0xff)); RUN(testSExt8BitAnd(0, 0x80)); RUN(testSExt8BitAnd(1, 0x80)); RUN(testSExt8BitAnd(42, 0x80)); RUN(testSExt8BitAnd(-1, 0x80)); RUN(testSExt8BitAnd(0xff, 0x80)); RUN(testSExt8BitAnd(0x100, 0x80)); RUN(testSExt8BitAnd(0xffff, 0x80)); RUN(testSExt8BitAnd(0x10000, 0x80)); RUN(testBitAndSExt8(0, 0xf)); RUN(testBitAndSExt8(1, 0xf)); RUN(testBitAndSExt8(42, 0xf)); RUN(testBitAndSExt8(-1, 0xf)); RUN(testBitAndSExt8(0xff, 0xf)); RUN(testBitAndSExt8(0x100, 0xf)); RUN(testBitAndSExt8(0xffff, 0xf)); RUN(testBitAndSExt8(0x10000, 0xf)); RUN(testBitAndSExt8(0, 0xff)); RUN(testBitAndSExt8(1, 0xff)); RUN(testBitAndSExt8(42, 0xff)); RUN(testBitAndSExt8(-1, 0xff)); RUN(testBitAndSExt8(0xff, 0xff)); RUN(testBitAndSExt8(0x100, 0xff)); RUN(testBitAndSExt8(0xffff, 0xff)); RUN(testBitAndSExt8(0x10000, 0xff)); RUN(testBitAndSExt8(0, 0xfff)); RUN(testBitAndSExt8(1, 0xfff)); RUN(testBitAndSExt8(42, 0xfff)); RUN(testBitAndSExt8(-1, 0xfff)); RUN(testBitAndSExt8(0xff, 0xfff)); RUN(testBitAndSExt8(0x100, 0xfff)); RUN(testBitAndSExt8(0xffff, 0xfff)); RUN(testBitAndSExt8(0x10000, 0xfff)); RUN(testSExt16(0)); RUN(testSExt16(1)); RUN(testSExt16(42)); RUN(testSExt16(-1)); RUN(testSExt16(0xffff)); RUN(testSExt16(0x10000)); RUN(testSExt16Fold(0)); RUN(testSExt16Fold(1)); RUN(testSExt16Fold(42)); RUN(testSExt16Fold(-1)); RUN(testSExt16Fold(0xffff)); RUN(testSExt16Fold(0x10000)); RUN(testSExt16SExt8(0)); RUN(testSExt16SExt8(1)); RUN(testSExt16SExt8(42)); RUN(testSExt16SExt8(-1)); RUN(testSExt16SExt8(0xffff)); RUN(testSExt16SExt8(0x10000)); RUN(testSExt16SExt16(0)); RUN(testSExt16SExt16(1)); RUN(testSExt16SExt16(42)); RUN(testSExt16SExt16(-1)); RUN(testSExt16SExt16(0xffff)); RUN(testSExt16SExt16(0x10000)); RUN(testSExt16SExt16(0xffffff)); RUN(testSExt16SExt16(0x1000000)); RUN(testSExt16BitAnd(0, 0)); RUN(testSExt16BitAnd(1, 0)); RUN(testSExt16BitAnd(42, 0)); RUN(testSExt16BitAnd(-1, 0)); RUN(testSExt16BitAnd(0xffff, 0)); RUN(testSExt16BitAnd(0x10000, 0)); RUN(testSExt16BitAnd(0xffffff, 0)); RUN(testSExt16BitAnd(0x1000000, 0)); RUN(testSExt16BitAnd(0, 0xf)); RUN(testSExt16BitAnd(1, 0xf)); RUN(testSExt16BitAnd(42, 0xf)); RUN(testSExt16BitAnd(-1, 0xf)); RUN(testSExt16BitAnd(0xffff, 0xf)); RUN(testSExt16BitAnd(0x10000, 0xf)); RUN(testSExt16BitAnd(0xffffff, 0xf)); RUN(testSExt16BitAnd(0x1000000, 0xf)); RUN(testSExt16BitAnd(0, 0xffff)); RUN(testSExt16BitAnd(1, 0xffff)); RUN(testSExt16BitAnd(42, 0xffff)); RUN(testSExt16BitAnd(-1, 0xffff)); RUN(testSExt16BitAnd(0xffff, 0xffff)); RUN(testSExt16BitAnd(0x10000, 0xffff)); RUN(testSExt16BitAnd(0xffffff, 0xffff)); RUN(testSExt16BitAnd(0x1000000, 0xffff)); RUN(testSExt16BitAnd(0, 0x8000)); RUN(testSExt16BitAnd(1, 0x8000)); RUN(testSExt16BitAnd(42, 0x8000)); RUN(testSExt16BitAnd(-1, 0x8000)); RUN(testSExt16BitAnd(0xffff, 0x8000)); RUN(testSExt16BitAnd(0x10000, 0x8000)); RUN(testSExt16BitAnd(0xffffff, 0x8000)); RUN(testSExt16BitAnd(0x1000000, 0x8000)); RUN(testBitAndSExt16(0, 0xf)); RUN(testBitAndSExt16(1, 0xf)); RUN(testBitAndSExt16(42, 0xf)); RUN(testBitAndSExt16(-1, 0xf)); RUN(testBitAndSExt16(0xffff, 0xf)); RUN(testBitAndSExt16(0x10000, 0xf)); RUN(testBitAndSExt16(0xffffff, 0xf)); RUN(testBitAndSExt16(0x1000000, 0xf)); RUN(testBitAndSExt16(0, 0xffff)); RUN(testBitAndSExt16(1, 0xffff)); RUN(testBitAndSExt16(42, 0xffff)); RUN(testBitAndSExt16(-1, 0xffff)); RUN(testBitAndSExt16(0xffff, 0xffff)); RUN(testBitAndSExt16(0x10000, 0xffff)); RUN(testBitAndSExt16(0xffffff, 0xffff)); RUN(testBitAndSExt16(0x1000000, 0xffff)); RUN(testBitAndSExt16(0, 0xfffff)); RUN(testBitAndSExt16(1, 0xfffff)); RUN(testBitAndSExt16(42, 0xfffff)); RUN(testBitAndSExt16(-1, 0xfffff)); RUN(testBitAndSExt16(0xffff, 0xfffff)); RUN(testBitAndSExt16(0x10000, 0xfffff)); RUN(testBitAndSExt16(0xffffff, 0xfffff)); RUN(testBitAndSExt16(0x1000000, 0xfffff)); RUN(testSExt32BitAnd(0, 0)); RUN(testSExt32BitAnd(1, 0)); RUN(testSExt32BitAnd(42, 0)); RUN(testSExt32BitAnd(-1, 0)); RUN(testSExt32BitAnd(0x80000000, 0)); RUN(testSExt32BitAnd(0, 0xf)); RUN(testSExt32BitAnd(1, 0xf)); RUN(testSExt32BitAnd(42, 0xf)); RUN(testSExt32BitAnd(-1, 0xf)); RUN(testSExt32BitAnd(0x80000000, 0xf)); RUN(testSExt32BitAnd(0, 0x80000000)); RUN(testSExt32BitAnd(1, 0x80000000)); RUN(testSExt32BitAnd(42, 0x80000000)); RUN(testSExt32BitAnd(-1, 0x80000000)); RUN(testSExt32BitAnd(0x80000000, 0x80000000)); RUN(testBitAndSExt32(0, 0xf)); RUN(testBitAndSExt32(1, 0xf)); RUN(testBitAndSExt32(42, 0xf)); RUN(testBitAndSExt32(-1, 0xf)); RUN(testBitAndSExt32(0xffff, 0xf)); RUN(testBitAndSExt32(0x10000, 0xf)); RUN(testBitAndSExt32(0xffffff, 0xf)); RUN(testBitAndSExt32(0x1000000, 0xf)); RUN(testBitAndSExt32(0, 0xffff00000000llu)); RUN(testBitAndSExt32(1, 0xffff00000000llu)); RUN(testBitAndSExt32(42, 0xffff00000000llu)); RUN(testBitAndSExt32(-1, 0xffff00000000llu)); RUN(testBitAndSExt32(0x80000000, 0xffff00000000llu)); RUN(testBasicSelect()); RUN(testSelectTest()); RUN(testSelectCompareDouble()); RUN_BINARY(testSelectCompareFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testSelectCompareFloatToDouble, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testSelectDouble()); RUN(testSelectDoubleTest()); RUN(testSelectDoubleCompareDouble()); RUN_BINARY(testSelectDoubleCompareFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN_BINARY(testSelectFloatCompareFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); RUN(testSelectDoubleCompareDoubleWithAliasing()); RUN(testSelectFloatCompareFloatWithAliasing()); RUN(testSelectFold(42)); RUN(testSelectFold(43)); RUN(testSelectInvert()); RUN(testCheckSelect()); RUN(testCheckSelectCheckSelect()); RUN_BINARY(testPowDoubleByIntegerLoop, floatingPointOperands<double>(), int64Operands()); RUN(testTruncOrHigh()); RUN(testTruncOrLow()); RUN(testBitAndOrHigh()); RUN(testBitAndOrLow()); RUN(testBranch64Equal(0, 0)); RUN(testBranch64Equal(1, 1)); RUN(testBranch64Equal(-1, -1)); RUN(testBranch64Equal(1, -1)); RUN(testBranch64Equal(-1, 1)); RUN(testBranch64EqualImm(0, 0)); RUN(testBranch64EqualImm(1, 1)); RUN(testBranch64EqualImm(-1, -1)); RUN(testBranch64EqualImm(1, -1)); RUN(testBranch64EqualImm(-1, 1)); RUN(testBranch64EqualMem(0, 0)); RUN(testBranch64EqualMem(1, 1)); RUN(testBranch64EqualMem(-1, -1)); RUN(testBranch64EqualMem(1, -1)); RUN(testBranch64EqualMem(-1, 1)); RUN(testBranch64EqualMemImm(0, 0)); RUN(testBranch64EqualMemImm(1, 1)); RUN(testBranch64EqualMemImm(-1, -1)); RUN(testBranch64EqualMemImm(1, -1)); RUN(testBranch64EqualMemImm(-1, 1)); RUN(testStore8Load8Z(0)); RUN(testStore8Load8Z(123)); RUN(testStore8Load8Z(12345)); RUN(testStore8Load8Z(-123)); RUN(testStore16Load16Z(0)); RUN(testStore16Load16Z(123)); RUN(testStore16Load16Z(12345)); RUN(testStore16Load16Z(12345678)); RUN(testStore16Load16Z(-123)); RUN(testSShrShl32(42, 24, 24)); RUN(testSShrShl32(-42, 24, 24)); RUN(testSShrShl32(4200, 24, 24)); RUN(testSShrShl32(-4200, 24, 24)); RUN(testSShrShl32(4200000, 24, 24)); RUN(testSShrShl32(-4200000, 24, 24)); RUN(testSShrShl32(42, 16, 16)); RUN(testSShrShl32(-42, 16, 16)); RUN(testSShrShl32(4200, 16, 16)); RUN(testSShrShl32(-4200, 16, 16)); RUN(testSShrShl32(4200000, 16, 16)); RUN(testSShrShl32(-4200000, 16, 16)); RUN(testSShrShl32(42, 8, 8)); RUN(testSShrShl32(-42, 8, 8)); RUN(testSShrShl32(4200, 8, 8)); RUN(testSShrShl32(-4200, 8, 8)); RUN(testSShrShl32(4200000, 8, 8)); RUN(testSShrShl32(-4200000, 8, 8)); RUN(testSShrShl32(420000000, 8, 8)); RUN(testSShrShl32(-420000000, 8, 8)); RUN(testSShrShl64(42, 56, 56)); RUN(testSShrShl64(-42, 56, 56)); RUN(testSShrShl64(4200, 56, 56)); RUN(testSShrShl64(-4200, 56, 56)); RUN(testSShrShl64(4200000, 56, 56)); RUN(testSShrShl64(-4200000, 56, 56)); RUN(testSShrShl64(420000000, 56, 56)); RUN(testSShrShl64(-420000000, 56, 56)); RUN(testSShrShl64(42000000000, 56, 56)); RUN(testSShrShl64(-42000000000, 56, 56)); RUN(testSShrShl64(42, 48, 48)); RUN(testSShrShl64(-42, 48, 48)); RUN(testSShrShl64(4200, 48, 48)); RUN(testSShrShl64(-4200, 48, 48)); RUN(testSShrShl64(4200000, 48, 48)); RUN(testSShrShl64(-4200000, 48, 48)); RUN(testSShrShl64(420000000, 48, 48)); RUN(testSShrShl64(-420000000, 48, 48)); RUN(testSShrShl64(42000000000, 48, 48)); RUN(testSShrShl64(-42000000000, 48, 48)); RUN(testSShrShl64(42, 32, 32)); RUN(testSShrShl64(-42, 32, 32)); RUN(testSShrShl64(4200, 32, 32)); RUN(testSShrShl64(-4200, 32, 32)); RUN(testSShrShl64(4200000, 32, 32)); RUN(testSShrShl64(-4200000, 32, 32)); RUN(testSShrShl64(420000000, 32, 32)); RUN(testSShrShl64(-420000000, 32, 32)); RUN(testSShrShl64(42000000000, 32, 32)); RUN(testSShrShl64(-42000000000, 32, 32)); RUN(testSShrShl64(42, 24, 24)); RUN(testSShrShl64(-42, 24, 24)); RUN(testSShrShl64(4200, 24, 24)); RUN(testSShrShl64(-4200, 24, 24)); RUN(testSShrShl64(4200000, 24, 24)); RUN(testSShrShl64(-4200000, 24, 24)); RUN(testSShrShl64(420000000, 24, 24)); RUN(testSShrShl64(-420000000, 24, 24)); RUN(testSShrShl64(42000000000, 24, 24)); RUN(testSShrShl64(-42000000000, 24, 24)); RUN(testSShrShl64(42, 16, 16)); RUN(testSShrShl64(-42, 16, 16)); RUN(testSShrShl64(4200, 16, 16)); RUN(testSShrShl64(-4200, 16, 16)); RUN(testSShrShl64(4200000, 16, 16)); RUN(testSShrShl64(-4200000, 16, 16)); RUN(testSShrShl64(420000000, 16, 16)); RUN(testSShrShl64(-420000000, 16, 16)); RUN(testSShrShl64(42000000000, 16, 16)); RUN(testSShrShl64(-42000000000, 16, 16)); RUN(testSShrShl64(42, 8, 8)); RUN(testSShrShl64(-42, 8, 8)); RUN(testSShrShl64(4200, 8, 8)); RUN(testSShrShl64(-4200, 8, 8)); RUN(testSShrShl64(4200000, 8, 8)); RUN(testSShrShl64(-4200000, 8, 8)); RUN(testSShrShl64(420000000, 8, 8)); RUN(testSShrShl64(-420000000, 8, 8)); RUN(testSShrShl64(42000000000, 8, 8)); RUN(testSShrShl64(-42000000000, 8, 8)); RUN(testCheckMul64SShr()); RUN(testComputeDivisionMagic<int32_t>(2, -2147483647, 0)); RUN(testTrivialInfiniteLoop()); RUN(testFoldPathEqual()); RUN(testRShiftSelf32()); RUN(testURShiftSelf32()); RUN(testLShiftSelf32()); RUN(testRShiftSelf64()); RUN(testURShiftSelf64()); RUN(testLShiftSelf64()); RUN(testPatchpointDoubleRegs()); RUN(testSpillDefSmallerThanUse()); RUN(testSpillUseLargerThanDef()); RUN(testLateRegister()); if (tasks.isEmpty()) usage(); Lock lock; Vector<ThreadIdentifier> threads; for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) { threads.append( createThread( "testb3 thread", [&] () { for (;;) { RefPtr<SharedTask<void()>> task; { LockHolder locker(lock); if (tasks.isEmpty()) return; task = tasks.takeFirst(); } task->run(); } })); } for (ThreadIdentifier thread : threads) waitForThreadCompletion(thread); crashLock.lock(); } } // anonymous namespace #else // ENABLE(B3_JIT) static void run(const char*) { dataLog("B3 JIT is not enabled.\n"); } #endif // ENABLE(B3_JIT) int main(int argc, char** argv) { const char* filter = nullptr; switch (argc) { case 1: break; case 2: filter = argv[1]; break; default: usage(); break; } run(filter); return 0; }