|  | /* | 
|  | * Copyright (C) 2015-2020 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 "B3LowerMacrosAfterOptimizations.h" | 
|  |  | 
|  | #if ENABLE(B3_JIT) | 
|  |  | 
|  | #include "AirArg.h" | 
|  | #include "B3BlockInsertionSet.h" | 
|  | #include "B3CCallValue.h" | 
|  | #include "B3ConstDoubleValue.h" | 
|  | #include "B3ConstFloatValue.h" | 
|  | #include "B3ConstPtrValue.h" | 
|  | #include "B3InsertionSetInlines.h" | 
|  | #include "B3PhaseScope.h" | 
|  | #include "B3ValueInlines.h" | 
|  |  | 
|  | namespace JSC { namespace B3 { | 
|  |  | 
|  | using Arg = Air::Arg; | 
|  | using Code = Air::Code; | 
|  | using Tmp = Air::Tmp; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class LowerMacrosAfterOptimizations { | 
|  | public: | 
|  | LowerMacrosAfterOptimizations(Procedure& proc) | 
|  | : m_proc(proc) | 
|  | , m_blockInsertionSet(proc) | 
|  | , m_insertionSet(proc) | 
|  | { | 
|  | } | 
|  |  | 
|  | bool run() | 
|  | { | 
|  | for (BasicBlock* block : m_proc) { | 
|  | m_block = block; | 
|  | processCurrentBlock(); | 
|  | } | 
|  | m_changed |= m_blockInsertionSet.execute(); | 
|  | if (m_changed) { | 
|  | m_proc.resetReachability(); | 
|  | m_proc.invalidateCFG(); | 
|  | } | 
|  | return m_changed; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void processCurrentBlock() | 
|  | { | 
|  | for (m_index = 0; m_index < m_block->size(); ++m_index) { | 
|  | m_value = m_block->at(m_index); | 
|  | m_origin = m_value->origin(); | 
|  | switch (m_value->opcode()) { | 
|  | case Abs: { | 
|  | // ARM supports this instruction natively. | 
|  | if (isARM64()) | 
|  | break; | 
|  |  | 
|  | Value* mask = nullptr; | 
|  | if (m_value->type() == Double) | 
|  | mask = m_insertionSet.insert<ConstDoubleValue>(m_index, m_origin, bitwise_cast<double>(~(1ll << 63))); | 
|  | else if (m_value->type() == Float) | 
|  | mask = m_insertionSet.insert<ConstFloatValue>(m_index, m_origin, bitwise_cast<float>(~(1 << 31))); | 
|  | else | 
|  | RELEASE_ASSERT_NOT_REACHED(); | 
|  | Value* result = m_insertionSet.insert<Value>(m_index, BitAnd, m_origin, m_value->child(0), mask); | 
|  | m_value->replaceWithIdentity(result); | 
|  | break; | 
|  | } | 
|  | case Ceil: { | 
|  | if (MacroAssembler::supportsFloatingPointRounding()) | 
|  | break; | 
|  |  | 
|  | Value* functionAddress = nullptr; | 
|  | if (m_value->type() == Double) | 
|  | functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunction<OperationPtrTag>(Math::ceilDouble)); | 
|  | else if (m_value->type() == Float) | 
|  | functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunction<OperationPtrTag>(Math::ceilFloat)); | 
|  | else | 
|  | RELEASE_ASSERT_NOT_REACHED(); | 
|  |  | 
|  | Value* result = m_insertionSet.insert<CCallValue>(m_index, | 
|  | m_value->type(), | 
|  | m_origin, | 
|  | Effects::none(), | 
|  | functionAddress, | 
|  | m_value->child(0)); | 
|  | m_value->replaceWithIdentity(result); | 
|  | break; | 
|  | } | 
|  | case Floor: { | 
|  | if (MacroAssembler::supportsFloatingPointRounding()) | 
|  | break; | 
|  |  | 
|  | Value* functionAddress = nullptr; | 
|  | if (m_value->type() == Double) | 
|  | functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunction<OperationPtrTag>(Math::floorDouble)); | 
|  | else if (m_value->type() == Float) | 
|  | functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunction<OperationPtrTag>(Math::floorFloat)); | 
|  | else | 
|  | RELEASE_ASSERT_NOT_REACHED(); | 
|  |  | 
|  | Value* result = m_insertionSet.insert<CCallValue>(m_index, | 
|  | m_value->type(), | 
|  | m_origin, | 
|  | Effects::none(), | 
|  | functionAddress, | 
|  | m_value->child(0)); | 
|  | m_value->replaceWithIdentity(result); | 
|  | break; | 
|  | } | 
|  | case Neg: { | 
|  | if (!m_value->type().isFloat()) | 
|  | break; | 
|  |  | 
|  | // X86 is odd in that it requires this. | 
|  | if (!isX86()) | 
|  | break; | 
|  |  | 
|  | Value* mask = nullptr; | 
|  | if (m_value->type() == Double) | 
|  | mask = m_insertionSet.insert<ConstDoubleValue>(m_index, m_origin, -0.0); | 
|  | else { | 
|  | RELEASE_ASSERT(m_value->type() == Float); | 
|  | mask = m_insertionSet.insert<ConstFloatValue>(m_index, m_origin, -0.0f); | 
|  | } | 
|  |  | 
|  | Value* result = m_insertionSet.insert<Value>( | 
|  | m_index, BitXor, m_origin, m_value->child(0), mask); | 
|  | m_value->replaceWithIdentity(result); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case RotL: { | 
|  | // ARM64 doesn't have a rotate left. | 
|  | if (isARM64()) { | 
|  | Value* newShift = m_insertionSet.insert<Value>(m_index, Neg, m_value->origin(), m_value->child(1)); | 
|  | Value* rotate = m_insertionSet.insert<Value>(m_index, RotR, m_value->origin(), m_value->child(0), newShift); | 
|  | m_value->replaceWithIdentity(rotate); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | m_insertionSet.execute(m_block); | 
|  | } | 
|  |  | 
|  | Procedure& m_proc; | 
|  | BlockInsertionSet m_blockInsertionSet; | 
|  | InsertionSet m_insertionSet; | 
|  | BasicBlock* m_block; | 
|  | unsigned m_index; | 
|  | Value* m_value; | 
|  | Origin m_origin; | 
|  | bool m_changed { false }; | 
|  | }; | 
|  |  | 
|  | bool lowerMacrosImpl(Procedure& proc) | 
|  | { | 
|  | LowerMacrosAfterOptimizations lowerMacros(proc); | 
|  | return lowerMacros.run(); | 
|  | } | 
|  |  | 
|  | } // anonymous namespace | 
|  |  | 
|  | bool lowerMacrosAfterOptimizations(Procedure& proc) | 
|  | { | 
|  | PhaseScope phaseScope(proc, "lowerMacrosAfterOptimizations"); | 
|  | bool result = lowerMacrosImpl(proc); | 
|  | if (shouldValidateIR()) | 
|  | RELEASE_ASSERT(!lowerMacrosImpl(proc)); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | } } // namespace JSC::B3 | 
|  |  | 
|  | #endif // ENABLE(B3_JIT) | 
|  |  |