blob: c10bd64b6c9362e6b1cedfd754a3cc6deadb0970 [file] [log] [blame]
/*
* 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"
#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) {
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 (!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)