/* * Copyright (C) 2015-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "B3LowerMacrosAfterOptimizations.h" #if ENABLE(B3_JIT) #include "B3BasicBlockInlines.h" #include "B3BlockInsertionSet.h" #include "B3CCallValue.h" #include "B3ConstDoubleValue.h" #include "B3ConstFloatValue.h" #include "B3ConstPtrValue.h" #include "B3InsertionSetInlines.h" #include "B3PhaseScope.h" namespace JSC { namespace B3 { namespace { class LowerMacros { public: LowerMacros(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(m_index, m_origin, bitwise_cast(~(1ll << 63))); else if (m_value->type() == Float) mask = m_insertionSet.insert(m_index, m_origin, bitwise_cast(~(1 << 31))); else RELEASE_ASSERT_NOT_REACHED(); Value* result = m_insertionSet.insert(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) { double (*ceilDouble)(double) = ceil; functionAddress = m_insertionSet.insert(m_index, m_origin, ceilDouble); } else if (m_value->type() == Float) functionAddress = m_insertionSet.insert(m_index, m_origin, ceilf); else RELEASE_ASSERT_NOT_REACHED(); Value* result = m_insertionSet.insert(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) { double (*floorDouble)(double) = floor; functionAddress = m_insertionSet.insert(m_index, m_origin, floorDouble); } else if (m_value->type() == Float) functionAddress = m_insertionSet.insert(m_index, m_origin, floorf); else RELEASE_ASSERT_NOT_REACHED(); Value* result = m_insertionSet.insert(m_index, m_value->type(), m_origin, Effects::none(), functionAddress, m_value->child(0)); m_value->replaceWithIdentity(result); break; } case Neg: { if (!isFloat(m_value->type())) break; // X86 is odd in that it requires this. if (!isX86()) break; Value* mask = nullptr; if (m_value->type() == Double) mask = m_insertionSet.insert(m_index, m_origin, -0.0); else { RELEASE_ASSERT(m_value->type() == Float); mask = m_insertionSet.insert(m_index, m_origin, -0.0f); } Value* result = m_insertionSet.insert( m_index, BitXor, m_origin, m_value->child(0), mask); m_value->replaceWithIdentity(result); 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) { LowerMacros 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)