blob: cb41f74ba1c3773ddcd3bd3fae0d90efe7b0ecda [file] [log] [blame]
/*
* Copyright (C) 2015 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 "B3ReduceDoubleToFloat.h"
#if ENABLE(B3_JIT)
#include "B3BasicBlock.h"
#include "B3PhaseScope.h"
#include "B3ValueInlines.h"
namespace JSC { namespace B3 {
namespace {
void attemptSimplification(Value* candidate)
{
switch (candidate->opcode()) {
case Add:
case Sub:
case Mul:
case Div:
if (candidate->child(0)->opcode() == FloatToDouble && candidate->child(1)->opcode() == FloatToDouble) {
candidate->child(0) = candidate->child(0)->child(0);
candidate->child(1) = candidate->child(1)->child(0);
candidate->setType(Float);
}
break;
case Abs:
case Ceil:
case Sqrt:
if (candidate->child(0)->opcode() == FloatToDouble) {
candidate->child(0) = candidate->child(0)->child(0);
candidate->setType(Float);
}
break;
default:
break;
}
}
} // namespace
// The goal of this phase is to transform Double operations
// into float if the Double result is never used as Double.
//
// In C, that would be something like:
// float add(float a, float b) {
// return (double)a + (double)b;
// }
//
// Such operation arise in JS because there are is no Float type
// and float operations are generated by adding double-to-float rounding.
//
// The operations can be done entirely without Double conversion.
// Using float in place remove the useless conversion, and the float
// ops is sometime massively cheaper (SQRT for example).
//
// If the Double value is used as Double, we do not do the conversion.
// It is cheaper to do a conversion than repeat any floating-point operation.
void reduceDoubleToFloat(Procedure& procedure)
{
// FIXME: We should tune this phase for performance and make it part of ReduceStrength.
// ReduceStrength can eliminate nodes that prevents us from simplifying operations.
PhaseScope phaseScope(procedure, "reduceDoubleToFloat");
HashSet<Value*> candidates;
// First, we find any value that is converted to float
// and only used as float.
// We also simplify comparisons since that's always safe and we
// don't want them to appear in the next loop.
for (BasicBlock* block : procedure) {
for (Value* value : *block) {
value->performSubstitution();
switch (value->opcode()) {
case DoubleToFloat:
candidates.add(value->child(0));
break;
case Equal:
case NotEqual:
case LessThan:
case GreaterThan:
case LessEqual:
case GreaterEqual:
case EqualOrUnordered:
if (value->child(0)->opcode() == FloatToDouble && value->child(1)->opcode() == FloatToDouble) {
value->child(0) = value->child(0)->child(0);
value->child(1) = value->child(1)->child(0);
}
break;
default:
break;
}
}
}
for (BasicBlock* block : procedure) {
for (Value* value : *block) {
if (value->opcode() == DoubleToFloat)
continue;
for (Value* child : value->children()) {
if (child->type() == Double)
candidates.remove(child);
}
}
}
if (candidates.isEmpty())
return;
// Second, we go over the candidates and attempt to simplify them.
// This leaves the graph in an invalid state where Float Values are
// used by DoubleToFloat Values. This is only temporary.
for (Value* candidate : candidates)
attemptSimplification(candidate);
// Finally, remove the DoubleToFloat made useless by the simplifications.
for (BasicBlock* block : procedure) {
for (Value* value : *block) {
if (value->opcode() == DoubleToFloat && value->child(0)->type() == Float)
value->replaceWithIdentity(value->child(0));
}
}
// We do not clean all the useless nodes and conversions. ReduceStrength does that better.
}
} } // namespace JSC::B3
#endif // ENABLE(B3_JIT)