Commit 668fe5cf authored by Bill Budge's avatar Bill Budge Committed by Commit Bot

[wasm] Add builtin WasmFloat32ToNumber.

- Use the new builtin to convert f32 to Number, rather than changing
  to f64, then calling f64 to Number.

Bug: v8:10070
Change-Id: I9a0660af8f5e517c2c6691d57d665b7e6316a51b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2111714
Commit-Queue: Bill Budge <bbudge@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67342}
parent 5e828c7d
......@@ -841,6 +841,7 @@ namespace internal {
ASM(WasmDebugBreak, Dummy) \
TFC(WasmInt32ToHeapNumber, WasmInt32ToHeapNumber) \
TFC(WasmTaggedNonSmiToInt32, WasmTaggedNonSmiToInt32) \
TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \
TFC(WasmFloat64ToNumber, WasmFloat64ToNumber) \
TFC(WasmTaggedToFloat64, WasmTaggedToFloat64) \
TFC(WasmAtomicNotify, WasmAtomicNotify) \
......
......@@ -48,6 +48,11 @@ TF_BUILTIN(WasmTaggedNonSmiToInt32, WasmBuiltinsAssembler) {
ChangeTaggedNonSmiToInt32(context, CAST(Parameter(Descriptor::kValue))));
}
TF_BUILTIN(WasmFloat32ToNumber, WasmBuiltinsAssembler) {
TNode<Float32T> val = UncheckedCast<Float32T>(Parameter(Descriptor::kValue));
Return(ChangeFloat32ToTagged(val));
}
TF_BUILTIN(WasmFloat64ToNumber, WasmBuiltinsAssembler) {
TNode<Float64T> val = UncheckedCast<Float64T>(Parameter(Descriptor::kValue));
Return(ChangeFloat64ToTagged(val));
......
......@@ -5282,6 +5282,38 @@ void CodeStubAssembler::TryHeapNumberToSmi(TNode<HeapNumber> number,
TryFloat64ToSmi(value, var_result_smi, if_smi);
}
void CodeStubAssembler::TryFloat32ToSmi(TNode<Float32T> value,
TVariable<Smi>* var_result_smi,
Label* if_smi) {
TNode<Int32T> ivalue = TruncateFloat32ToInt32(value);
TNode<Float32T> fvalue = RoundInt32ToFloat32(ivalue);
Label if_int32(this), if_heap_number(this);
GotoIfNot(Float32Equal(value, fvalue), &if_heap_number);
GotoIfNot(Word32Equal(ivalue, Int32Constant(0)), &if_int32);
Branch(Int32LessThan(UncheckedCast<Int32T>(BitcastFloat32ToInt32(value)),
Int32Constant(0)),
&if_heap_number, &if_int32);
TVARIABLE(Number, var_result);
BIND(&if_int32);
{
if (SmiValuesAre32Bits()) {
*var_result_smi = SmiTag(ChangeInt32ToIntPtr(ivalue));
} else {
DCHECK(SmiValuesAre31Bits());
TNode<PairT<Int32T, BoolT>> pair = Int32AddWithOverflow(ivalue, ivalue);
TNode<BoolT> overflow = Projection<1>(pair);
GotoIf(overflow, &if_heap_number);
*var_result_smi =
BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(Projection<0>(pair)));
}
Goto(if_smi);
}
BIND(&if_heap_number);
}
void CodeStubAssembler::TryFloat64ToSmi(TNode<Float64T> value,
TVariable<Smi>* var_result_smi,
Label* if_smi) {
......@@ -5314,6 +5346,24 @@ void CodeStubAssembler::TryFloat64ToSmi(TNode<Float64T> value,
BIND(&if_heap_number);
}
TNode<Number> CodeStubAssembler::ChangeFloat32ToTagged(TNode<Float32T> value) {
Label if_smi(this), done(this);
TVARIABLE(Smi, var_smi_result);
TVARIABLE(Number, var_result);
TryFloat32ToSmi(value, &var_smi_result, &if_smi);
var_result = AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(value));
Goto(&done);
BIND(&if_smi);
{
var_result = var_smi_result.value();
Goto(&done);
}
BIND(&done);
return var_result.value();
}
TNode<Number> CodeStubAssembler::ChangeFloat64ToTagged(
SloppyTNode<Float64T> value) {
Label if_smi(this), done(this);
......
......@@ -2424,8 +2424,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Conversions.
void TryHeapNumberToSmi(TNode<HeapNumber> number, TVariable<Smi>* output,
Label* if_smi);
void TryFloat32ToSmi(TNode<Float32T> number, TVariable<Smi>* output,
Label* if_smi);
void TryFloat64ToSmi(TNode<Float64T> number, TVariable<Smi>* output,
Label* if_smi);
TNode<Number> ChangeFloat32ToTagged(TNode<Float32T> value);
TNode<Number> ChangeFloat64ToTagged(SloppyTNode<Float64T> value);
TNode<Number> ChangeInt32ToTagged(SloppyTNode<Int32T> value);
TNode<Number> ChangeUint32ToTagged(SloppyTNode<Uint32T> value);
......
......@@ -284,6 +284,14 @@ void RunMicrotasksEntryDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(0, nullptr);
}
void WasmFloat32ToNumberDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// Work around using eax, whose register code is 0, and leads to the FP
// parameter being passed via xmm0, which is not allocatable on ia32.
Register registers[] = {ecx};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void WasmFloat64ToNumberDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// Work around using eax, whose register code is 0, and leads to the FP
......
......@@ -388,6 +388,12 @@ void WasmTaggedNonSmiToInt32Descriptor::InitializePlatformSpecific(
}
#if !V8_TARGET_ARCH_IA32
// We need a custom descriptor on ia32 to avoid using xmm0.
void WasmFloat32ToNumberDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data, kParameterCount);
}
// We need a custom descriptor on ia32 to avoid using xmm0.
void WasmFloat64ToNumberDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
......
......@@ -92,6 +92,7 @@ namespace internal {
V(Void) \
V(WasmInt32ToHeapNumber) \
V(WasmTaggedNonSmiToInt32) \
V(WasmFloat32ToNumber) \
V(WasmFloat64ToNumber) \
V(WasmTaggedToFloat64) \
V(WasmAtomicNotify) \
......@@ -1330,6 +1331,14 @@ class WasmTaggedNonSmiToInt32Descriptor final : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(WasmTaggedNonSmiToInt32Descriptor, CallInterfaceDescriptor)
};
class WasmFloat32ToNumberDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kValue)
DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), // result
MachineType::Float32()) // value
DECLARE_DESCRIPTOR(WasmFloat32ToNumberDescriptor, CallInterfaceDescriptor)
};
class WasmFloat64ToNumberDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kValue)
......
......@@ -308,6 +308,10 @@ TNode<ExternalReference> CodeAssembler::ExternalConstant(
raw_assembler()->ExternalConstant(address));
}
TNode<Float32T> CodeAssembler::Float32Constant(double value) {
return UncheckedCast<Float32T>(jsgraph()->Float32Constant(value));
}
TNode<Float64T> CodeAssembler::Float64Constant(double value) {
return UncheckedCast<Float64T>(jsgraph()->Float64Constant(value));
}
......@@ -435,6 +439,13 @@ void CodeAssembler::Return(TNode<WordT> value) {
return raw_assembler()->Return(value);
}
void CodeAssembler::Return(TNode<Float32T> value) {
DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
DCHECK_EQ(MachineType::Float32(),
raw_assembler()->call_descriptor()->GetReturnType(0));
return raw_assembler()->Return(value);
}
void CodeAssembler::Return(TNode<Float64T> value) {
DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
DCHECK_EQ(MachineType::Float64(),
......
......@@ -320,6 +320,7 @@ TNode<Float64T> Float64Add(TNode<Float64T> a, TNode<Float64T> b);
V(BitcastMaybeObjectToWord, IntPtrT, MaybeObject) \
V(BitcastWordToTagged, Object, WordT) \
V(BitcastWordToTaggedSigned, Smi, WordT) \
V(TruncateFloat32ToInt32, Int32T, Float32T) \
V(TruncateFloat64ToFloat32, Float32T, Float64T) \
V(TruncateFloat64ToWord32, Uint32T, Float64T) \
V(TruncateInt64ToInt32, Int32T, Int64T) \
......@@ -532,6 +533,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
TNode<String> StringConstant(const char* str);
TNode<Oddball> BooleanConstant(bool value);
TNode<ExternalReference> ExternalConstant(ExternalReference address);
TNode<Float32T> Float32Constant(double value);
TNode<Float64T> Float64Constant(double value);
TNode<BoolT> Int32TrueConstant() {
return ReinterpretCast<BoolT>(Int32Constant(1));
......@@ -571,6 +573,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
void Return(TNode<Int32T> value);
void Return(TNode<Uint32T> value);
void Return(TNode<WordT> value);
void Return(TNode<Float32T> value);
void Return(TNode<Float64T> value);
void Return(TNode<WordT> value1, TNode<WordT> value2);
void PopAndReturn(Node* pop, Node* value);
......
......@@ -5183,6 +5183,19 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return done.PhiAt(0);
}
Node* BuildChangeFloat32ToNumber(Node* value) {
CommonOperatorBuilder* common = mcgraph()->common();
Node* target = GetTargetForBuiltinCall(wasm::WasmCode::kWasmFloat32ToNumber,
Builtins::kWasmFloat32ToNumber);
if (!float32_to_number_operator_.is_set()) {
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), WasmFloat32ToNumberDescriptor(), 0,
CallDescriptor::kNoFlags, Operator::kNoProperties, stub_mode_);
float32_to_number_operator_.set(common->Call(call_descriptor));
}
return gasm_->Call(float32_to_number_operator_.get(), target, value);
}
Node* BuildChangeFloat64ToNumber(Node* value) {
CommonOperatorBuilder* common = mcgraph()->common();
Node* target = GetTargetForBuiltinCall(wasm::WasmCode::kWasmFloat64ToNumber,
......@@ -5234,9 +5247,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return BuildChangeInt64ToBigInt(node);
}
case wasm::ValueType::kF32:
node = graph()->NewNode(mcgraph()->machine()->ChangeFloat32ToFloat64(),
node);
return BuildChangeFloat64ToNumber(node);
return BuildChangeFloat32ToNumber(node);
case wasm::ValueType::kF64:
return BuildChangeFloat64ToNumber(node);
case wasm::ValueType::kAnyRef:
......@@ -6108,6 +6119,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
SetOncePointer<Node> undefined_value_node_;
SetOncePointer<const Operator> int32_to_heapnumber_operator_;
SetOncePointer<const Operator> tagged_non_smi_to_int32_operator_;
SetOncePointer<const Operator> float32_to_number_operator_;
SetOncePointer<const Operator> float64_to_number_operator_;
SetOncePointer<const Operator> tagged_to_float64_operator_;
wasm::WasmFeatures enabled_features_;
......
......@@ -52,6 +52,7 @@ struct WasmModule;
V(WasmDebugBreak) \
V(WasmInt32ToHeapNumber) \
V(WasmTaggedNonSmiToInt32) \
V(WasmFloat32ToNumber) \
V(WasmFloat64ToNumber) \
V(WasmTaggedToFloat64) \
V(WasmAtomicNotify) \
......
......@@ -3798,6 +3798,46 @@ TEST(WasmTaggedNonSmiToInt32) {
}
}
TEST(WasmFloat32ToNumber) {
Isolate* isolate(CcTest::InitIsolateOnce());
float test_values[] = {
// Smi values.
1,
0,
-1,
// Max and min Smis can't be represented as floats.
// Non-Smi values.
-0.0,
1.5,
std::numeric_limits<float>::quiet_NaN(),
std::numeric_limits<float>::infinity(),
};
// FunctionTester can't handle Wasm type arguments, so for each test value,
// build a function with the arguments baked in, then generate a no-argument
// function to call.
const int kNumParams = 1;
for (size_t i = 0; i < arraysize(test_values); ++i) {
double test_value = test_values[i];
CodeAssemblerTester asm_tester(isolate, kNumParams);
CodeStubAssembler m(asm_tester.state());
Node* context = m.Parameter(kNumParams + 1);
const TNode<Float32T> arg = m.Float32Constant(test_value);
const TNode<Object> call_result =
m.CallBuiltin(Builtins::kWasmFloat32ToNumber, context, arg);
m.Return(call_result);
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
Handle<Object> result = ft.Call().ToHandleChecked();
CHECK(result->IsNumber());
Handle<Object> expected(isolate->factory()->NewNumber(test_value));
CHECK(result->StrictEquals(*expected) ||
(std::isnan(test_value) && std::isnan(result->Number())));
CHECK_EQ(result->IsSmi(), expected->IsSmi());
}
}
TEST(WasmFloat64ToNumber) {
Isolate* isolate(CcTest::InitIsolateOnce());
......
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