[turbofan] Rematerialize BigInt64 in deopt
This CL introduces two MachineTypes - SignedBigInt64 and UnsignedBigInt64, which are represented as Word64 but will be rematerialized to BigInt in deoptimization. This will avoid unnecessary conversions for BigInt64s when they are passed to StateValues. Bug: v8:9407 Change-Id: I65fdee3e028ed8f9920b1c20ff78993c7784de48 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3858238 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Nico Hartmann <nicohartmann@chromium.org> Commit-Queue: Qifan Pan <panq@google.com> Cr-Commit-Position: refs/heads/main@{#83230}
This commit is contained in:
parent
8199d70fd6
commit
80fb281561
@ -79,6 +79,10 @@ std::ostream& operator<<(std::ostream& os, MachineSemantic type) {
|
||||
return os << "kTypeInt64";
|
||||
case MachineSemantic::kUint64:
|
||||
return os << "kTypeUint64";
|
||||
case MachineSemantic::kSignedBigInt64:
|
||||
return os << "kTypeSignedBigInt64";
|
||||
case MachineSemantic::kUnsignedBigInt64:
|
||||
return os << "kTypeUnsignedBigInt64";
|
||||
case MachineSemantic::kNumber:
|
||||
return os << "kTypeNumber";
|
||||
case MachineSemantic::kAny:
|
||||
|
@ -86,6 +86,8 @@ enum class MachineSemantic : uint8_t {
|
||||
kUint32,
|
||||
kInt64,
|
||||
kUint64,
|
||||
kSignedBigInt64,
|
||||
kUnsignedBigInt64,
|
||||
kNumber,
|
||||
kAny
|
||||
};
|
||||
@ -193,6 +195,14 @@ class MachineType {
|
||||
return MachineType(MachineRepresentation::kWord64,
|
||||
MachineSemantic::kUint64);
|
||||
}
|
||||
constexpr static MachineType SignedBigInt64() {
|
||||
return MachineType(MachineRepresentation::kWord64,
|
||||
MachineSemantic::kSignedBigInt64);
|
||||
}
|
||||
constexpr static MachineType UnsignedBigInt64() {
|
||||
return MachineType(MachineRepresentation::kWord64,
|
||||
MachineSemantic::kUnsignedBigInt64);
|
||||
}
|
||||
constexpr static MachineType Float32() {
|
||||
return MachineType(MachineRepresentation::kFloat32,
|
||||
MachineSemantic::kNumber);
|
||||
|
@ -1171,6 +1171,12 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
|
||||
translations_.StoreUint32StackSlot(LocationOperand::cast(op)->index());
|
||||
} else if (type == MachineType::Int64()) {
|
||||
translations_.StoreInt64StackSlot(LocationOperand::cast(op)->index());
|
||||
} else if (type == MachineType::SignedBigInt64()) {
|
||||
translations_.StoreSignedBigInt64StackSlot(
|
||||
LocationOperand::cast(op)->index());
|
||||
} else if (type == MachineType::UnsignedBigInt64()) {
|
||||
translations_.StoreUnsignedBigInt64StackSlot(
|
||||
LocationOperand::cast(op)->index());
|
||||
} else {
|
||||
#if defined(V8_COMPRESS_POINTERS)
|
||||
CHECK(MachineRepresentation::kTagged == type.representation() ||
|
||||
@ -1199,6 +1205,10 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
|
||||
translations_.StoreUint32Register(converter.ToRegister(op));
|
||||
} else if (type == MachineType::Int64()) {
|
||||
translations_.StoreInt64Register(converter.ToRegister(op));
|
||||
} else if (type == MachineType::SignedBigInt64()) {
|
||||
translations_.StoreSignedBigInt64Register(converter.ToRegister(op));
|
||||
} else if (type == MachineType::UnsignedBigInt64()) {
|
||||
translations_.StoreUnsignedBigInt64Register(converter.ToRegister(op));
|
||||
} else {
|
||||
#if defined(V8_COMPRESS_POINTERS)
|
||||
CHECK(MachineRepresentation::kTagged == type.representation() ||
|
||||
@ -1229,7 +1239,7 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
|
||||
DCHECK_EQ(4, kSystemPointerSize);
|
||||
Smi smi(static_cast<Address>(constant.ToInt32()));
|
||||
DCHECK(smi.IsSmi());
|
||||
literal = DeoptimizationLiteral(smi.value());
|
||||
literal = DeoptimizationLiteral(static_cast<double>(smi.value()));
|
||||
} else if (type.representation() == MachineRepresentation::kBit) {
|
||||
if (constant.ToInt32() == 0) {
|
||||
literal =
|
||||
@ -1246,16 +1256,25 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
|
||||
DCHECK(type.representation() != MachineRepresentation::kNone ||
|
||||
constant.ToInt32() == FrameStateDescriptor::kImpossibleValue);
|
||||
if (type == MachineType::Uint32()) {
|
||||
literal = DeoptimizationLiteral(
|
||||
static_cast<uint32_t>(constant.ToInt32()));
|
||||
literal =
|
||||
DeoptimizationLiteral(static_cast<double>(constant.ToInt32()));
|
||||
} else {
|
||||
literal = DeoptimizationLiteral(constant.ToInt32());
|
||||
literal =
|
||||
DeoptimizationLiteral(static_cast<double>(constant.ToInt32()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Constant::kInt64:
|
||||
DCHECK_EQ(8, kSystemPointerSize);
|
||||
if (type.representation() == MachineRepresentation::kWord64) {
|
||||
if (type == MachineType::SignedBigInt64()) {
|
||||
literal = DeoptimizationLiteral(constant.ToInt64());
|
||||
} else if (type == MachineType::UnsignedBigInt64()) {
|
||||
literal =
|
||||
DeoptimizationLiteral(static_cast<uint64_t>(constant.ToInt64()));
|
||||
} else if (type.representation() == MachineRepresentation::kWord64) {
|
||||
CHECK_EQ(
|
||||
constant.ToInt64(),
|
||||
static_cast<int64_t>(static_cast<double>(constant.ToInt64())));
|
||||
literal =
|
||||
DeoptimizationLiteral(static_cast<double>(constant.ToInt64()));
|
||||
} else {
|
||||
@ -1264,7 +1283,7 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
|
||||
DCHECK_EQ(MachineRepresentation::kTagged, type.representation());
|
||||
Smi smi(static_cast<Address>(constant.ToInt64()));
|
||||
DCHECK(smi.IsSmi());
|
||||
literal = DeoptimizationLiteral(smi.value());
|
||||
literal = DeoptimizationLiteral(static_cast<double>(smi.value()));
|
||||
}
|
||||
break;
|
||||
case Constant::kFloat32:
|
||||
@ -1325,6 +1344,12 @@ Handle<Object> DeoptimizationLiteral::Reify(Isolate* isolate) const {
|
||||
case DeoptimizationLiteralKind::kNumber: {
|
||||
return isolate->factory()->NewNumber(number_);
|
||||
}
|
||||
case DeoptimizationLiteralKind::kSignedBigInt64: {
|
||||
return BigInt::FromInt64(isolate, signed_bigint64_);
|
||||
}
|
||||
case DeoptimizationLiteralKind::kUnsignedBigInt64: {
|
||||
return BigInt::FromUint64(isolate, unsigned_bigint64_);
|
||||
}
|
||||
case DeoptimizationLiteralKind::kInvalid: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -55,26 +55,52 @@ class InstructionOperandIterator {
|
||||
size_t pos_;
|
||||
};
|
||||
|
||||
enum class DeoptimizationLiteralKind { kObject, kNumber, kInvalid };
|
||||
enum class DeoptimizationLiteralKind {
|
||||
kObject,
|
||||
kNumber,
|
||||
kSignedBigInt64,
|
||||
kUnsignedBigInt64,
|
||||
kInvalid
|
||||
};
|
||||
|
||||
// Either a non-null Handle<Object> or a double.
|
||||
// A non-null Handle<Object>, a double, an int64_t, or a uint64_t.
|
||||
class DeoptimizationLiteral {
|
||||
public:
|
||||
DeoptimizationLiteral()
|
||||
: kind_(DeoptimizationLiteralKind::kInvalid), object_(), number_(0) {}
|
||||
: kind_(DeoptimizationLiteralKind::kInvalid), object_() {}
|
||||
explicit DeoptimizationLiteral(Handle<Object> object)
|
||||
: kind_(DeoptimizationLiteralKind::kObject), object_(object) {
|
||||
CHECK(!object_.is_null());
|
||||
}
|
||||
explicit DeoptimizationLiteral(double number)
|
||||
: kind_(DeoptimizationLiteralKind::kNumber), number_(number) {}
|
||||
explicit DeoptimizationLiteral(int64_t signed_bigint64)
|
||||
: kind_(DeoptimizationLiteralKind::kSignedBigInt64),
|
||||
signed_bigint64_(signed_bigint64) {}
|
||||
explicit DeoptimizationLiteral(uint64_t unsigned_bigint64)
|
||||
: kind_(DeoptimizationLiteralKind::kUnsignedBigInt64),
|
||||
unsigned_bigint64_(unsigned_bigint64) {}
|
||||
|
||||
Handle<Object> object() const { return object_; }
|
||||
|
||||
bool operator==(const DeoptimizationLiteral& other) const {
|
||||
return kind_ == other.kind_ && object_.equals(other.object_) &&
|
||||
base::bit_cast<uint64_t>(number_) ==
|
||||
if (kind_ != other.kind_) {
|
||||
return false;
|
||||
}
|
||||
switch (kind_) {
|
||||
case DeoptimizationLiteralKind::kObject:
|
||||
return object_.equals(other.object_);
|
||||
case DeoptimizationLiteralKind::kNumber:
|
||||
return base::bit_cast<uint64_t>(number_) ==
|
||||
base::bit_cast<uint64_t>(other.number_);
|
||||
case DeoptimizationLiteralKind::kSignedBigInt64:
|
||||
return signed_bigint64_ == other.signed_bigint64_;
|
||||
case DeoptimizationLiteralKind::kUnsignedBigInt64:
|
||||
return unsigned_bigint64_ == other.unsigned_bigint64_;
|
||||
case DeoptimizationLiteralKind::kInvalid:
|
||||
return true;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Handle<Object> Reify(Isolate* isolate) const;
|
||||
@ -91,8 +117,12 @@ class DeoptimizationLiteral {
|
||||
private:
|
||||
DeoptimizationLiteralKind kind_;
|
||||
|
||||
Handle<Object> object_;
|
||||
double number_ = 0;
|
||||
union {
|
||||
Handle<Object> object_;
|
||||
double number_;
|
||||
int64_t signed_bigint64_;
|
||||
uint64_t unsigned_bigint64_;
|
||||
};
|
||||
};
|
||||
|
||||
// These structs hold pc offsets for generated instructions and is only used
|
||||
|
@ -26,6 +26,10 @@ bool IsNonTruncatingMachineTypeFor(const MachineType& mt, const Type& type) {
|
||||
if (type.IsNone()) return true;
|
||||
// TODO(nicohartmann@): Add more cases here.
|
||||
if (type.Is(Type::BigInt())) {
|
||||
if (mt.representation() == MachineRepresentation::kWord64) {
|
||||
return type.Is(Type::SignedBigInt64()) ||
|
||||
type.Is(Type::UnsignedBigInt64());
|
||||
}
|
||||
return mt.representation() == MachineRepresentation::kTaggedPointer ||
|
||||
mt.representation() == MachineRepresentation::kTagged;
|
||||
}
|
||||
|
@ -223,6 +223,11 @@ bool IsSomePositiveOrderedNumber(Type type) {
|
||||
return type.Is(Type::OrderedNumber()) && (type.IsNone() || type.Min() > 0);
|
||||
}
|
||||
|
||||
inline bool IsLargeBigInt(Type type) {
|
||||
return type.Is(Type::BigInt()) && !type.Is(Type::SignedBigInt64()) &&
|
||||
!type.Is(Type::UnsignedBigInt64());
|
||||
}
|
||||
|
||||
class JSONGraphWriterWithVerifierTypes : public JSONGraphWriter {
|
||||
public:
|
||||
JSONGraphWriterWithVerifierTypes(std::ostream& os, const Graph* graph,
|
||||
@ -1307,6 +1312,14 @@ class RepresentationSelector {
|
||||
return MachineType::AnyTagged();
|
||||
}
|
||||
if (rep == MachineRepresentation::kWord64) {
|
||||
if (type.Is(Type::SignedBigInt64())) {
|
||||
return MachineType::SignedBigInt64();
|
||||
}
|
||||
|
||||
if (type.Is(Type::UnsignedBigInt64())) {
|
||||
return MachineType::UnsignedBigInt64();
|
||||
}
|
||||
|
||||
if (type.Is(Type::BigInt())) {
|
||||
return MachineType::AnyTagged();
|
||||
}
|
||||
@ -1328,13 +1341,11 @@ class RepresentationSelector {
|
||||
void VisitStateValues(Node* node) {
|
||||
if (propagate<T>()) {
|
||||
for (int i = 0; i < node->InputCount(); i++) {
|
||||
// When lowering 64 bit BigInts to Word64 representation, we have to
|
||||
// make sure they are rematerialized before deoptimization. By
|
||||
// propagating a AnyTagged use, the RepresentationChanger is going to
|
||||
// insert the necessary conversions.
|
||||
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
|
||||
// truncated BigInts.
|
||||
if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
|
||||
// BigInt64s are rematerialized in deoptimization. The other BigInts
|
||||
// must be rematerialized before deoptimization. By propagating an
|
||||
// AnyTagged use, the RepresentationChanger is going to insert the
|
||||
// necessary conversions.
|
||||
if (IsLargeBigInt(TypeOf(node->InputAt(i)))) {
|
||||
EnqueueInput<T>(node, i, UseInfo::AnyTagged());
|
||||
} else {
|
||||
EnqueueInput<T>(node, i, UseInfo::Any());
|
||||
@ -1346,9 +1357,7 @@ class RepresentationSelector {
|
||||
zone->New<ZoneVector<MachineType>>(node->InputCount(), zone);
|
||||
for (int i = 0; i < node->InputCount(); i++) {
|
||||
Node* input = node->InputAt(i);
|
||||
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
|
||||
// truncated BigInts.
|
||||
if (TypeOf(input).Is(Type::BigInt())) {
|
||||
if (IsLargeBigInt(TypeOf(input))) {
|
||||
ConvertInput(node, i, UseInfo::AnyTagged());
|
||||
}
|
||||
|
||||
@ -1377,9 +1386,7 @@ class RepresentationSelector {
|
||||
// state-values node).
|
||||
Node* accumulator = node.stack();
|
||||
if (propagate<T>()) {
|
||||
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
|
||||
// truncated BigInts.
|
||||
if (TypeOf(accumulator).Is(Type::BigInt())) {
|
||||
if (IsLargeBigInt(TypeOf(accumulator))) {
|
||||
EnqueueInput<T>(node, FrameState::kFrameStateStackInput,
|
||||
UseInfo::AnyTagged());
|
||||
} else {
|
||||
@ -1387,9 +1394,7 @@ class RepresentationSelector {
|
||||
UseInfo::Any());
|
||||
}
|
||||
} else if (lower<T>()) {
|
||||
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
|
||||
// truncated BigInts.
|
||||
if (TypeOf(accumulator).Is(Type::BigInt())) {
|
||||
if (IsLargeBigInt(TypeOf(accumulator))) {
|
||||
ConvertInput(node, FrameState::kFrameStateStackInput,
|
||||
UseInfo::AnyTagged());
|
||||
}
|
||||
@ -1424,9 +1429,7 @@ class RepresentationSelector {
|
||||
void VisitObjectState(Node* node) {
|
||||
if (propagate<T>()) {
|
||||
for (int i = 0; i < node->InputCount(); i++) {
|
||||
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
|
||||
// truncated BigInts.
|
||||
if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
|
||||
if (IsLargeBigInt(TypeOf(node->InputAt(i)))) {
|
||||
EnqueueInput<T>(node, i, UseInfo::AnyTagged());
|
||||
} else {
|
||||
EnqueueInput<T>(node, i, UseInfo::Any());
|
||||
@ -1440,9 +1443,7 @@ class RepresentationSelector {
|
||||
Node* input = node->InputAt(i);
|
||||
(*types)[i] =
|
||||
DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
|
||||
// TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
|
||||
// truncated BigInts.
|
||||
if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
|
||||
if (IsLargeBigInt(TypeOf(input))) {
|
||||
ConvertInput(node, i, UseInfo::AnyTagged());
|
||||
}
|
||||
}
|
||||
@ -1981,7 +1982,7 @@ class RepresentationSelector {
|
||||
case wasm::kI32:
|
||||
return MachineType::Int32();
|
||||
case wasm::kI64:
|
||||
return MachineType::Int64();
|
||||
return MachineType::SignedBigInt64();
|
||||
case wasm::kF32:
|
||||
return MachineType::Float32();
|
||||
case wasm::kF64:
|
||||
@ -2983,7 +2984,10 @@ class RepresentationSelector {
|
||||
node, InsertTypeOverrideForVerifier(Type::UnsignedBigInt63(),
|
||||
jsgraph_->ZeroConstant()));
|
||||
} else if (p.bits() == 64) {
|
||||
DeferReplacement(node, node->InputAt(0));
|
||||
DeferReplacement(node, InsertTypeOverrideForVerifier(
|
||||
is_asuintn ? Type::UnsignedBigInt64()
|
||||
: Type::SignedBigInt64(),
|
||||
node->InputAt(0)));
|
||||
} else {
|
||||
if (is_asuintn) {
|
||||
const uint64_t mask = (1ULL << p.bits()) - 1ULL;
|
||||
|
@ -145,6 +145,22 @@ void TranslationArrayPrintSingleFrame(
|
||||
break;
|
||||
}
|
||||
|
||||
case TranslationOpcode::SIGNED_BIGINT64_REGISTER: {
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
int reg_code = iterator.NextUnsigned();
|
||||
os << "{input=" << converter.NameOfCPURegister(reg_code)
|
||||
<< " (signed bigint64)}";
|
||||
break;
|
||||
}
|
||||
|
||||
case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER: {
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
int reg_code = iterator.NextUnsigned();
|
||||
os << "{input=" << converter.NameOfCPURegister(reg_code)
|
||||
<< " (unsigned bigint64)}";
|
||||
break;
|
||||
}
|
||||
|
||||
case TranslationOpcode::UINT32_REGISTER: {
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
int reg_code = iterator.NextUnsigned();
|
||||
@ -195,6 +211,20 @@ void TranslationArrayPrintSingleFrame(
|
||||
break;
|
||||
}
|
||||
|
||||
case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT: {
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
int input_slot_index = iterator.Next();
|
||||
os << "{input=" << input_slot_index << " (signed bigint64)}";
|
||||
break;
|
||||
}
|
||||
|
||||
case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT: {
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
int input_slot_index = iterator.Next();
|
||||
os << "{input=" << input_slot_index << " (unsigned bigint64)}";
|
||||
break;
|
||||
}
|
||||
|
||||
case TranslationOpcode::UINT32_STACK_SLOT: {
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
int input_slot_index = iterator.Next();
|
||||
@ -329,6 +359,14 @@ TranslatedValue TranslatedValue::NewInt64ToBigInt(TranslatedState* container,
|
||||
return slot;
|
||||
}
|
||||
|
||||
// static
|
||||
TranslatedValue TranslatedValue::NewUint64ToBigInt(TranslatedState* container,
|
||||
uint64_t value) {
|
||||
TranslatedValue slot(container, kUint64ToBigInt);
|
||||
slot.uint64_value_ = value;
|
||||
return slot;
|
||||
}
|
||||
|
||||
// static
|
||||
TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container,
|
||||
uint32_t value) {
|
||||
@ -375,6 +413,11 @@ int64_t TranslatedValue::int64_value() const {
|
||||
return int64_value_;
|
||||
}
|
||||
|
||||
uint64_t TranslatedValue::uint64_value() const {
|
||||
DCHECK(kUint64ToBigInt == kind());
|
||||
return uint64_value_;
|
||||
}
|
||||
|
||||
uint32_t TranslatedValue::uint32_value() const {
|
||||
DCHECK(kind() == kUInt32 || kind() == kBoolBit);
|
||||
return uint32_value_;
|
||||
@ -547,6 +590,9 @@ Handle<Object> TranslatedValue::GetValue() {
|
||||
case TranslatedValue::kInt64ToBigInt:
|
||||
heap_object = BigInt::FromInt64(isolate(), int64_value());
|
||||
break;
|
||||
case TranslatedValue::kUint64ToBigInt:
|
||||
heap_object = BigInt::FromUint64(isolate(), uint64_value());
|
||||
break;
|
||||
case TranslatedValue::kUInt32:
|
||||
number = uint32_value();
|
||||
heap_object = isolate()->factory()->NewHeapNumber(number);
|
||||
@ -562,7 +608,8 @@ Handle<Object> TranslatedValue::GetValue() {
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
DCHECK(!IsSmiDouble(number) || kind() == TranslatedValue::kInt64ToBigInt);
|
||||
DCHECK(!IsSmiDouble(number) || kind() == TranslatedValue::kInt64ToBigInt ||
|
||||
kind() == TranslatedValue::kUint64ToBigInt);
|
||||
set_initialized_storage(heap_object);
|
||||
return storage_;
|
||||
}
|
||||
@ -868,6 +915,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
|
||||
case TranslationOpcode::REGISTER:
|
||||
case TranslationOpcode::INT32_REGISTER:
|
||||
case TranslationOpcode::INT64_REGISTER:
|
||||
case TranslationOpcode::SIGNED_BIGINT64_REGISTER:
|
||||
case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER:
|
||||
case TranslationOpcode::UINT32_REGISTER:
|
||||
case TranslationOpcode::BOOL_REGISTER:
|
||||
case TranslationOpcode::FLOAT_REGISTER:
|
||||
@ -875,6 +924,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
|
||||
case TranslationOpcode::STACK_SLOT:
|
||||
case TranslationOpcode::INT32_STACK_SLOT:
|
||||
case TranslationOpcode::INT64_STACK_SLOT:
|
||||
case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT:
|
||||
case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT:
|
||||
case TranslationOpcode::UINT32_STACK_SLOT:
|
||||
case TranslationOpcode::BOOL_STACK_SLOT:
|
||||
case TranslationOpcode::FLOAT_STACK_SLOT:
|
||||
@ -1089,6 +1140,42 @@ int TranslatedState::CreateNextTranslatedValue(
|
||||
return translated_value.GetChildrenCount();
|
||||
}
|
||||
|
||||
case TranslationOpcode::SIGNED_BIGINT64_REGISTER: {
|
||||
int input_reg = iterator->NextUnsigned();
|
||||
if (registers == nullptr) {
|
||||
TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
|
||||
frame.Add(translated_value);
|
||||
return translated_value.GetChildrenCount();
|
||||
}
|
||||
intptr_t value = registers->GetRegister(input_reg);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%" V8PRIdPTR " ; %s (signed bigint64)", value,
|
||||
converter.NameOfCPURegister(input_reg));
|
||||
}
|
||||
TranslatedValue translated_value =
|
||||
TranslatedValue::NewInt64ToBigInt(this, value);
|
||||
frame.Add(translated_value);
|
||||
return translated_value.GetChildrenCount();
|
||||
}
|
||||
|
||||
case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER: {
|
||||
int input_reg = iterator->NextUnsigned();
|
||||
if (registers == nullptr) {
|
||||
TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
|
||||
frame.Add(translated_value);
|
||||
return translated_value.GetChildrenCount();
|
||||
}
|
||||
intptr_t value = registers->GetRegister(input_reg);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%" V8PRIdPTR " ; %s (unsigned bigint64)", value,
|
||||
converter.NameOfCPURegister(input_reg));
|
||||
}
|
||||
TranslatedValue translated_value =
|
||||
TranslatedValue::NewUint64ToBigInt(this, value);
|
||||
frame.Add(translated_value);
|
||||
return translated_value.GetChildrenCount();
|
||||
}
|
||||
|
||||
case TranslationOpcode::UINT32_REGISTER: {
|
||||
int input_reg = iterator->NextUnsigned();
|
||||
if (registers == nullptr) {
|
||||
@ -1205,6 +1292,36 @@ int TranslatedState::CreateNextTranslatedValue(
|
||||
return translated_value.GetChildrenCount();
|
||||
}
|
||||
|
||||
case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT: {
|
||||
int slot_offset =
|
||||
OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
|
||||
uint64_t value = GetUInt64Slot(fp, slot_offset);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%" V8PRIdPTR " ; (signed bigint64) [fp %c %3d] ",
|
||||
static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
|
||||
std::abs(slot_offset));
|
||||
}
|
||||
TranslatedValue translated_value =
|
||||
TranslatedValue::NewInt64ToBigInt(this, value);
|
||||
frame.Add(translated_value);
|
||||
return translated_value.GetChildrenCount();
|
||||
}
|
||||
|
||||
case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT: {
|
||||
int slot_offset =
|
||||
OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
|
||||
uint64_t value = GetUInt64Slot(fp, slot_offset);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%" V8PRIdPTR " ; (unsigned bigint64) [fp %c %3d] ",
|
||||
static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
|
||||
std::abs(slot_offset));
|
||||
}
|
||||
TranslatedValue translated_value =
|
||||
TranslatedValue::NewUint64ToBigInt(this, value);
|
||||
frame.Add(translated_value);
|
||||
return translated_value.GetChildrenCount();
|
||||
}
|
||||
|
||||
case TranslationOpcode::UINT32_STACK_SLOT: {
|
||||
int slot_offset =
|
||||
OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
|
||||
|
@ -73,6 +73,7 @@ class TranslatedValue {
|
||||
kInt32,
|
||||
kInt64,
|
||||
kInt64ToBigInt,
|
||||
kUint64ToBigInt,
|
||||
kUInt32,
|
||||
kBoolBit,
|
||||
kFloat,
|
||||
@ -111,6 +112,8 @@ class TranslatedValue {
|
||||
static TranslatedValue NewInt64(TranslatedState* container, int64_t value);
|
||||
static TranslatedValue NewInt64ToBigInt(TranslatedState* container,
|
||||
int64_t value);
|
||||
static TranslatedValue NewUint64ToBigInt(TranslatedState* container,
|
||||
uint64_t value);
|
||||
static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
|
||||
static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
|
||||
static TranslatedValue NewTagged(TranslatedState* container, Object literal);
|
||||
@ -152,7 +155,9 @@ class TranslatedValue {
|
||||
uint32_t uint32_value_;
|
||||
// kind is kInt32.
|
||||
int32_t int32_value_;
|
||||
// kind is kInt64.
|
||||
// kind is kUint64ToBigInt.
|
||||
uint64_t uint64_value_;
|
||||
// kind is kInt64 or kInt64ToBigInt.
|
||||
int64_t int64_value_;
|
||||
// kind is kFloat
|
||||
Float32 float_value_;
|
||||
@ -167,6 +172,7 @@ class TranslatedValue {
|
||||
int32_t int32_value() const;
|
||||
int64_t int64_value() const;
|
||||
uint32_t uint32_value() const;
|
||||
uint64_t uint64_value() const;
|
||||
Float32 float_value() const;
|
||||
Float64 double_value() const;
|
||||
int object_length() const;
|
||||
|
@ -287,6 +287,20 @@ void TranslationArrayBuilder::StoreInt64Register(Register reg) {
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
}
|
||||
|
||||
void TranslationArrayBuilder::StoreSignedBigInt64Register(Register reg) {
|
||||
auto opcode = TranslationOpcode::SIGNED_BIGINT64_REGISTER;
|
||||
AddOpcode(opcode);
|
||||
AddRegister(reg);
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
}
|
||||
|
||||
void TranslationArrayBuilder::StoreUnsignedBigInt64Register(Register reg) {
|
||||
auto opcode = TranslationOpcode::UNSIGNED_BIGINT64_REGISTER;
|
||||
AddOpcode(opcode);
|
||||
AddRegister(reg);
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
}
|
||||
|
||||
void TranslationArrayBuilder::StoreUint32Register(Register reg) {
|
||||
auto opcode = TranslationOpcode::UINT32_REGISTER;
|
||||
AddOpcode(opcode);
|
||||
@ -334,6 +348,20 @@ void TranslationArrayBuilder::StoreInt64StackSlot(int index) {
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
}
|
||||
|
||||
void TranslationArrayBuilder::StoreSignedBigInt64StackSlot(int index) {
|
||||
auto opcode = TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT;
|
||||
AddOpcode(opcode);
|
||||
Add(index);
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
}
|
||||
|
||||
void TranslationArrayBuilder::StoreUnsignedBigInt64StackSlot(int index) {
|
||||
auto opcode = TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT;
|
||||
AddOpcode(opcode);
|
||||
Add(index);
|
||||
DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
|
||||
}
|
||||
|
||||
void TranslationArrayBuilder::StoreUint32StackSlot(int index) {
|
||||
auto opcode = TranslationOpcode::UINT32_STACK_SLOT;
|
||||
AddOpcode(opcode);
|
||||
|
@ -90,6 +90,8 @@ class TranslationArrayBuilder {
|
||||
void StoreRegister(Register reg);
|
||||
void StoreInt32Register(Register reg);
|
||||
void StoreInt64Register(Register reg);
|
||||
void StoreSignedBigInt64Register(Register reg);
|
||||
void StoreUnsignedBigInt64Register(Register reg);
|
||||
void StoreUint32Register(Register reg);
|
||||
void StoreBoolRegister(Register reg);
|
||||
void StoreFloatRegister(FloatRegister reg);
|
||||
@ -97,6 +99,8 @@ class TranslationArrayBuilder {
|
||||
void StoreStackSlot(int index);
|
||||
void StoreInt32StackSlot(int index);
|
||||
void StoreInt64StackSlot(int index);
|
||||
void StoreSignedBigInt64StackSlot(int index);
|
||||
void StoreUnsignedBigInt64StackSlot(int index);
|
||||
void StoreUint32StackSlot(int index);
|
||||
void StoreBoolStackSlot(int index);
|
||||
void StoreFloatStackSlot(int index);
|
||||
|
@ -30,6 +30,10 @@ namespace internal {
|
||||
V(INT32_STACK_SLOT, 1) \
|
||||
V(INT64_REGISTER, 1) \
|
||||
V(INT64_STACK_SLOT, 1) \
|
||||
V(SIGNED_BIGINT64_REGISTER, 1) \
|
||||
V(SIGNED_BIGINT64_STACK_SLOT, 1) \
|
||||
V(UNSIGNED_BIGINT64_REGISTER, 1) \
|
||||
V(UNSIGNED_BIGINT64_STACK_SLOT, 1) \
|
||||
V(INTERPRETED_FRAME, 5) \
|
||||
V(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME, 3) \
|
||||
V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME, 3) \
|
||||
|
156
test/mjsunit/compiler/bigint-rematerialize.js
Normal file
156
test/mjsunit/compiler/bigint-rematerialize.js
Normal file
@ -0,0 +1,156 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --turbofan --no-always-turbofan
|
||||
|
||||
(function OptimizeAndTestAsUintN() {
|
||||
function f(x) {
|
||||
// Will be lowered to Int64Constant(-1) and stored as an immediate.
|
||||
let y = BigInt.asUintN(64, -1n);
|
||||
try {
|
||||
return x + y;
|
||||
} catch(_) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(2n ** 64n, f(1n));
|
||||
assertEquals(2n ** 64n + 1n, f(2n));
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(2n ** 64n, f(1n));
|
||||
assertOptimized(f);
|
||||
// Should be rematerialized to 2n ** 64n - 1n in code generation.
|
||||
assertEquals(2n ** 64n - 1n, f(0));
|
||||
if (%Is64Bit()) {
|
||||
assertUnoptimized(f);
|
||||
}
|
||||
})();
|
||||
|
||||
(function OptimizeAndTestAsUintN() {
|
||||
function f(x) {
|
||||
// Will be lowered to Int64Sub because exponentiation is not truncated and
|
||||
// stored in a register.
|
||||
let y = BigInt.asUintN(64, -(2n ** 0n));
|
||||
try {
|
||||
return x + y;
|
||||
} catch(_) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(2n ** 64n, f(1n));
|
||||
assertEquals(2n ** 64n + 1n, f(2n));
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(2n ** 64n, f(1n));
|
||||
assertOptimized(f);
|
||||
// Should be rematerialized to 2n ** 64n - 1n in deoptimization.
|
||||
assertEquals(2n ** 64n - 1n, f(0));
|
||||
if (%Is64Bit()) {
|
||||
assertUnoptimized(f);
|
||||
}
|
||||
})();
|
||||
|
||||
(function OptimizeAndTestAsUintN() {
|
||||
function f(x) {
|
||||
// Will be lowered to Int64Sub because exponentiation is not truncated and
|
||||
// stored in a stack slot.
|
||||
let y = BigInt.asUintN(64, -(2n ** 0n));
|
||||
try {
|
||||
// The recursion is used to make sure `y` is stored on the stack.
|
||||
return (x < 3n) ? (x + y) : f(x - 1n);
|
||||
} catch(_) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(2n ** 64n, f(1n));
|
||||
assertEquals(2n ** 64n + 1n, f(2n));
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(2n ** 64n, f(1n));
|
||||
assertOptimized(f);
|
||||
// Should be rematerialized to 2n ** 64n - 1n in deoptimization.
|
||||
assertEquals(2n ** 64n - 1n, f(0));
|
||||
if (%Is64Bit()) {
|
||||
assertUnoptimized(f);
|
||||
}
|
||||
})();
|
||||
|
||||
(function OptimizeAndTestAsIntN() {
|
||||
function f(x) {
|
||||
// Will be lowered to Int64Constant(-1) and stored as an immediate.
|
||||
let y = BigInt.asIntN(64, -1n);
|
||||
try {
|
||||
return x + y;
|
||||
} catch (_) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(0n, f(1n));
|
||||
assertEquals(1n, f(2n));
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(0n, f(1n));
|
||||
assertOptimized(f);
|
||||
// Should be rematerialized to -1n in code generation.
|
||||
assertEquals(-1n, f(0));
|
||||
if (%Is64Bit()) {
|
||||
assertUnoptimized(f);
|
||||
}
|
||||
})();
|
||||
|
||||
(function OptimizeAndTestAsIntN() {
|
||||
function f(x) {
|
||||
// Will be lowered to Int64Sub because exponentiation is not truncated and
|
||||
// stored in a register.
|
||||
let y = BigInt.asIntN(64, -(2n ** 0n));
|
||||
try {
|
||||
return x + y;
|
||||
} catch(_) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(0n, f(1n));
|
||||
assertEquals(1n, f(2n));
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(0n, f(1n));
|
||||
assertOptimized(f);
|
||||
// Should be rematerialized to -1n in deoptimization.
|
||||
assertEquals(-1n, f(0));
|
||||
if (%Is64Bit()) {
|
||||
assertUnoptimized(f);
|
||||
}
|
||||
})();
|
||||
|
||||
(function OptimizeAndTestAsIntN() {
|
||||
|
||||
function f(x) {
|
||||
// Will be lowered to Int64Sub because exponentiation is not truncated and
|
||||
// stored in a stack slot.
|
||||
let y = BigInt.asIntN(64, -(2n ** 0n));
|
||||
try {
|
||||
// The recursion is used to make sure `y` is stored on the stack.
|
||||
return (x < 3n) ? (x + y) : f(x - 1n);
|
||||
} catch(_) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(0n, f(1n));
|
||||
assertEquals(1n, f(2n));
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(0n, f(1n));
|
||||
assertOptimized(f);
|
||||
// Should be rematerialized to -1n in deoptimization.
|
||||
assertEquals(-1n, f(0));
|
||||
if (%Is64Bit()) {
|
||||
assertUnoptimized(f);
|
||||
}
|
||||
})();
|
43
test/mjsunit/wasm/bigint-rematerialize.js
Normal file
43
test/mjsunit/wasm/bigint-rematerialize.js
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --turbofan --no-always-turbofan --turbo-inline-js-wasm-calls
|
||||
|
||||
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
let builder = new WasmModuleBuilder();
|
||||
|
||||
builder
|
||||
.addFunction("f", kSig_l_v) // () -> i64
|
||||
.addBody([
|
||||
kExprI64Const, 0,
|
||||
kExprI64Const, 1,
|
||||
kExprI64Sub, // -1
|
||||
])
|
||||
.exportFunc();
|
||||
|
||||
let module = builder.instantiate();
|
||||
|
||||
function f(x) {
|
||||
let y = module.exports.f();
|
||||
try {
|
||||
return x + y;
|
||||
} catch(_) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(0n, f(1n));
|
||||
assertEquals(1n, f(2n));
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(0n, f(1n));
|
||||
assertOptimized(f);
|
||||
// After optimization, the result of the js wasm call is stored in word64 and
|
||||
// passed to StateValues without conversion. Rematerialization will happen
|
||||
// in deoptimizer.
|
||||
assertEquals(-1n, f(0));
|
||||
if (%Is64Bit()) {
|
||||
assertUnoptimized(f);
|
||||
}
|
Loading…
Reference in New Issue
Block a user