/* * Copyright (C) 2015-2019 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "testb3.h" #if ENABLE(B3_JIT) void testBitOrBitOrArgImmImm32(int a, int b, int c) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* innerBitOr = root->appendNew( proc, BitOr, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), b)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitOr, Origin(), innerBitOr, root->appendNew(proc, Origin(), c))); CHECK(compileAndRun(proc, a) == ((a | b) | c)); } void testBitOrImmBitOrArgImm32(int a, int b, int c) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* innerBitOr = root->appendNew( proc, BitOr, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), c)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitOr, Origin(), root->appendNew(proc, Origin(), a), innerBitOr)); CHECK(compileAndRun(proc, b) == (a | (b | c))); } double bitOrDouble(double a, double b) { return bitwise_cast(bitwise_cast(a) | bitwise_cast(b)); } void testBitOrArgDouble(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* result = root->appendNew(proc, BitOr, Origin(), argument, argument); root->appendNewControlValue(proc, Return, Origin(), result); CHECK(isIdentical(compileAndRun(proc, a), bitOrDouble(a, a))); } void testBitOrArgsDouble(double a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentA = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* argumentB = root->appendNew(proc, Origin(), FPRInfo::argumentFPR1); Value* result = root->appendNew(proc, BitOr, Origin(), argumentA, argumentB); root->appendNewControlValue(proc, Return, Origin(), result); CHECK(isIdentical(compileAndRun(proc, a, b), bitOrDouble(a, b))); } void testBitOrArgImmDouble(double a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentA = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* argumentB = root->appendNew(proc, Origin(), b); Value* result = root->appendNew(proc, BitOr, Origin(), argumentA, argumentB); root->appendNewControlValue(proc, Return, Origin(), result); CHECK(isIdentical(compileAndRun(proc, a, b), bitOrDouble(a, b))); } void testBitOrImmsDouble(double a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentA = root->appendNew(proc, Origin(), a); Value* argumentB = root->appendNew(proc, Origin(), b); Value* result = root->appendNew(proc, BitOr, Origin(), argumentA, argumentB); root->appendNewControlValue(proc, Return, Origin(), result); CHECK(isIdentical(compileAndRun(proc), bitOrDouble(a, b))); } float bitOrFloat(float a, float b) { return bitwise_cast(bitwise_cast(a) | bitwise_cast(b)); } void testBitOrArgFloat(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))); Value* result = root->appendNew(proc, BitOr, Origin(), argument, argument); root->appendNewControlValue(proc, Return, Origin(), result); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitOrFloat(a, a))); } void testBitOrArgsFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentA = root->appendNew(proc, BitwiseCast, Origin(), root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))); Value* argumentB = root->appendNew(proc, BitwiseCast, Origin(), root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1))); Value* result = root->appendNew(proc, BitOr, Origin(), argumentA, argumentB); root->appendNewControlValue(proc, Return, Origin(), result); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a), bitwise_cast(b)), bitOrFloat(a, b))); } void testBitOrArgImmFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentA = root->appendNew(proc, BitwiseCast, Origin(), root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))); Value* argumentB = root->appendNew(proc, Origin(), b); Value* result = root->appendNew(proc, BitOr, Origin(), argumentA, argumentB); root->appendNewControlValue(proc, Return, Origin(), result); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a), bitwise_cast(b)), bitOrFloat(a, b))); } void testBitOrImmsFloat(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentA = root->appendNew(proc, Origin(), a); Value* argumentB = root->appendNew(proc, Origin(), b); Value* result = root->appendNew(proc, BitOr, Origin(), argumentA, argumentB); root->appendNewControlValue(proc, Return, Origin(), result); CHECK(isIdentical(compileAndRun(proc), bitOrFloat(a, b))); } void testBitOrArgsFloatWithUselessDoubleConversion(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentA = root->appendNew(proc, BitwiseCast, Origin(), root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))); Value* argumentB = root->appendNew(proc, BitwiseCast, Origin(), root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1))); Value* argumentAasDouble = root->appendNew(proc, FloatToDouble, Origin(), argumentA); Value* argumentBasDouble = root->appendNew(proc, FloatToDouble, Origin(), argumentB); Value* doubleResult = root->appendNew(proc, BitOr, Origin(), argumentAasDouble, argumentBasDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), doubleResult); root->appendNewControlValue(proc, Return, Origin(), floatResult); double doubleA = a; double doubleB = b; float expected = static_cast(bitOrDouble(doubleA, doubleB)); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a), bitwise_cast(b)), expected)); } void testBitXorArgs(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1))); CHECK(compileAndRun(proc, a, b) == (a ^ b)); } void testBitXorSameArg(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), argument, argument)); CHECK(!compileAndRun(proc, a)); } void testBitXorAndAndArgs(int64_t a, int64_t b, int64_t c) { // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength): // ((a & b) ^ (a & c)) // ((a & b) ^ (c & a)) // ((b & a) ^ (a & c)) // ((b & a) ^ (c & a)) for (int i = 0; i < 4; ++i) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argA = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* argB = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); Value* argC = root->appendNew(proc, Origin(), GPRInfo::argumentGPR2); Value* andAB = i & 2 ? root->appendNew(proc, BitAnd, Origin(), argA, argB) : root->appendNew(proc, BitAnd, Origin(), argB, argA); Value* andAC = i & 1 ? root->appendNew(proc, BitAnd, Origin(), argA, argC) : root->appendNew(proc, BitAnd, Origin(), argC, argA); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), andAB, andAC)); CHECK_EQ(compileAndRun(proc, a, b, c), ((a & b) ^ (a & c))); } } void testBitXorAndSameArgs(int64_t a, int64_t b) { // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength): // ((a & b) ^ a) // ((b & a) ^ a) // (a ^ (a & b)) // (a ^ (b & a)) for (int i = 0; i < 4; ++i) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argA = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* argB = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); Value* andAB = i & 1 ? root->appendNew(proc, BitAnd, Origin(), argA, argB) : root->appendNew(proc, BitAnd, Origin(), argB, argA); Value* result = i & 2 ? root->appendNew(proc, BitXor, Origin(), andAB, argA) : root->appendNew(proc, BitXor, Origin(), argA, andAB); root->appendNewControlValue(proc, Return, Origin(), result); CHECK_EQ(compileAndRun(proc, a, b), ((a & b) ^ a)); } } void testBitXorImms(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc) == (a ^ b)); } void testBitXorArgImm(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc, a) == (a ^ b)); } void testBitXorImmArg(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))); CHECK(compileAndRun(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( proc, BitXor, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew(proc, Origin(), b)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), innerBitXor, root->appendNew(proc, Origin(), c))); CHECK(compileAndRun(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( proc, BitXor, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew(proc, Origin(), c)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), a), innerBitXor)); CHECK(compileAndRun(proc, b) == (a ^ (b ^ c))); } void testBitXorArgs32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun(proc, a, b) == (a ^ b)); } void testBitXorSameArg32(int a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), argument, argument)); CHECK(!compileAndRun(proc, a)); } void testBitXorImms32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc) == (a ^ b)); } void testBitXorArgImm32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc, a) == (a ^ b)); } void testBitXorImmArg32(int a, int b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), a), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(compileAndRun(proc, b) == (a ^ b)); } void testBitXorBitXorArgImmImm32(int a, int b, int c) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* innerBitXor = root->appendNew( proc, BitXor, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), b)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), innerBitXor, root->appendNew(proc, Origin(), c))); CHECK(compileAndRun(proc, a) == ((a ^ b) ^ c)); } void testBitXorImmBitXorArgImm32(int a, int b, int c) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* innerBitXor = root->appendNew( proc, BitXor, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), c)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), a), innerBitXor)); CHECK(compileAndRun(proc, b) == (a ^ (b ^ c))); } void testBitNotArg(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), -1), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))); CHECK(isIdentical(compileAndRun(proc, a), static_cast((static_cast(a) ^ 0xffffffffffffffff)))); } void testBitNotImm(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), -1), root->appendNew(proc, Origin(), a))); CHECK(isIdentical(compileAndRun(proc, a), static_cast((static_cast(a) ^ 0xffffffffffffffff)))); } void testBitNotMem(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* load = root->appendNew(proc, Load, Int64, Origin(), address); Value* notLoad = root->appendNew(proc, BitXor, Origin(), root->appendNew(proc, Origin(), -1), load); root->appendNew(proc, Store, Origin(), notLoad, address); root->appendNewControlValue(proc, Return, Origin(), root->appendNew(proc, Origin(), 0)); int64_t input = a; compileAndRun(proc, &input); CHECK(isIdentical(input, static_cast((static_cast(a) ^ 0xffffffffffffffff)))); } void testBitNotArg32(int32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, BitXor, Origin(), root->appendNew(proc, Origin(), -1), argument)); CHECK(isIdentical(compileAndRun(proc, a), static_cast((static_cast(a) ^ 0xffffffff)))); } void testBitNotImm32(int32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitXor, Origin(), root->appendNew(proc, Origin(), -1), root->appendNew(proc, Origin(), a))); CHECK(isIdentical(compileAndRun(proc, a), static_cast((static_cast(a) ^ 0xffffffff)))); } void testBitNotMem32(int32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* load = root->appendNew(proc, Load, Int32, Origin(), address); Value* notLoad = root->appendNew(proc, BitXor, Origin(), root->appendNew(proc, Origin(), -1), load); root->appendNew(proc, Store, Origin(), notLoad, address); root->appendNewControlValue(proc, Return, Origin(), root->appendNew(proc, Origin(), 0)); int32_t input = a; compileAndRun(proc, &input); CHECK(isIdentical(input, static_cast((static_cast(a) ^ 0xffffffff)))); } void testNotOnBooleanAndBranch32(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* arg1 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)); Value* argsAreEqual = root->appendNew(proc, Equal, Origin(), arg1, arg2); Value* argsAreNotEqual = root->appendNew(proc, BitXor, Origin(), root->appendNew(proc, Origin(), 1), argsAreEqual); root->appendNewControlValue( proc, Branch, Origin(), argsAreNotEqual, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNewControlValue( proc, Return, Origin(), thenCase->appendNew(proc, Origin(), 42)); elseCase->appendNewControlValue( proc, Return, Origin(), elseCase->appendNew(proc, Origin(), -42)); int32_t expectedValue = (a != b) ? 42 : -42; CHECK(compileAndRun(proc, a, b) == expectedValue); } void testBitNotOnBooleanAndBranch32(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); Value* arg1 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg2 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)); Value* argsAreEqual = root->appendNew(proc, Equal, Origin(), arg1, arg2); Value* bitNotArgsAreEqual = root->appendNew(proc, BitXor, Origin(), root->appendNew(proc, Origin(), -1), argsAreEqual); root->appendNewControlValue(proc, Branch, Origin(), bitNotArgsAreEqual, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); thenCase->appendNewControlValue(proc, Return, Origin(), thenCase->appendNew(proc, Origin(), 42)); elseCase->appendNewControlValue(proc, Return, Origin(), elseCase->appendNew(proc, Origin(), -42)); static constexpr int32_t expectedValue = 42; CHECK(compileAndRun(proc, a, b) == expectedValue); } void testShlArgs(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Shl, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun(proc, a, b) == (a << b)); } void testShlImms(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Shl, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), b))); b = b & 0x3f; // to avoid undefined behaviour below CHECK(compileAndRun(proc) == (a << b)); } void testShlArgImm(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Shl, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew(proc, Origin(), b))); b = b & 0x3f; // to avoid undefined behaviour below CHECK(compileAndRun(proc, a) == (a << b)); } void testShlSShrArgImm(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argA = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* constB = root->appendNew(proc, Origin(), b); Value* innerShift = root->appendNew(proc, SShr, Origin(), argA, constB); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Shl, Origin(), innerShift, constB)); b = b & 0x3f; // to avoid undefined behaviour below CHECK(compileAndRun(proc, a) == ((a >> b) << b)); } void testShlArg32(int32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Shl, Origin(), value, value)); CHECK(compileAndRun(proc, a) == (a << a)); } void testShlArgs32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Shl, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun(proc, a, b) == (a << b)); } void testShlImms32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Shl, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), b))); b = b & 0x1f; // to avoid undefined behaviour below CHECK(compileAndRun(proc) == (a << b)); } void testShlArgImm32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Shl, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), b))); b = b & 0x1f; // to avoid undefined behaviour below CHECK(compileAndRun(proc, a) == (a << b)); } void testShlZShrArgImm32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argA = root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* constB = root->appendNew(proc, Origin(), b); Value* innerShift = root->appendNew(proc, ZShr, Origin(), argA, constB); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Shl, Origin(), innerShift, constB)); b = b & 0x1f; // to avoid undefined behaviour below CHECK(compileAndRun(proc, a) == static_cast((static_cast(a) >> b) << b)); } static void testSShrArgs(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, SShr, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun(proc, a, b) == (a >> b)); } static void testSShrImms(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, SShr, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc) == (a >> b)); } static void testSShrArgImm(int64_t a, int64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, SShr, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc, a) == (a >> b)); } static void testSShrArg32(int32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, SShr, Origin(), value, value)); CHECK(compileAndRun(proc, a) == (a >> (a & 31))); } static void testSShrArgs32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, SShr, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun(proc, a, b) == (a >> b)); } static void testSShrImms32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, SShr, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc) == (a >> b)); } static void testSShrArgImm32(int32_t a, int32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, SShr, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc, a) == (a >> b)); } static void testZShrArgs(uint64_t a, uint64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, ZShr, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun(proc, a, b) == (a >> b)); } static void testZShrImms(uint64_t a, uint64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, ZShr, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc) == (a >> b)); } static void testZShrArgImm(uint64_t a, uint64_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, ZShr, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc, a) == (a >> b)); } static void testZShrArg32(uint32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, ZShr, Origin(), value, value)); CHECK(compileAndRun(proc, a) == (a >> (a & 31))); } static void testZShrArgs32(uint32_t a, uint32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, ZShr, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)))); CHECK(compileAndRun(proc, a, b) == (a >> b)); } static void testZShrImms32(uint32_t a, uint32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, ZShr, Origin(), root->appendNew(proc, Origin(), a), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc) == (a >> b)); } static void testZShrArgImm32(uint32_t a, uint32_t b) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, ZShr, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), b))); CHECK(compileAndRun(proc, a) == (a >> b)); } template static unsigned countLeadingZero(IntegerType value) { unsigned bitCount = sizeof(IntegerType) * 8; if (!value) return bitCount; unsigned counter = 0; while (!(static_cast(value) & (1l << (bitCount - 1)))) { value <<= 1; ++counter; } return counter; } void testClzArg64(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* clzValue = root->appendNew(proc, Clz, Origin(), argument); root->appendNewControlValue(proc, Return, Origin(), clzValue); CHECK(compileAndRun(proc, a) == countLeadingZero(a)); } void testClzMem64(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* value = root->appendNew(proc, Load, Int64, Origin(), address); Value* clzValue = root->appendNew(proc, Clz, Origin(), value); root->appendNewControlValue(proc, Return, Origin(), clzValue); CHECK(compileAndRun(proc, &a) == countLeadingZero(a)); } void testClzArg32(int32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* clzValue = root->appendNew(proc, Clz, Origin(), argument); root->appendNewControlValue(proc, Return, Origin(), clzValue); CHECK(compileAndRun(proc, a) == countLeadingZero(a)); } void testClzMem32(int32_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* value = root->appendNew(proc, Load, Int32, Origin(), address); Value* clzValue = root->appendNew(proc, Clz, Origin(), value); root->appendNewControlValue(proc, Return, Origin(), clzValue); CHECK(compileAndRun(proc, &a) == countLeadingZero(a)); } void testAbsArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Abs, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0))); CHECK(isIdentical(compileAndRun(proc, a), fabs(a))); } void testAbsImm(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), a); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Abs, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc), fabs(a))); } void testAbsMem(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadDouble = root->appendNew(proc, Load, Double, Origin(), address); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Abs, Origin(), loadDouble)); CHECK(isIdentical(compileAndRun(proc, &a), fabs(a))); } void testAbsAbsArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* firstAbs = root->appendNew(proc, Abs, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0)); Value* secondAbs = root->appendNew(proc, Abs, Origin(), firstAbs); root->appendNewControlValue(proc, Return, Origin(), secondAbs); CHECK(isIdentical(compileAndRun(proc, a), fabs(fabs(a)))); } void testAbsNegArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* neg = root->appendNew(proc, Neg, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0)); Value* abs = root->appendNew(proc, Abs, Origin(), neg); root->appendNewControlValue(proc, Return, Origin(), abs); CHECK(isIdentical(compileAndRun(proc, a), fabs(- a))); } void testAbsBitwiseCastArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentAsInt64 = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* argumentAsDouble = root->appendNew(proc, BitwiseCast, Origin(), argumentAsInt64); Value* absValue = root->appendNew(proc, Abs, Origin(), argumentAsDouble); root->appendNewControlValue(proc, Return, Origin(), absValue); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), fabs(a))); } void testBitwiseCastAbsBitwiseCastArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentAsInt64 = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* argumentAsDouble = root->appendNew(proc, BitwiseCast, Origin(), argumentAsInt64); Value* absValue = root->appendNew(proc, Abs, Origin(), argumentAsDouble); Value* resultAsInt64 = root->appendNew(proc, BitwiseCast, Origin(), absValue); root->appendNewControlValue(proc, Return, Origin(), resultAsInt64); int64_t expectedResult = bitwise_cast(fabs(a)); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), expectedResult)); } void testAbsArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* result = root->appendNew(proc, Abs, Origin(), argument); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(static_cast(fabs(a))))); } void testAbsImm(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), a); Value* result = root->appendNew(proc, Abs, Origin(), argument); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(static_cast(fabs(a))))); } void testAbsMem(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadFloat = root->appendNew(proc, Load, Float, Origin(), address); Value* result = root->appendNew(proc, Abs, Origin(), loadFloat); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, &a), bitwise_cast(static_cast(fabs(a))))); } void testAbsAbsArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* firstAbs = root->appendNew(proc, Abs, Origin(), argument); Value* secondAbs = root->appendNew(proc, Abs, Origin(), firstAbs); root->appendNewControlValue(proc, Return, Origin(), secondAbs); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), static_cast(fabs(fabs(a))))); } void testAbsNegArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* neg = root->appendNew(proc, Neg, Origin(), argument); Value* abs = root->appendNew(proc, Abs, Origin(), neg); root->appendNewControlValue(proc, Return, Origin(), abs); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), static_cast(fabs(- a)))); } void testAbsBitwiseCastArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentAsInt32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argumentAsfloat = root->appendNew(proc, BitwiseCast, Origin(), argumentAsInt32); Value* absValue = root->appendNew(proc, Abs, Origin(), argumentAsfloat); root->appendNewControlValue(proc, Return, Origin(), absValue); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), static_cast(fabs(a)))); } void testBitwiseCastAbsBitwiseCastArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argumentAsInt32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argumentAsfloat = root->appendNew(proc, BitwiseCast, Origin(), argumentAsInt32); Value* absValue = root->appendNew(proc, Abs, Origin(), argumentAsfloat); Value* resultAsInt64 = root->appendNew(proc, BitwiseCast, Origin(), absValue); root->appendNewControlValue(proc, Return, Origin(), resultAsInt64); int32_t expectedResult = bitwise_cast(static_cast(fabs(a))); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), expectedResult)); } void testAbsArgWithUselessDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew(proc, Abs, Origin(), asDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), floatResult); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(static_cast(fabs(a))))); } void testAbsArgWithEffectfulDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew(proc, Abs, Origin(), asDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), floatResult); Value* doubleAddress = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew(proc, Store, Origin(), result, doubleAddress); root->appendNewControlValue(proc, Return, Origin(), result32); double effect = 0; int32_t resultValue = compileAndRun(proc, bitwise_cast(a), &effect); CHECK(isIdentical(resultValue, bitwise_cast(static_cast(fabs(a))))); CHECK(isIdentical(effect, static_cast(fabs(a)))); } void testCeilArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Ceil, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0))); CHECK(isIdentical(compileAndRun(proc, a), ceil(a))); } void testCeilImm(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), a); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Ceil, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc), ceil(a))); } void testCeilMem(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadDouble = root->appendNew(proc, Load, Double, Origin(), address); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Ceil, Origin(), loadDouble)); CHECK(isIdentical(compileAndRun(proc, &a), ceil(a))); } void testCeilCeilArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* firstCeil = root->appendNew(proc, Ceil, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0)); Value* secondCeil = root->appendNew(proc, Ceil, Origin(), firstCeil); root->appendNewControlValue(proc, Return, Origin(), secondCeil); CHECK(isIdentical(compileAndRun(proc, a), ceil(a))); } void testFloorCeilArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* firstCeil = root->appendNew(proc, Ceil, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0)); Value* wrappingFloor = root->appendNew(proc, Floor, Origin(), firstCeil); root->appendNewControlValue(proc, Return, Origin(), wrappingFloor); CHECK(isIdentical(compileAndRun(proc, a), ceil(a))); } void testCeilIToD64(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* argumentAsDouble = root->appendNew(proc, IToD, Origin(), argument); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Ceil, Origin(), argumentAsDouble)); CHECK(isIdentical(compileAndRun(proc, a), ceil(static_cast(a)))); } void testCeilIToD32(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argumentAsDouble = root->appendNew(proc, IToD, Origin(), argument); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Ceil, Origin(), argumentAsDouble)); CHECK(isIdentical(compileAndRun(proc, a), ceil(static_cast(a)))); } void testCeilArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* result = root->appendNew(proc, Ceil, Origin(), argument); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(ceilf(a)))); } void testCeilImm(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), a); Value* result = root->appendNew(proc, Ceil, Origin(), argument); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(ceilf(a)))); } void testCeilMem(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadFloat = root->appendNew(proc, Load, Float, Origin(), address); Value* result = root->appendNew(proc, Ceil, Origin(), loadFloat); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, &a), bitwise_cast(ceilf(a)))); } void testCeilCeilArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* firstCeil = root->appendNew(proc, Ceil, Origin(), argument); Value* secondCeil = root->appendNew(proc, Ceil, Origin(), firstCeil); root->appendNewControlValue(proc, Return, Origin(), secondCeil); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), ceilf(a))); } void testFloorCeilArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* firstCeil = root->appendNew(proc, Ceil, Origin(), argument); Value* wrappingFloor = root->appendNew(proc, Floor, Origin(), firstCeil); root->appendNewControlValue(proc, Return, Origin(), wrappingFloor); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), ceilf(a))); } void testCeilArgWithUselessDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew(proc, Ceil, Origin(), asDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), floatResult); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(ceilf(a)))); } void testCeilArgWithEffectfulDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew(proc, Ceil, Origin(), asDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), floatResult); Value* doubleAddress = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew(proc, Store, Origin(), result, doubleAddress); root->appendNewControlValue(proc, Return, Origin(), result32); double effect = 0; int32_t resultValue = compileAndRun(proc, bitwise_cast(a), &effect); CHECK(isIdentical(resultValue, bitwise_cast(ceilf(a)))); CHECK(isIdentical(effect, static_cast(ceilf(a)))); } void testFloorArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Floor, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0))); CHECK(isIdentical(compileAndRun(proc, a), floor(a))); } void testFloorImm(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), a); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Floor, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc), floor(a))); } void testFloorMem(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadDouble = root->appendNew(proc, Load, Double, Origin(), address); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Floor, Origin(), loadDouble)); CHECK(isIdentical(compileAndRun(proc, &a), floor(a))); } void testFloorFloorArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* firstFloor = root->appendNew(proc, Floor, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0)); Value* secondFloor = root->appendNew(proc, Floor, Origin(), firstFloor); root->appendNewControlValue(proc, Return, Origin(), secondFloor); CHECK(isIdentical(compileAndRun(proc, a), floor(a))); } void testCeilFloorArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* firstFloor = root->appendNew(proc, Floor, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0)); Value* wrappingCeil = root->appendNew(proc, Ceil, Origin(), firstFloor); root->appendNewControlValue(proc, Return, Origin(), wrappingCeil); CHECK(isIdentical(compileAndRun(proc, a), floor(a))); } void testFloorIToD64(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* argumentAsDouble = root->appendNew(proc, IToD, Origin(), argument); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Floor, Origin(), argumentAsDouble)); CHECK(isIdentical(compileAndRun(proc, a), floor(static_cast(a)))); } void testFloorIToD32(int64_t a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argumentAsDouble = root->appendNew(proc, IToD, Origin(), argument); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Floor, Origin(), argumentAsDouble)); CHECK(isIdentical(compileAndRun(proc, a), floor(static_cast(a)))); } void testFloorArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* result = root->appendNew(proc, Floor, Origin(), argument); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(floorf(a)))); } void testFloorImm(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), a); Value* result = root->appendNew(proc, Floor, Origin(), argument); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(floorf(a)))); } void testFloorMem(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadFloat = root->appendNew(proc, Load, Float, Origin(), address); Value* result = root->appendNew(proc, Floor, Origin(), loadFloat); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, &a), bitwise_cast(floorf(a)))); } void testFloorFloorArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* firstFloor = root->appendNew(proc, Floor, Origin(), argument); Value* secondFloor = root->appendNew(proc, Floor, Origin(), firstFloor); root->appendNewControlValue(proc, Return, Origin(), secondFloor); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), floorf(a))); } void testCeilFloorArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* firstFloor = root->appendNew(proc, Floor, Origin(), argument); Value* wrappingCeil = root->appendNew(proc, Ceil, Origin(), firstFloor); root->appendNewControlValue(proc, Return, Origin(), wrappingCeil); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), floorf(a))); } void testFloorArgWithUselessDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew(proc, Floor, Origin(), asDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), floatResult); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(floorf(a)))); } void testFloorArgWithEffectfulDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew(proc, Floor, Origin(), asDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), floatResult); Value* doubleAddress = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew(proc, Store, Origin(), result, doubleAddress); root->appendNewControlValue(proc, Return, Origin(), result32); double effect = 0; int32_t resultValue = compileAndRun(proc, bitwise_cast(a), &effect); CHECK(isIdentical(resultValue, bitwise_cast(floorf(a)))); CHECK(isIdentical(effect, static_cast(floorf(a)))); } double correctSqrt(double value) { #if CPU(X86) || CPU(X86_64) double result; asm ("sqrtsd %1, %0" : "=x"(result) : "x"(value)); return result; #else return sqrt(value); #endif } void testSqrtArg(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Sqrt, Origin(), root->appendNew(proc, Origin(), FPRInfo::argumentFPR0))); CHECK(isIdentical(compileAndRun(proc, a), correctSqrt(a))); } void testSqrtImm(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), a); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Sqrt, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc), correctSqrt(a))); } void testSqrtMem(double a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadDouble = root->appendNew(proc, Load, Double, Origin(), address); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Sqrt, Origin(), loadDouble)); CHECK(isIdentical(compileAndRun(proc, &a), correctSqrt(a))); } void testSqrtArg(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* argument = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* result = root->appendNew(proc, Sqrt, Origin(), argument); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(static_cast(correctSqrt(a))))); } void testSqrtImm(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), a); Value* result = root->appendNew(proc, Sqrt, Origin(), argument); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(static_cast(correctSqrt(a))))); } void testSqrtMem(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadFloat = root->appendNew(proc, Load, Float, Origin(), address); Value* result = root->appendNew(proc, Sqrt, Origin(), loadFloat); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), result); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, &a), bitwise_cast(static_cast(correctSqrt(a))))); } void testSqrtArgWithUselessDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew(proc, Sqrt, Origin(), asDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), floatResult); root->appendNewControlValue(proc, Return, Origin(), result32); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(a)), bitwise_cast(static_cast(correctSqrt(a))))); } void testSqrtArgWithEffectfulDoubleConversion(float a) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* result = root->appendNew(proc, Sqrt, Origin(), asDouble); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), result); Value* result32 = root->appendNew(proc, BitwiseCast, Origin(), floatResult); Value* doubleAddress = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew(proc, Store, Origin(), result, doubleAddress); root->appendNewControlValue(proc, Return, Origin(), result32); double effect = 0; int32_t resultValue = compileAndRun(proc, bitwise_cast(a), &effect); CHECK(isIdentical(resultValue, bitwise_cast(static_cast(correctSqrt(a))))); double expected = static_cast(correctSqrt(a)); CHECK(isIdentical(effect, expected)); } void testCompareTwoFloatToDouble(float a, float b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1As32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg1Float = root->appendNew(proc, BitwiseCast, Origin(), arg1As32); Value* arg1AsDouble = root->appendNew(proc, FloatToDouble, Origin(), arg1Float); Value* arg2As32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)); Value* arg2Float = root->appendNew(proc, BitwiseCast, Origin(), arg2As32); Value* arg2AsDouble = root->appendNew(proc, FloatToDouble, Origin(), arg2Float); Value* equal = root->appendNew(proc, Equal, Origin(), arg1AsDouble, arg2AsDouble); root->appendNewControlValue(proc, Return, Origin(), equal); CHECK(compileAndRun(proc, bitwise_cast(a), bitwise_cast(b)) == (a == b)); } void testCompareOneFloatToDouble(float a, double b) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* arg1As32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* arg1Float = root->appendNew(proc, BitwiseCast, Origin(), arg1As32); Value* arg1AsDouble = root->appendNew(proc, FloatToDouble, Origin(), arg1Float); Value* arg2AsDouble = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* equal = root->appendNew(proc, Equal, Origin(), arg1AsDouble, arg2AsDouble); root->appendNewControlValue(proc, Return, Origin(), equal); CHECK(compileAndRun(proc, bitwise_cast(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(proc, Origin(), GPRInfo::argumentGPR0); Value* arg1As32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)); Value* arg1Float = root->appendNew(proc, BitwiseCast, Origin(), arg1As32); Value* arg1AsDouble = root->appendNew(proc, FloatToDouble, Origin(), arg1Float); Value* arg2AsDouble = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* arg2AsFloat = root->appendNew(proc, DoubleToFloat, Origin(), arg2AsDouble); Value* arg2AsFRoundedDouble = root->appendNew(proc, FloatToDouble, Origin(), arg2AsFloat); root->appendNewControlValue( proc, Branch, Origin(), condition, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); UpsilonValue* thenValue = thenCase->appendNew(proc, Origin(), arg1AsDouble); thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* elseConst = elseCase->appendNew(proc, Origin(), 0.); UpsilonValue* elseValue = elseCase->appendNew(proc, Origin(), elseConst); elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* doubleInput = tail->appendNew(proc, Phi, Double, Origin()); thenValue->setPhi(doubleInput); elseValue->setPhi(doubleInput); Value* equal = tail->appendNew(proc, Equal, Origin(), doubleInput, arg2AsFRoundedDouble); tail->appendNewControlValue(proc, Return, Origin(), equal); auto code = compileProc(proc); int32_t integerA = bitwise_cast(a); double doubleB = b; CHECK(invoke(*code, 1, integerA, doubleB) == (a == b)); CHECK(invoke(*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(proc, Origin(), GPRInfo::argumentGPR0); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* argAsDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); root->appendNewControlValue( proc, Branch, Origin(), condition, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); Value* postitiveConst = thenCase->appendNew(proc, Origin(), 42.5f); Value* thenAdd = thenCase->appendNew(proc, Add, Origin(), argAsDouble, postitiveConst); UpsilonValue* thenValue = thenCase->appendNew(proc, Origin(), thenAdd); thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* elseConst = elseCase->appendNew(proc, Origin(), M_PI); UpsilonValue* elseValue = elseCase->appendNew(proc, Origin(), elseConst); elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* doubleInput = tail->appendNew(proc, Phi, Double, Origin()); thenValue->setPhi(doubleInput); elseValue->setPhi(doubleInput); Value* floatResult = tail->appendNew(proc, DoubleToFloat, Origin(), doubleInput); tail->appendNewControlValue(proc, Return, Origin(), floatResult); auto code = compileProc(proc); CHECK(isIdentical(invoke(*code, 1, bitwise_cast(value)), value + 42.5f)); CHECK(isIdentical(invoke(*code, 0, bitwise_cast(value)), static_cast(M_PI))); } void testReduceFloatToDoubleValidates() { // Simple case of: // f = DoubleToFloat(Bitcast(argGPR0)) // if (a) { // x = FloatConst() // else // x = FloatConst() // p = Phi(x) // a = Mul(p, p) // b = Add(a, f) // c = Add(p, b) // Return(c) // // This should not crash in the validator after ReduceFloatToDouble. Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); BasicBlock* tail = proc.addBlock(); Value* condition = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* thingy = root->appendNew(proc, BitwiseCast, Origin(), condition); thingy = root->appendNew(proc, DoubleToFloat, Origin(), thingy); // Make the phase think it has work to do. root->appendNewControlValue( proc, Branch, Origin(), condition, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); UpsilonValue* thenValue = thenCase->appendNew(proc, Origin(), thenCase->appendNew(proc, Origin(), 11.5)); thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); UpsilonValue* elseValue = elseCase->appendNew(proc, Origin(), elseCase->appendNew(proc, Origin(), 10.5)); elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* phi = tail->appendNew(proc, Phi, Float, Origin()); thenValue->setPhi(phi); elseValue->setPhi(phi); Value* result = tail->appendNew(proc, Mul, Origin(), phi, phi); result = tail->appendNew(proc, Add, Origin(), result, thingy); result = tail->appendNew(proc, Add, Origin(), phi, result); tail->appendNewControlValue(proc, Return, Origin(), result); auto code = compileProc(proc); CHECK(isIdentical(invoke(*code, 1), 11.5f * 11.5f + static_cast(bitwise_cast(static_cast(1))) + 11.5f)); CHECK(isIdentical(invoke(*code, 0), 10.5f * 10.5f + static_cast(bitwise_cast(static_cast(0))) + 10.5f)); } void testDoubleProducerPhiToFloatConversion(float value) { Procedure proc; BasicBlock* root = proc.addBlock(); BasicBlock* thenCase = proc.addBlock(); BasicBlock* elseCase = proc.addBlock(); BasicBlock* tail = proc.addBlock(); Value* condition = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); root->appendNewControlValue( proc, Branch, Origin(), condition, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); Value* asDouble = thenCase->appendNew(proc, FloatToDouble, Origin(), floatValue); UpsilonValue* thenValue = thenCase->appendNew(proc, Origin(), asDouble); thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* constDouble = elseCase->appendNew(proc, Origin(), 42.5); UpsilonValue* elseValue = elseCase->appendNew(proc, Origin(), constDouble); elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* doubleInput = tail->appendNew(proc, Phi, Double, Origin()); thenValue->setPhi(doubleInput); elseValue->setPhi(doubleInput); Value* argAsDoubleAgain = tail->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* finalAdd = tail->appendNew(proc, Add, Origin(), doubleInput, argAsDoubleAgain); Value* floatResult = tail->appendNew(proc, DoubleToFloat, Origin(), finalAdd); tail->appendNewControlValue(proc, Return, Origin(), floatResult); auto code = compileProc(proc); CHECK(isIdentical(invoke(*code, 1, bitwise_cast(value)), value + value)); CHECK(isIdentical(invoke(*code, 0, bitwise_cast(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(proc, Origin(), GPRInfo::argumentGPR0); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); root->appendNewControlValue( proc, Branch, Origin(), condition, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); Value* asDouble = thenCase->appendNew(proc, FloatToDouble, Origin(), floatValue); UpsilonValue* thenValue = thenCase->appendNew(proc, Origin(), asDouble); thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* constDouble = elseCase->appendNew(proc, Origin(), 42.5); UpsilonValue* elseValue = elseCase->appendNew(proc, Origin(), constDouble); elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* doubleInput = tail->appendNew(proc, Phi, Double, Origin()); thenValue->setPhi(doubleInput); elseValue->setPhi(doubleInput); Value* argAsDoubleAgain = tail->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* floatAdd = tail->appendNew(proc, Add, Origin(), doubleInput, argAsDoubleAgain); // FRound. Value* floatResult = tail->appendNew(proc, DoubleToFloat, Origin(), floatAdd); Value* doubleResult = tail->appendNew(proc, FloatToDouble, Origin(), floatResult); // This one *cannot* be eliminated Value* doubleAdd = tail->appendNew(proc, Add, Origin(), doubleInput, doubleResult); tail->appendNewControlValue(proc, Return, Origin(), doubleAdd); auto code = compileProc(proc); CHECK(isIdentical(invoke(*code, 1, bitwise_cast(value)), (value + value) + static_cast(value))); CHECK(isIdentical(invoke(*code, 0, bitwise_cast(value)), static_cast((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(proc, Origin(), GPRInfo::argumentGPR0); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR1)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); root->appendNewControlValue( proc, Branch, Origin(), condition, FrequentedBlock(thenCase), FrequentedBlock(elseCase)); Value* asDouble = thenCase->appendNew(proc, FloatToDouble, Origin(), floatValue); UpsilonValue* thenValue = thenCase->appendNew(proc, Origin(), asDouble); thenCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* constDouble = elseCase->appendNew(proc, Origin(), constValue); UpsilonValue* elseValue = elseCase->appendNew(proc, Origin(), constDouble); elseCase->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(tail)); Value* doubleInput = tail->appendNew(proc, Phi, Double, Origin()); thenValue->setPhi(doubleInput); elseValue->setPhi(doubleInput); Value* argAsDoubleAgain = tail->appendNew(proc, FloatToDouble, Origin(), floatValue); Value* finalAdd = tail->appendNew(proc, Add, Origin(), doubleInput, argAsDoubleAgain); Value* floatResult = tail->appendNew(proc, DoubleToFloat, Origin(), finalAdd); tail->appendNewControlValue(proc, Return, Origin(), floatResult); auto code = compileProc(proc); CHECK(isIdentical(invoke(*code, 1, bitwise_cast(value)), value + value)); CHECK(isIdentical(invoke(*code, 0, bitwise_cast(value)), static_cast(constValue + value))); } void testDoubleArgToInt64BitwiseCast(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc, value), bitwise_cast(value))); } void testDoubleImmToInt64BitwiseCast(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), value); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc), bitwise_cast(value))); } void testTwoBitwiseCastOnDouble(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* first = root->appendNew(proc, BitwiseCast, Origin(), argument); Value* second = root->appendNew(proc, BitwiseCast, Origin(), first); root->appendNewControlValue(proc, Return, Origin(), second); CHECK(isIdentical(compileAndRun(proc, value), value)); } void testBitwiseCastOnDoubleInMemory(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadDouble = root->appendNew(proc, Load, Double, Origin(), address); Value* cast = root->appendNew(proc, BitwiseCast, Origin(), loadDouble); root->appendNewControlValue(proc, Return, Origin(), cast); CHECK(isIdentical(compileAndRun(proc, &value), bitwise_cast(value))); } void testBitwiseCastOnDoubleInMemoryIndexed(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* base = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* offset = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); Value* scaledOffset = root->appendNew(proc, Shl, Origin(), offset, root->appendNew(proc, Origin(), 3)); Value* address = root->appendNew(proc, Add, Origin(), base, scaledOffset); MemoryValue* loadDouble = root->appendNew(proc, Load, Double, Origin(), address); Value* cast = root->appendNew(proc, BitwiseCast, Origin(), loadDouble); root->appendNewControlValue(proc, Return, Origin(), cast); CHECK(isIdentical(compileAndRun(proc, &value, 0), bitwise_cast(value))); } void testInt64BArgToDoubleBitwiseCast(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc, value), bitwise_cast(value))); } void testInt64BImmToDoubleBitwiseCast(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), value); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc), bitwise_cast(value))); } void testTwoBitwiseCastOnInt64(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* first = root->appendNew(proc, BitwiseCast, Origin(), argument); Value* second = root->appendNew(proc, BitwiseCast, Origin(), first); root->appendNewControlValue(proc, Return, Origin(), second); CHECK(isIdentical(compileAndRun(proc, value), value)); } void testBitwiseCastOnInt64InMemory(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadDouble = root->appendNew(proc, Load, Int64, Origin(), address); Value* cast = root->appendNew(proc, BitwiseCast, Origin(), loadDouble); root->appendNewControlValue(proc, Return, Origin(), cast); CHECK(isIdentical(compileAndRun(proc, &value), bitwise_cast(value))); } void testBitwiseCastOnInt64InMemoryIndexed(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* base = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* offset = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); Value* scaledOffset = root->appendNew(proc, Shl, Origin(), offset, root->appendNew(proc, Origin(), 3)); Value* address = root->appendNew(proc, Add, Origin(), base, scaledOffset); MemoryValue* loadDouble = root->appendNew(proc, Load, Int64, Origin(), address); Value* cast = root->appendNew(proc, BitwiseCast, Origin(), loadDouble); root->appendNewControlValue(proc, Return, Origin(), cast); CHECK(isIdentical(compileAndRun(proc, &value, 0), bitwise_cast(value))); } void testFloatImmToInt32BitwiseCast(float value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), value); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc), bitwise_cast(value))); } void testBitwiseCastOnFloatInMemory(float value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadFloat = root->appendNew(proc, Load, Float, Origin(), address); Value* cast = root->appendNew(proc, BitwiseCast, Origin(), loadFloat); root->appendNewControlValue(proc, Return, Origin(), cast); CHECK(isIdentical(compileAndRun(proc, &value), bitwise_cast(value))); } void testInt32BArgToFloatBitwiseCast(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc, value), bitwise_cast(value))); } void testInt32BImmToFloatBitwiseCast(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), value); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, BitwiseCast, Origin(), argument)); CHECK(isIdentical(compileAndRun(proc), bitwise_cast(value))); } void testTwoBitwiseCastOnInt32(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* first = root->appendNew(proc, BitwiseCast, Origin(), argument); Value* second = root->appendNew(proc, BitwiseCast, Origin(), first); root->appendNewControlValue(proc, Return, Origin(), second); CHECK(isIdentical(compileAndRun(proc, value), value)); } void testBitwiseCastOnInt32InMemory(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadFloat = root->appendNew(proc, Load, Int32, Origin(), address); Value* cast = root->appendNew(proc, BitwiseCast, Origin(), loadFloat); root->appendNewControlValue(proc, Return, Origin(), cast); CHECK(isIdentical(compileAndRun(proc, &value), bitwise_cast(value))); } void testConvertDoubleToFloatArg(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* asFloat = root->appendNew(proc, DoubleToFloat, Origin(), argument); root->appendNewControlValue(proc, Return, Origin(), asFloat); CHECK(isIdentical(compileAndRun(proc, value), static_cast(value))); } void testConvertDoubleToFloatImm(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), value); Value* asFloat = root->appendNew(proc, DoubleToFloat, Origin(), argument); root->appendNewControlValue(proc, Return, Origin(), asFloat); CHECK(isIdentical(compileAndRun(proc), static_cast(value))); } void testConvertDoubleToFloatMem(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadedDouble = root->appendNew(proc, Load, Double, Origin(), address); Value* asFloat = root->appendNew(proc, DoubleToFloat, Origin(), loadedDouble); root->appendNewControlValue(proc, Return, Origin(), asFloat); CHECK(isIdentical(compileAndRun(proc, &value), static_cast(value))); } void testConvertFloatToDoubleArg(float value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument32 = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* floatValue = root->appendNew(proc, BitwiseCast, Origin(), argument32); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), floatValue); root->appendNewControlValue(proc, Return, Origin(), asDouble); CHECK(isIdentical(compileAndRun(proc, bitwise_cast(value)), static_cast(value))); } void testConvertFloatToDoubleImm(float value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), value); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), argument); root->appendNewControlValue(proc, Return, Origin(), asDouble); CHECK(isIdentical(compileAndRun(proc), static_cast(value))); } void testConvertFloatToDoubleMem(float value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadedFloat = root->appendNew(proc, Load, Float, Origin(), address); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), loadedFloat); root->appendNewControlValue(proc, Return, Origin(), asDouble); CHECK(isIdentical(compileAndRun(proc, &value), static_cast(value))); } void testConvertDoubleToFloatToDoubleToFloat(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* asFloat = root->appendNew(proc, DoubleToFloat, Origin(), argument); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), asFloat); Value* asFloatAgain = root->appendNew(proc, DoubleToFloat, Origin(), asDouble); root->appendNewControlValue(proc, Return, Origin(), asFloatAgain); CHECK(isIdentical(compileAndRun(proc, value), static_cast(value))); } void testLoadFloatConvertDoubleConvertFloatStoreFloat(float value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* dst = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); MemoryValue* loadedFloat = root->appendNew(proc, Load, Float, Origin(), src); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), loadedFloat); Value* asFloatAgain = root->appendNew(proc, DoubleToFloat, Origin(), asDouble); root->appendNew(proc, Store, Origin(), asFloatAgain, dst); root->appendNewControlValue(proc, Return, Origin(), root->appendNew(proc, Origin(), 0)); float input = value; float output = 0.; CHECK(!compileAndRun(proc, &input, &output)); CHECK(isIdentical(input, output)); } void testFroundArg(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* argument = root->appendNew(proc, Origin(), FPRInfo::argumentFPR0); Value* asFloat = root->appendNew(proc, DoubleToFloat, Origin(), argument); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), asFloat); root->appendNewControlValue(proc, Return, Origin(), asDouble); CHECK(isIdentical(compileAndRun(proc, value), static_cast(static_cast(value)))); } void testFroundMem(double value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadedDouble = root->appendNew(proc, Load, Double, Origin(), address); Value* asFloat = root->appendNew(proc, DoubleToFloat, Origin(), loadedDouble); Value* asDouble = root->appendNew(proc, FloatToDouble, Origin(), asFloat); root->appendNewControlValue(proc, Return, Origin(), asDouble); CHECK(isIdentical(compileAndRun(proc, &value), static_cast(static_cast(value)))); } void testIToD64Arg() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* srcAsDouble = root->appendNew(proc, IToD, Origin(), src); root->appendNewControlValue(proc, Return, Origin(), srcAsDouble); auto code = compileProc(proc); for (auto testValue : int64Operands()) CHECK(isIdentical(invoke(*code, testValue.value), static_cast(testValue.value))); } void testIToF64Arg() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* srcAsFloat = root->appendNew(proc, IToF, Origin(), src); root->appendNewControlValue(proc, Return, Origin(), srcAsFloat); auto code = compileProc(proc); for (auto testValue : int64Operands()) CHECK(isIdentical(invoke(*code, testValue.value), static_cast(testValue.value))); } void testIToD32Arg() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* srcAsDouble = root->appendNew(proc, IToD, Origin(), src); root->appendNewControlValue(proc, Return, Origin(), srcAsDouble); auto code = compileProc(proc); for (auto testValue : int32Operands()) CHECK(isIdentical(invoke(*code, testValue.value), static_cast(testValue.value))); } void testIToF32Arg() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* srcAsFloat = root->appendNew(proc, IToF, Origin(), src); root->appendNewControlValue(proc, Return, Origin(), srcAsFloat); auto code = compileProc(proc); for (auto testValue : int32Operands()) CHECK(isIdentical(invoke(*code, testValue.value), static_cast(testValue.value))); } void testIToD64Mem() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadedSrc = root->appendNew(proc, Load, Int64, Origin(), address); Value* srcAsDouble = root->appendNew(proc, IToD, Origin(), loadedSrc); root->appendNewControlValue(proc, Return, Origin(), srcAsDouble); auto code = compileProc(proc); int64_t inMemoryValue; for (auto testValue : int64Operands()) { inMemoryValue = testValue.value; CHECK(isIdentical(invoke(*code, &inMemoryValue), static_cast(testValue.value))); CHECK(inMemoryValue == testValue.value); } } void testIToF64Mem() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadedSrc = root->appendNew(proc, Load, Int64, Origin(), address); Value* srcAsFloat = root->appendNew(proc, IToF, Origin(), loadedSrc); root->appendNewControlValue(proc, Return, Origin(), srcAsFloat); auto code = compileProc(proc); int64_t inMemoryValue; for (auto testValue : int64Operands()) { inMemoryValue = testValue.value; CHECK(isIdentical(invoke(*code, &inMemoryValue), static_cast(testValue.value))); CHECK(inMemoryValue == testValue.value); } } void testIToD32Mem() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadedSrc = root->appendNew(proc, Load, Int32, Origin(), address); Value* srcAsDouble = root->appendNew(proc, IToD, Origin(), loadedSrc); root->appendNewControlValue(proc, Return, Origin(), srcAsDouble); auto code = compileProc(proc); int32_t inMemoryValue; for (auto testValue : int32Operands()) { inMemoryValue = testValue.value; CHECK(isIdentical(invoke(*code, &inMemoryValue), static_cast(testValue.value))); CHECK(inMemoryValue == testValue.value); } } void testIToF32Mem() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); MemoryValue* loadedSrc = root->appendNew(proc, Load, Int32, Origin(), address); Value* srcAsFloat = root->appendNew(proc, IToF, Origin(), loadedSrc); root->appendNewControlValue(proc, Return, Origin(), srcAsFloat); auto code = compileProc(proc); int32_t inMemoryValue; for (auto testValue : int32Operands()) { inMemoryValue = testValue.value; CHECK(isIdentical(invoke(*code, &inMemoryValue), static_cast(testValue.value))); CHECK(inMemoryValue == testValue.value); } } void testIToD64Imm(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Origin(), value); Value* srcAsFloatingPoint = root->appendNew(proc, IToD, Origin(), src); root->appendNewControlValue(proc, Return, Origin(), srcAsFloatingPoint); CHECK(isIdentical(compileAndRun(proc), static_cast(value))); } void testIToF64Imm(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Origin(), value); Value* srcAsFloatingPoint = root->appendNew(proc, IToF, Origin(), src); root->appendNewControlValue(proc, Return, Origin(), srcAsFloatingPoint); CHECK(isIdentical(compileAndRun(proc), static_cast(value))); } void testIToD32Imm(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Origin(), value); Value* srcAsFloatingPoint = root->appendNew(proc, IToD, Origin(), src); root->appendNewControlValue(proc, Return, Origin(), srcAsFloatingPoint); CHECK(isIdentical(compileAndRun(proc), static_cast(value))); } void testIToF32Imm(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Origin(), value); Value* srcAsFloatingPoint = root->appendNew(proc, IToF, Origin(), src); root->appendNewControlValue(proc, Return, Origin(), srcAsFloatingPoint); CHECK(isIdentical(compileAndRun(proc), static_cast(value))); } void testIToDReducedToIToF64Arg() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* srcAsDouble = root->appendNew(proc, IToD, Origin(), src); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), srcAsDouble); root->appendNewControlValue(proc, Return, Origin(), floatResult); auto code = compileProc(proc); for (auto testValue : int64Operands()) CHECK(isIdentical(invoke(*code, testValue.value), static_cast(testValue.value))); } void testIToDReducedToIToF32Arg() { Procedure proc; BasicBlock* root = proc.addBlock(); Value* src = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* srcAsDouble = root->appendNew(proc, IToD, Origin(), src); Value* floatResult = root->appendNew(proc, DoubleToFloat, Origin(), srcAsDouble); root->appendNewControlValue(proc, Return, Origin(), floatResult); auto code = compileProc(proc); for (auto testValue : int32Operands()) CHECK(isIdentical(invoke(*code, testValue.value), static_cast(testValue.value))); } void testStore32(int value) { Procedure proc; BasicBlock* root = proc.addBlock(); int slot = 0xbaadbeef; root->appendNew( proc, Store, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), &slot), 0); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Origin(), 0)); CHECK(!compileAndRun(proc, value)); CHECK(slot == value); } void testStoreConstant(int value) { Procedure proc; BasicBlock* root = proc.addBlock(); int slot = 0xbaadbeef; root->appendNew( proc, Store, Origin(), root->appendNew(proc, Origin(), value), root->appendNew(proc, Origin(), &slot), 0); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Origin(), 0)); CHECK(!compileAndRun(proc)); CHECK(slot == value); } void testStoreConstantPtr(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); intptr_t slot; #if CPU(ADDRESS64) slot = (static_cast(0xbaadbeef) << 32) + static_cast(0xbaadbeef); #else slot = 0xbaadbeef; #endif root->appendNew( proc, Store, Origin(), root->appendNew(proc, Origin(), value), root->appendNew(proc, Origin(), &slot), 0); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Origin(), 0)); CHECK(!compileAndRun(proc)); CHECK(slot == value); } void testStore8Arg() { { // Direct addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew(proc, Store8, Origin(), value, address); root->appendNewControlValue(proc, Return, Origin(), value); int8_t storage = 0; CHECK(compileAndRun(proc, 42, &storage) == 42); CHECK(storage == 42); } { // Indexed addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* base = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); Value* offset = root->appendNew(proc, Origin(), GPRInfo::argumentGPR2); Value* displacement = root->appendNew(proc, Origin(), -1); Value* baseDisplacement = root->appendNew(proc, Add, Origin(), displacement, base); Value* address = root->appendNew(proc, Add, Origin(), baseDisplacement, offset); root->appendNew(proc, Store8, Origin(), value, address); root->appendNewControlValue(proc, Return, Origin(), value); int8_t storage = 0; CHECK(compileAndRun(proc, 42, &storage, 1) == 42); CHECK(storage == 42); } } void testStore8Imm() { { // Direct addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew(proc, Origin(), 42); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew(proc, Store8, Origin(), value, address); root->appendNewControlValue(proc, Return, Origin(), value); int8_t storage = 0; CHECK(compileAndRun(proc, &storage) == 42); CHECK(storage == 42); } { // Indexed addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew(proc, Origin(), 42); Value* base = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* offset = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); Value* displacement = root->appendNew(proc, Origin(), -1); Value* baseDisplacement = root->appendNew(proc, Add, Origin(), displacement, base); Value* address = root->appendNew(proc, Add, Origin(), baseDisplacement, offset); root->appendNew(proc, Store8, Origin(), value, address); root->appendNewControlValue(proc, Return, Origin(), value); int8_t storage = 0; CHECK(compileAndRun(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(proc, Origin(), GPRInfo::argumentGPR0); // We want this suck in EDX. Value* whereToStore = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); // The patch point is there to help us force the hand of the compiler. PatchpointValue* patchpoint = root->appendNew(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(proc, Store8, Origin(), patchpoint, whereToStore); root->appendNewControlValue(proc, Return, Origin(), returnValue); int8_t storage = 0xff; CHECK(compileAndRun(proc, 0x12345678abcdef12, &storage) == 0x12345678abcdef12); CHECK(!storage); } void testStore16Arg() { { // Direct addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); root->appendNew(proc, Store16, Origin(), value, address); root->appendNewControlValue(proc, Return, Origin(), value); int16_t storage = -1; CHECK(compileAndRun(proc, 42, &storage) == 42); CHECK(storage == 42); } { // Indexed addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew(proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)); Value* base = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); Value* offset = root->appendNew(proc, Origin(), GPRInfo::argumentGPR2); Value* displacement = root->appendNew(proc, Origin(), -1); Value* baseDisplacement = root->appendNew(proc, Add, Origin(), displacement, base); Value* address = root->appendNew(proc, Add, Origin(), baseDisplacement, offset); root->appendNew(proc, Store16, Origin(), value, address); root->appendNewControlValue(proc, Return, Origin(), value); int16_t storage = -1; CHECK(compileAndRun(proc, 42, &storage, 1) == 42); CHECK(storage == 42); } } void testStore16Imm() { { // Direct addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew(proc, Origin(), 42); Value* address = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); root->appendNew(proc, Store16, Origin(), value, address); root->appendNewControlValue(proc, Return, Origin(), value); int16_t storage = -1; CHECK(compileAndRun(proc, &storage) == 42); CHECK(storage == 42); } { // Indexed addressing. Procedure proc; BasicBlock* root = proc.addBlock(); Value* value = root->appendNew(proc, Origin(), 42); Value* base = root->appendNew(proc, Origin(), GPRInfo::argumentGPR0); Value* offset = root->appendNew(proc, Origin(), GPRInfo::argumentGPR1); Value* displacement = root->appendNew(proc, Origin(), -1); Value* baseDisplacement = root->appendNew(proc, Add, Origin(), displacement, base); Value* address = root->appendNew(proc, Add, Origin(), baseDisplacement, offset); root->appendNew(proc, Store16, Origin(), value, address); root->appendNewControlValue(proc, Return, Origin(), value); int16_t storage = -1; CHECK(compileAndRun(proc, &storage, 1) == 42); CHECK(storage == 42); } } void testTrunc(int64_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))); CHECK(compileAndRun(proc, value) == static_cast(value)); } void testAdd1(int value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Add, Origin(), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)), root->appendNew(proc, Origin(), 1))); CHECK(compileAndRun(proc, value) == value + 1); } void testAdd1Ptr(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Add, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0), root->appendNew(proc, Origin(), 1))); CHECK(compileAndRun(proc, value) == value + 1); } void testNeg32(int32_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Sub, Origin(), root->appendNew(proc, Origin(), 0), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0)))); CHECK(compileAndRun(proc, value) == -value); } void testNegPtr(intptr_t value) { Procedure proc; BasicBlock* root = proc.addBlock(); root->appendNewControlValue( proc, Return, Origin(), root->appendNew( proc, Sub, Origin(), root->appendNew(proc, Origin(), 0), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))); CHECK(compileAndRun(proc, value) == -value); } void testStoreAddLoad32(int amount) { Procedure proc; BasicBlock* root = proc.addBlock(); int slot = 37; ConstPtrValue* slotPtr = root->appendNew(proc, Origin(), &slot); root->appendNew( proc, Store, Origin(), root->appendNew( proc, Add, Origin(), root->appendNew(proc, Load, Int32, Origin(), slotPtr), root->appendNew( proc, Trunc, Origin(), root->appendNew(proc, Origin(), GPRInfo::argumentGPR0))), slotPtr, 0); root->appendNewControlValue( proc, Return, Origin(), root->appendNew(proc, Origin(), 0)); CHECK(!compileAndRun(proc, amount)); CHECK(slot == 37 + amount); } // Make sure the compiler does not try to optimize anything out. static NEVER_INLINE double zero() { return 0.; } static double negativeZero() { return -zero(); } void addArgTests(const char* filter, Deque>>& tasks) { 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_BINARY(testAddNeg1, int32Operands(), int32Operands()); RUN_BINARY(testAddNeg2, int32Operands(), int32Operands()); RUN(testAddArgZeroImmZDef()); RUN(testAddLoadTwice()); RUN_TERNARY(testAddMulMulArgs, int64Operands(), int64Operands(), int64Operands()); 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()); RUN_BINARY(testAddArgsFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testAddFPRArgsFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testAddArgImmFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testAddImmArgFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testAddImmsFloat, floatingPointOperands(), floatingPointOperands()); RUN_UNARY(testAddArgFloatWithUselessDoubleConversion, floatingPointOperands()); RUN_BINARY(testAddArgsFloatWithUselessDoubleConversion, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testAddArgsFloatWithEffectfulDoubleConversion, floatingPointOperands(), floatingPointOperands()); 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(testMulImm32SignExtend(1, 2)); RUN(testMulImm32SignExtend(0, 2)); RUN(testMulImm32SignExtend(1, 0)); RUN(testMulImm32SignExtend(3, 3)); RUN(testMulImm32SignExtend(0xFFFFFFFF, 0xFFFFFFFF)); RUN(testMulImm32SignExtend(0xFFFFFFFE, 0xFFFFFFFF)); RUN(testMulImm32SignExtend(0xFFFFFFFF, 0xFFFFFFFE)); RUN(testMulArgs32(1, 1)); RUN(testMulArgs32(1, 2)); RUN(testMulArgs32(0xFFFFFFFF, 0xFFFFFFFF)); RUN(testMulArgs32(0xFFFFFFFE, 0xFFFFFFFF)); RUN(testMulArgs32SignExtend(1, 1)); RUN(testMulArgs32SignExtend(1, 2)); RUN(testMulArgs32SignExtend(0xFFFFFFFF, 0xFFFFFFFF)); RUN(testMulArgs32SignExtend(0xFFFFFFFE, 0xFFFFFFFF)); RUN(testMulLoadTwice()); RUN(testMulAddArgsLeft()); RUN(testMulAddArgsRight()); RUN(testMulAddArgsLeft32()); RUN(testMulAddArgsRight32()); RUN(testMulSubArgsLeft()); RUN(testMulSubArgsRight()); RUN(testMulSubArgsLeft32()); RUN(testMulSubArgsRight32()); RUN(testMulNegArgs()); RUN(testMulNegArgs32()); RUN_BINARY(testMulArgNegArg, int64Operands(), int64Operands()) RUN_BINARY(testMulNegArgArg, int64Operands(), int64Operands()) RUN_UNARY(testMulArgDouble, floatingPointOperands()); RUN_BINARY(testMulArgsDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testMulArgImmDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testMulImmArgDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testMulImmsDouble, floatingPointOperands(), floatingPointOperands()); RUN_UNARY(testMulArgFloat, floatingPointOperands()); RUN_BINARY(testMulArgsFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testMulArgImmFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testMulImmArgFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testMulImmsFloat, floatingPointOperands(), floatingPointOperands()); RUN_UNARY(testMulArgFloatWithUselessDoubleConversion, floatingPointOperands()); RUN_BINARY(testMulArgsFloatWithUselessDoubleConversion, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testMulArgsFloatWithEffectfulDoubleConversion, floatingPointOperands(), floatingPointOperands()); 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()); RUN_BINARY(testDivArgsFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testDivArgImmFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testDivImmArgFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testDivImmsFloat, floatingPointOperands(), floatingPointOperands()); RUN_UNARY(testDivArgFloatWithUselessDoubleConversion, floatingPointOperands()); RUN_BINARY(testDivArgsFloatWithUselessDoubleConversion, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testDivArgsFloatWithEffectfulDoubleConversion, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testUDivArgsInt32, int32Operands(), int32Operands()); RUN_BINARY(testUDivArgsInt64, int64Operands(), int64Operands()); RUN_UNARY(testModArgDouble, floatingPointOperands()); RUN_BINARY(testModArgsDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testModArgImmDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testModImmArgDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testModImmsDouble, floatingPointOperands(), floatingPointOperands()); RUN_UNARY(testModArgFloat, floatingPointOperands()); RUN_BINARY(testModArgsFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testModArgImmFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testModImmArgFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testModImmsFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testUModArgsInt32, int32Operands(), int32Operands()); RUN_BINARY(testUModArgsInt64, int64Operands(), int64Operands()); 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_BINARY(testSubNeg, int32Operands(), int32Operands()); RUN_BINARY(testNegSub, int32Operands(), int32Operands()); RUN_UNARY(testNegValueSubOne, int32Operands()); RUN_BINARY(testNegMulArgImm, int64Operands(), int64Operands()); RUN_TERNARY(testSubMulMulArgs, int64Operands(), int64Operands(), int64Operands()); RUN_TERNARY(testSubSub, int32Operands(), int32Operands(), int32Operands()); RUN_TERNARY(testSubSub2, int32Operands(), int32Operands(), int32Operands()); RUN_TERNARY(testSubAdd, int32Operands(), int32Operands(), int32Operands()); RUN_BINARY(testSubFirstNeg, int32Operands(), 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()); RUN_BINARY(testSubArgsDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testSubArgImmDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testSubImmArgDouble, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testSubImmsDouble, floatingPointOperands(), floatingPointOperands()); RUN_UNARY(testSubArgFloat, floatingPointOperands()); RUN_BINARY(testSubArgsFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testSubArgImmFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testSubImmArgFloat, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testSubImmsFloat, floatingPointOperands(), floatingPointOperands()); RUN_UNARY(testSubArgFloatWithUselessDoubleConversion, floatingPointOperands()); RUN_BINARY(testSubArgsFloatWithUselessDoubleConversion, floatingPointOperands(), floatingPointOperands()); RUN_BINARY(testSubArgsFloatWithEffectfulDoubleConversion, floatingPointOperands(), floatingPointOperands()); } void addCallTests(const char* filter, Deque>>& tasks) { RUN(testCallSimple(1, 2)); RUN(testCallRare(1, 2)); RUN(testCallRareLive(1, 2, 3)); RUN(testCallSimplePure(1, 2)); RUN(testCallFunctionWithHellaArguments()); RUN(testCallFunctionWithHellaArguments2()); RUN(testCallFunctionWithHellaArguments3()); RUN(testReturnDouble(0.0)); RUN(testReturnDouble(negativeZero())); RUN(testReturnDouble(42.5)); RUN_UNARY(testReturnFloat, floatingPointOperands()); RUN(testCallSimpleDouble(1, 2)); RUN(testCallFunctionWithHellaDoubleArguments()); RUN_BINARY(testCallSimpleFloat, floatingPointOperands(), floatingPointOperands()); RUN(testCallFunctionWithHellaFloatArguments()); } void addShrTests(const char* filter, Deque>>& tasks) { 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)); } #endif // ENABLE(B3_JIT)