/* * 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 Floor: 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 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)