B3ReduceDoubleToFloat.cpp [plain text]
#include "config.h"
#include "B3ReduceDoubleToFloat.h"
#if ENABLE(B3_JIT)
#include "B3BasicBlock.h"
#include "B3IndexSet.h"
#include "B3InsertionSetInlines.h"
#include "B3PhaseScope.h"
#include "B3UseCounts.h"
#include "B3ValueInlines.h"
namespace JSC { namespace B3 {
namespace {
bool verbose = false;
bool printRemainingConversions = false;
class DoubleToFloatReduction {
public:
DoubleToFloatReduction(Procedure& procedure)
: m_procedure(procedure)
{
}
void run()
{
if (!findCandidates())
return;
findPhisContainingFloat();
simplify();
cleanUp();
}
private:
bool findCandidates()
{
bool foundConversionCandidate = false;
Vector<Value*, 32> upsilons;
for (BasicBlock* block : m_procedure) {
for (Value* value : *block) {
value->performSubstitution();
if (value->opcode() == DoubleToFloat) {
foundConversionCandidate = true;
Value* child = value->child(0);
if (child->opcode() == FloatToDouble) {
value->replaceWithIdentity(child->child(0));
}
continue;
}
if (value->opcode() == FloatToDouble)
foundConversionCandidate = true;
if (value->opcode() == Upsilon) {
Value* child = value->child(0);
if (child->type() == Double)
upsilons.append(value);
continue;
}
for (Value* child : value->children()) {
if (child->type() == Double)
m_valuesUsedAsDouble.add(child);
}
}
}
if (!foundConversionCandidate)
return false;
bool changedPhiState;
do {
changedPhiState = false;
for (Value* value : upsilons) {
UpsilonValue* upsilon = value->as<UpsilonValue>();
Value* phi = upsilon->phi();
if (!m_valuesUsedAsDouble.contains(phi))
continue;
Value* child = value->child(0);
bool childChanged = m_valuesUsedAsDouble.add(child);
if (childChanged && child->opcode() == Phi)
changedPhiState = true;
}
} while (changedPhiState);
if (verbose) {
dataLog("Conversion candidates:\n");
for (BasicBlock* block : m_procedure) {
for (Value* value : *block) {
if (value->type() == Double && !m_valuesUsedAsDouble.contains(value))
dataLog(" ", deepDump(m_procedure, value), "\n");
}
}
dataLog("\n");
}
return true;
}
void findPhisContainingFloat()
{
Vector<Value*, 32> upsilons;
for (BasicBlock* block : m_procedure) {
for (Value* value : *block) {
if (value->opcode() != Upsilon)
continue;
Value* child = value->child(0);
if (child->type() != Double
|| child->opcode() == FloatToDouble)
continue;
if (child->hasDouble()) {
double constValue = child->asDouble();
if (isIdentical(static_cast<double>(static_cast<float>(constValue)), constValue))
continue;
}
if (child->opcode() == Phi) {
upsilons.append(value);
continue;
}
UpsilonValue* upsilon = value->as<UpsilonValue>();
Value* phi = upsilon->phi();
m_phisContainingDouble.add(phi);
}
}
bool changedPhiState;
do {
changedPhiState = false;
for (Value* value : upsilons) {
Value* child = value->child(0);
if (m_phisContainingDouble.contains(child)) {
UpsilonValue* upsilon = value->as<UpsilonValue>();
Value* phi = upsilon->phi();
changedPhiState |= m_phisContainingDouble.add(phi);
}
}
} while (changedPhiState);
if (verbose) {
dataLog("Phis containing float values:\n");
for (BasicBlock* block : m_procedure) {
for (Value* value : *block) {
if (value->opcode() == Phi
&& value->type() == Double
&& !m_phisContainingDouble.contains(value))
dataLog(" ", deepDump(m_procedure, value), "\n");
}
}
dataLog("\n");
}
}
bool canBeTransformedToFloat(Value* value)
{
if (value->opcode() == FloatToDouble)
return true;
if (value->hasDouble())
return true;
if (value->opcode() == Phi) {
return value->type() == Float
|| (value->type() == Double && !m_phisContainingDouble.contains(value));
}
return false;
}
Value* transformToFloat(Value* value, unsigned valueIndex, InsertionSet& insertionSet)
{
ASSERT(canBeTransformedToFloat(value));
if (value->opcode() == FloatToDouble)
return value->child(0);
if (value->hasDouble())
return insertionSet.insert<ConstFloatValue>(valueIndex, value->origin(), static_cast<float>(value->asDouble()));
if (value->opcode() == Phi) {
convertPhi(value);
return value;
}
RELEASE_ASSERT_NOT_REACHED();
return nullptr;
}
void convertPhi(Value* phi)
{
ASSERT(phi->opcode() == Phi);
phi->setType(Float);
m_convertedPhis.add(phi);
}
bool attemptTwoOperandsSimplify(Value* candidate, unsigned candidateIndex, InsertionSet& insertionSet)
{
Value* left = candidate->child(0);
Value* right = candidate->child(1);
if (!canBeTransformedToFloat(left) || !canBeTransformedToFloat(right))
return false;
m_convertedValue.add(candidate);
candidate->child(0) = transformToFloat(left, candidateIndex, insertionSet);
candidate->child(1) = transformToFloat(right, candidateIndex, insertionSet);
return true;
}
void simplify()
{
Vector<Value*, 32> upsilonReferencingDoublePhi;
InsertionSet insertionSet(m_procedure);
for (BasicBlock* block : m_procedure) {
for (unsigned index = 0; index < block->size(); ++index) {
Value* value = block->at(index);
switch (value->opcode()) {
case Equal:
case NotEqual:
case LessThan:
case GreaterThan:
case LessEqual:
case GreaterEqual:
case EqualOrUnordered:
attemptTwoOperandsSimplify(value, index, insertionSet);
continue;
case Upsilon: {
Value* child = value->child(0);
if (child->opcode() == Phi && child->type() == Double)
upsilonReferencingDoublePhi.append(value);
continue;
}
default:
break;
}
if (m_valuesUsedAsDouble.contains(value))
continue;
switch (value->opcode()) {
case Add:
case Sub:
case Mul:
case Div:
if (attemptTwoOperandsSimplify(value, index, insertionSet))
value->setType(Float);
break;
case Abs:
case Ceil:
case Floor:
case Sqrt: {
Value* child = value->child(0);
if (canBeTransformedToFloat(child)) {
value->child(0) = transformToFloat(child, index, insertionSet);
value->setType(Float);
m_convertedValue.add(value);
}
break;
}
case IToD: {
Value* iToF = insertionSet.insert<Value>(index, IToF, value->origin(), value->child(0));
value->setType(Float);
value->replaceWithIdentity(iToF);
m_convertedValue.add(value);
break;
}
case FloatToDouble:
value->setType(Float);
value->replaceWithIdentity(value->child(0));
m_convertedValue.add(value);
break;
case Phi:
if (value->type() == Double)
convertPhi(value);
break;
default:
break;
}
}
insertionSet.execute(block);
}
if (!upsilonReferencingDoublePhi.isEmpty()) {
bool changedPhi;
do {
changedPhi = false;
for (Value* value : upsilonReferencingDoublePhi) {
UpsilonValue* upsilon = value->as<UpsilonValue>();
Value* child = value->child(0);
Value* phi = upsilon->phi();
if (phi->type() == Float && child->type() == Double
&& !m_phisContainingDouble.contains(child)) {
convertPhi(child);
changedPhi = true;
}
}
} while (changedPhi);
}
}
void cleanUp()
{
InsertionSet insertionSet(m_procedure);
for (BasicBlock* block : m_procedure) {
for (unsigned index = 0; index < block->size(); ++index) {
Value* value = block->at(index);
if (value->opcode() == DoubleToFloat && value->child(0)->type() == Float) {
value->replaceWithIdentity(value->child(0));
continue;
}
if (value->opcode() == Upsilon) {
UpsilonValue* upsilon = value->as<UpsilonValue>();
Value* child = value->child(0);
Value* phi = upsilon->phi();
if (phi->type() == Float) {
if (child->type() == Double) {
Value* newChild = nullptr;
if (child->opcode() == FloatToDouble)
newChild = child->child(0);
else if (child->hasDouble())
newChild = insertionSet.insert<ConstFloatValue>(index, child->origin(), static_cast<float>(child->asDouble()));
else
newChild = insertionSet.insert<Value>(index, DoubleToFloat, upsilon->origin(), child);
upsilon->child(0) = newChild;
}
continue;
}
}
if (!m_convertedValue.contains(value)) {
for (Value*& child : value->children()) {
if (m_convertedPhis.contains(child))
child = insertionSet.insert<Value>(index, FloatToDouble, value->origin(), child);
}
}
}
insertionSet.execute(block);
}
}
Procedure& m_procedure;
IndexSet<Value> m_valuesUsedAsDouble;
IndexSet<Value> m_phisContainingDouble;
IndexSet<Value> m_convertedValue;
IndexSet<Value> m_convertedPhis;
};
void printGraphIfConverting(Procedure& procedure)
{
if (!printRemainingConversions)
return;
UseCounts useCount(procedure);
Vector<Value*> doubleToFloat;
Vector<Value*> floatToDouble;
for (BasicBlock* block : procedure) {
for (Value* value : *block) {
if (!useCount.numUses(value))
continue;
if (value->opcode() == DoubleToFloat)
doubleToFloat.append(value);
if (value->opcode() == FloatToDouble)
floatToDouble.append(value);
}
}
if (doubleToFloat.isEmpty() && floatToDouble.isEmpty())
return;
dataLog("Procedure with Float-Double conversion:\n", procedure, "\n");
dataLog("Converting nodes:\n");
for (Value* value : doubleToFloat)
dataLog(" ", deepDump(procedure, value), "\n");
for (Value* value : floatToDouble)
dataLog(" ", deepDump(procedure, value), "\n");
}
}
void reduceDoubleToFloat(Procedure& procedure)
{
PhaseScope phaseScope(procedure, "reduceDoubleToFloat");
if (verbose)
dataLog("Before DoubleToFloatReduction:\n", procedure, "\n");
DoubleToFloatReduction doubleToFloatReduction(procedure);
doubleToFloatReduction.run();
if (verbose)
dataLog("After DoubleToFloatReduction:\n", procedure, "\n");
printGraphIfConverting(procedure);
}
} }
#endif // ENABLE(B3_JIT)