Commit c7685a59 authored by jarin@chromium.org's avatar jarin@chromium.org

[turbofan] Use range types to type and lower arithmetic ops.

This is based on Georg's work on typing arithmetic operations (https://codereview.chromium.org/658743002/).

Instead of weakening to bitset types, we weaken to the closest 2^n
limit if we see that we are re-typing a node with a range type (which
means that the node can be part of a cycle, so we might need
to speed up the fixpoint there).

BUG=
R=rossberg@chromium.org

Review URL: https://codereview.chromium.org/636283009

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24848 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a8ff27ab
......@@ -216,6 +216,37 @@ class RepresentationChanger {
}
}
Node* GetTruncatedWord32For(Node* node, MachineTypeUnion output_type) {
// Eagerly fold truncations for constants.
switch (node->opcode()) {
case IrOpcode::kInt32Constant:
return node; // No change necessary.
case IrOpcode::kFloat32Constant:
return jsgraph()->Int32Constant(
DoubleToInt32(OpParameter<float>(node)));
case IrOpcode::kNumberConstant:
case IrOpcode::kFloat64Constant:
return jsgraph()->Int32Constant(
DoubleToInt32(OpParameter<double>(node)));
default:
break;
}
// Select the correct X -> Word32 truncation operator.
const Operator* op = NULL;
if (output_type & kRepFloat64) {
op = machine()->TruncateFloat64ToInt32();
} else if (output_type & kRepFloat32) {
node = InsertChangeFloat32ToFloat64(node);
op = machine()->TruncateFloat64ToInt32();
} else if (output_type & kRepTagged) {
node = InsertChangeTaggedToFloat64(node);
op = machine()->TruncateFloat64ToInt32();
} else {
return TypeError(node, output_type, kRepWord32);
}
return jsgraph()->graph()->NewNode(op, node);
}
Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
bool use_unsigned) {
// Eagerly fold representation changes for constants.
......@@ -421,6 +452,11 @@ class RepresentationChanger {
node);
}
Node* InsertChangeTaggedToFloat64(Node* node) {
return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
node);
}
JSGraph* jsgraph() { return jsgraph_; }
Isolate* isolate() { return isolate_; }
SimplifiedOperatorBuilder* simplified() { return simplified_; }
......
......@@ -74,6 +74,10 @@ class RepresentationSelector {
changer_(changer),
queue_(zone) {
memset(info_, 0, sizeof(NodeInfo) * count_);
Factory* f = zone->isolate()->factory();
safe_int_additive_range_ =
Type::Range(f->NewNumber(-pow(2, 52)), f->NewNumber(pow(2, 52)), zone);
}
void Run(SimplifiedLowering* lowering) {
......@@ -167,6 +171,30 @@ class RepresentationSelector {
NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type);
}
void ProcessTruncateWord32Input(Node* node, int index, MachineTypeUnion use) {
Node* input = node->InputAt(index);
if (phase_ == PROPAGATE) {
// In the propagate phase, propagate the usage information backward.
Enqueue(input, use);
} else {
// In the change phase, insert a change before the use if necessary.
MachineTypeUnion output = GetInfo(input)->output;
if ((output & kRepWord32) == 0) {
// Output representation doesn't match usage.
TRACE((" truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(),
node->op()->mnemonic(), index, input->id(),
input->op()->mnemonic()));
TRACE((" from "));
PrintInfo(output);
TRACE((" to "));
PrintInfo(use);
TRACE(("\n"));
Node* n = changer_->GetTruncatedWord32For(input, output);
node->ReplaceInput(index, n);
}
}
}
void ProcessInput(Node* node, int index, MachineTypeUnion use) {
Node* input = node->InputAt(index);
if (phase_ == PROPAGATE) {
......@@ -371,10 +399,31 @@ class RepresentationSelector {
return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use);
}
bool IsSafeIntAdditiveOperand(Node* node) {
Type* type = NodeProperties::GetBounds(node).upper;
// TODO(jarin): Unfortunately, bitset types are not subtypes of larger
// range types, so we have to explicitly check for Integral32 here
// (in addition to the safe integer range). Once we fix subtyping for
// ranges, we should simplify this.
return type->Is(safe_int_additive_range_) || type->Is(Type::Integral32());
}
bool CanLowerToInt32AdditiveBinop(Node* node, MachineTypeUnion use) {
return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
IsSafeIntAdditiveOperand(node->InputAt(1)) &&
!CanObserveNonInt32(use);
}
bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) {
return BothInputsAre(node, Type::Unsigned32()) && !CanObserveNonUint32(use);
}
bool CanLowerToUint32AdditiveBinop(Node* node, MachineTypeUnion use) {
return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
IsSafeIntAdditiveOperand(node->InputAt(1)) &&
!CanObserveNonUint32(use);
}
bool CanObserveNonInt32(MachineTypeUnion use) {
return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
}
......@@ -516,10 +565,22 @@ class RepresentationSelector {
// => signed Int32Add/Sub
VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node));
} else if (CanLowerToInt32AdditiveBinop(node, use)) {
// => signed Int32Add/Sub, truncating inputs
ProcessTruncateWord32Input(node, 0, kTypeInt32);
ProcessTruncateWord32Input(node, 1, kTypeInt32);
SetOutput(node, kMachInt32);
if (lower()) node->set_op(Int32Op(node));
} else if (CanLowerToUint32Binop(node, use)) {
// => unsigned Int32Add/Sub
VisitUint32Binop(node);
if (lower()) node->set_op(Uint32Op(node));
} else if (CanLowerToUint32AdditiveBinop(node, use)) {
// => signed Int32Add/Sub, truncating inputs
ProcessTruncateWord32Input(node, 0, kTypeUint32);
ProcessTruncateWord32Input(node, 1, kTypeUint32);
SetOutput(node, kMachUint32);
if (lower()) node->set_op(Uint32Op(node));
} else {
// => Float64Add/Sub
VisitFloat64Binop(node);
......@@ -915,6 +976,7 @@ class RepresentationSelector {
Phase phase_; // current phase of algorithm
RepresentationChanger* changer_; // for inserting representation changes
ZoneQueue<Node*> queue_; // queue for traversing the graph
Type* safe_int_additive_range_;
NodeInfo* GetInfo(Node* node) {
DCHECK(node->id() >= 0);
......
This diff is collapsed.
......@@ -51,6 +51,7 @@ class Typer {
Type* zeroish;
Type* falsish;
Type* integer;
Type* weakint;
Type* number_fun0_;
Type* number_fun1_;
Type* number_fun2_;
......@@ -67,6 +68,9 @@ class Typer {
Type* uint32_array_fun_;
Type* float32_array_fun_;
Type* float64_array_fun_;
ZoneVector<Handle<Object> > weaken_min_limits_;
ZoneVector<Handle<Object> > weaken_max_limits_;
};
}
}
......
......@@ -787,6 +787,7 @@ class TypeImpl<Config>::RangeType : public StructuralType {
static RangeHandle New(
i::Handle<i::Object> min, i::Handle<i::Object> max, Region* region) {
DCHECK(IsInteger(min->Number()) && IsInteger(max->Number()));
DCHECK(min->Number() <= max->Number());
RangeHandle type = Config::template cast<RangeType>(
StructuralType::New(StructuralType::kRangeTag, 3, region));
......
......@@ -947,24 +947,50 @@ TEST(LowerNumberCmp_to_float64) {
TEST(LowerNumberAddSub_to_int32) {
TestingGraph t(Type::Signed32(), Type::Signed32());
t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
t.simplified()->NumberAdd(),
t.simplified()->NumberToInt32());
t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
t.simplified()->NumberSubtract(),
t.simplified()->NumberToInt32());
HandleAndZoneScope scope;
Factory* f = scope.main_zone()->isolate()->factory();
Type* small_range =
Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
Type* large_range =
Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
large_range};
for (size_t i = 0; i < arraysize(types); i++) {
for (size_t j = 0; j < arraysize(types); j++) {
TestingGraph t(types[i], types[j]);
t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
t.simplified()->NumberAdd(),
t.simplified()->NumberToInt32());
t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
t.simplified()->NumberSubtract(),
t.simplified()->NumberToInt32());
}
}
}
TEST(LowerNumberAddSub_to_uint32) {
TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
t.simplified()->NumberAdd(),
t.simplified()->NumberToUint32());
t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
t.simplified()->NumberSubtract(),
t.simplified()->NumberToUint32());
HandleAndZoneScope scope;
Factory* f = scope.main_zone()->isolate()->factory();
Type* small_range =
Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
Type* large_range =
Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
large_range};
for (size_t i = 0; i < arraysize(types); i++) {
for (size_t j = 0; j < arraysize(types); j++) {
TestingGraph t(types[i], types[j]);
t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
t.simplified()->NumberAdd(),
t.simplified()->NumberToUint32());
t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
t.simplified()->NumberSubtract(),
t.simplified()->NumberToUint32());
}
}
}
......
......@@ -194,7 +194,7 @@ static int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
TEST(TypeJSAdd) {
TyperTester t;
t.TestBinaryArithOp(t.javascript_.Subtract(), std::plus<double>());
t.TestBinaryArithOp(t.javascript_.Add(), std::plus<double>());
}
......
......@@ -590,6 +590,8 @@ struct Tests : Rep {
}
void MinMax() {
Factory* fac = isolate->factory();
// If b is regular numeric bitset, then Range(b->Min(), b->Max())->Is(b).
// TODO(neis): Need to ignore representation for this to be true.
/*
......@@ -608,8 +610,7 @@ struct Tests : Rep {
// If b is regular numeric bitset, then b->Min() and b->Max() are integers.
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
TypeHandle type = *it;
if (this->IsBitset(type) && type->Is(T.Number) &&
!type->Is(T.None) && !type->Is(T.NaN)) {
if (this->IsBitset(type) && type->Is(T.Number) && !type->Is(T.NaN)) {
CHECK(IsInteger(type->Min()) && IsInteger(type->Max()));
}
}
......@@ -637,6 +638,15 @@ struct Tests : Rep {
CHECK(lub->Min() <= type->Min() && type->Max() <= lub->Max());
}
}
// Rangification: If T->Is(Range(-inf,+inf)) and !T->Is(None), then
// T->Is(Range(T->Min(), T->Max())).
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
TypeHandle type = *it;
CHECK(!(type->Is(T.Integer) && !type->Is(T.None)) ||
type->Is(T.Range(fac->NewNumber(type->Min()),
fac->NewNumber(type->Max()))));
}
}
void BitsetGlb() {
......
......@@ -103,6 +103,9 @@ class Types {
if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
}
Integer = Type::Range(isolate->factory()->NewNumber(-V8_INFINITY),
isolate->factory()->NewNumber(+V8_INFINITY), region);
NumberArray = Type::Array(Number, region);
StringArray = Type::Array(String, region);
AnyArray = Type::Array(Any, region);
......@@ -145,6 +148,8 @@ class Types {
TypeHandle ArrayConstant;
TypeHandle UninitializedConstant;
TypeHandle Integer;
TypeHandle NumberArray;
TypeHandle StringArray;
TypeHandle AnyArray;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment