| /* |
| * Copyright (C) 2015-2018 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 "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 { |
| |
| 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) { |
| double (*ceilDouble)(double) = ceil; |
| functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunctionPtr(ceilDouble, B3CCallPtrTag)); |
| } else if (m_value->type() == Float) |
| functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunctionPtr(ceilf, B3CCallPtrTag)); |
| 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) { |
| double (*floorDouble)(double) = floor; |
| functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunctionPtr(floorDouble, B3CCallPtrTag)); |
| } else if (m_value->type() == Float) |
| functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunctionPtr(floorf, B3CCallPtrTag)); |
| 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 (!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<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) |
| |