return GetTaggedRepresentationFor(node, output_type);
} else if (use_type & kRepFloat64) {
return GetFloat64RepresentationFor(node, output_type);
+ } else if (use_type & kRepFloat32) {
+ return TypeError(node, output_type, use_type); // TODO(titzer): handle
} else if (use_type & kRepBit) {
return GetBitRepresentationFor(node, output_type);
} else if (use_type & rWord) {
return changer_->Float64OperatorFor(node->opcode());
}
+ static MachineType AssumeImplicitFloat32Change(MachineType type) {
+ // TODO(titzer): Assume loads of float32 change representation to float64.
+ // Fix this with full support for float32 representations.
+ if (type & kRepFloat32) {
+ return static_cast<MachineType>((type & ~kRepFloat32) | kRepFloat64);
+ }
+ return type;
+ }
+
// Dispatching routine for visiting the node {node} with the usage {use}.
// Depending on the operator, propagate new usage info to the inputs.
void VisitNode(Node* node, MachineTypeUnion use,
FieldAccess access = FieldAccessOf(node->op());
ProcessInput(node, 0, changer_->TypeForBasePointer(access));
ProcessRemainingInputs(node, 1);
- SetOutput(node, access.machine_type);
+ SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
if (lower()) lowering->DoLoadField(node);
break;
}
case IrOpcode::kStoreField: {
FieldAccess access = FieldAccessOf(node->op());
ProcessInput(node, 0, changer_->TypeForBasePointer(access));
- ProcessInput(node, 1, access.machine_type);
+ ProcessInput(node, 1, AssumeImplicitFloat32Change(access.machine_type));
ProcessRemainingInputs(node, 2);
SetOutput(node, 0);
if (lower()) lowering->DoStoreField(node);
ProcessInput(node, 0, changer_->TypeForBasePointer(access));
ProcessInput(node, 1, kMachInt32); // element index
ProcessRemainingInputs(node, 2);
- SetOutput(node, access.machine_type);
+ SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
if (lower()) lowering->DoLoadElement(node);
break;
}
ElementAccess access = ElementAccessOf(node->op());
ProcessInput(node, 0, changer_->TypeForBasePointer(access));
ProcessInput(node, 1, kMachInt32); // element index
- ProcessInput(node, 2, access.machine_type);
+ ProcessInput(node, 2, AssumeImplicitFloat32Change(access.machine_type));
ProcessRemainingInputs(node, 3);
SetOutput(node, 0);
if (lower()) lowering->DoStoreElement(node);
} // namespace v8::internal::compiler
+// TODO(titzer): add kRepFloat32 when fully supported.
static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64,
kRepFloat64, kRepTagged};
r.CheckNop(all_reps[i], all_reps[i]);
}
+ // 32-bit floats.
+ r.CheckNop(kRepFloat32, kRepFloat32);
+ r.CheckNop(kRepFloat32 | kTypeNumber, kRepFloat32);
+ r.CheckNop(kRepFloat32, kRepFloat32 | kTypeNumber);
+
// 32-bit or 64-bit words can be used as branch conditions (kRepBit).
r.CheckNop(kRepWord32, kRepBit);
r.CheckNop(kRepWord32, kRepBit | kTypeBool);
r.CheckTypeError(kRepBit, kRepFloat64);
r.CheckTypeError(kRepBit | kTypeBool, kRepFloat64);
+ // Floats cannot be implicitly converted to/from comparison conditions.
+ r.CheckTypeError(kRepFloat32, kRepBit);
+ r.CheckTypeError(kRepFloat32, kRepBit | kTypeBool);
+ r.CheckTypeError(kRepBit, kRepFloat32);
+ r.CheckTypeError(kRepBit | kTypeBool, kRepFloat32);
+
// Word64 is internal and shouldn't be implicitly converted.
r.CheckTypeError(kRepWord64, kRepTagged | kTypeBool);
r.CheckTypeError(kRepWord64, kRepTagged);
r.CheckTypeError(all_reps[i] | all_reps[j], kRepTagged);
}
}
-}
-
-TEST(CompleteMatrix) {
- // TODO(titzer): test all variants in the matrix.
- // rB
- // tBrB
- // tBrT
- // rW32
- // tIrW32
- // tUrW32
- // rW64
- // tIrW64
- // tUrW64
- // rF64
- // tIrF64
- // tUrF64
- // tArF64
- // rT
- // tArT
+ // TODO(titzer): Float32 representation changes trigger type errors now.
+ // Enforce current behavior to test all paths through representation changer.
+ for (size_t i = 0; i < arraysize(all_reps); i++) {
+ r.CheckTypeError(all_reps[i], kRepFloat32);
+ r.CheckTypeError(kRepFloat32, all_reps[i]);
+ }
}
CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled);
for (size_t i = 0; i < arraysize(kValues); ++i) {
for (size_t j = 0; j < arraysize(kValues); ++j) {
- double value_a = static_cast<U>(kValues[i]);
- double value_b = static_cast<U>(kValues[j]);
- double expected = value_a + value_b;
+ U value_a = static_cast<U>(kValues[i]);
+ U value_b = static_cast<U>(kValues[j]);
+ double expected =
+ static_cast<double>(value_a) + static_cast<double>(value_b);
T.CheckCall(T.Val(expected), T.Val(static_cast<double>(i)),
T.Val(static_cast<double>(j)));
}
TypedArrayLoadHelper<uint16_t>("Uint16");
TypedArrayLoadHelper<int32_t>("Int32");
TypedArrayLoadHelper<uint32_t>("Uint32");
+ TypedArrayLoadHelper<float>("Float32");
TypedArrayLoadHelper<double>("Float64");
- // TODO(mstarzinger): Add tests for Float32.
// TODO(mstarzinger): Add tests for ClampedUint8.
}
CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled);
for (size_t i = 0; i < arraysize(kValues); ++i) {
for (size_t j = 0; j < arraysize(kValues); ++j) {
- double value_a = static_cast<U>(kValues[i]);
- double value_b = static_cast<U>(kValues[j]);
- double expected = value_b + value_a;
+ U value_a = static_cast<U>(kValues[i]);
+ U value_b = static_cast<U>(kValues[j]);
+ double expected =
+ static_cast<double>(value_a) + static_cast<double>(value_b);
T.CheckCall(T.Val(expected), T.Val(static_cast<double>(i)),
T.Val(static_cast<double>(j)));
}
TypedArrayStoreHelper<uint16_t>("Uint16");
TypedArrayStoreHelper<int32_t>("Int32");
TypedArrayStoreHelper<uint32_t>("Uint32");
+ TypedArrayStoreHelper<float>("Float32");
TypedArrayStoreHelper<double>("Float64");
- // TODO(mstarzinger): Add tests for Float32.
// TODO(mstarzinger): Add tests for ClampedUint8.
}
RepresentationOf(OpParameter<MachineType>(phi)));
}
}
+
+
+// TODO(titzer): this tests current behavior of assuming an implicit
+// representation change in loading float32s. Fix when float32 is fully
+// supported.
+TEST(ImplicitFloat32ToFloat64InLoads) {
+ TestingGraph t(Type::Any());
+
+ FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
+ Handle<Name>::null(), Type::Any(), kMachFloat32};
+
+ Node* load =
+ t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
+ t.Return(load);
+ t.Lower();
+ CHECK_EQ(IrOpcode::kLoad, load->opcode());
+ CHECK_EQ(t.p0, load->InputAt(0));
+ CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
+}
+
+
+TEST(ImplicitFloat64ToFloat32InStores) {
+ TestingGraph t(Type::Any(), Type::Signed32());
+ FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
+ Handle<Name>::null(), Type::Any(), kMachFloat32};
+
+ Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
+ t.p1, t.start, t.start);
+ t.Effect(store);
+ t.Lower();
+
+ CHECK_EQ(IrOpcode::kStore, store->opcode());
+ CHECK_EQ(t.p0, store->InputAt(0));
+ CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
+}