Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,226 @@
// Copyright 2023 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.
#include <limits>
#ifdef V8_ENABLE_MAGLEV
#include "src/execution/simulator.h"
#include "src/maglev/maglev-assembler-inl.h"
#include "src/maglev/maglev-assembler.h"
#include "test/unittests/maglev/maglev-test.h"
namespace v8 {
namespace internal {
namespace maglev {
class MaglevAssemblerTest : public MaglevTest {
public:
MaglevAssemblerTest()
: MaglevTest(),
codegen_state(nullptr, nullptr, 0),
as(isolate(), zone(), &codegen_state) {}
void FinalizeAndRun(Label* pass, Label* fail) {
as.bind(pass);
as.Ret();
as.bind(fail);
as.AssertUnreachable(AbortReason::kNoReason);
CodeDesc desc;
as.GetCode(isolate(), &desc);
Factory::CodeBuilder build(isolate(), desc, CodeKind::FOR_TESTING);
auto res = build.TryBuild().ToHandleChecked();
using Function = GeneratedCode<Address()>;
auto fun = Function::FromAddress(isolate(), res->instruction_start());
fun.Call();
}
MaglevCodeGenState codegen_state;
MaglevAssembler as;
};
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToUint32One) {
as.CodeEntry();
as.Move(kFPReturnRegister0, 1.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToUint32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.Cmp(kReturnRegister0, 1);
as.Assert(Condition::kEqual, AbortReason::kNoReason);
as.jmp(&can_convert);
FinalizeAndRun(&can_convert, &cannot_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToUint32Zero) {
as.CodeEntry();
as.Move(kFPReturnRegister0, 0.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToUint32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.Cmp(kReturnRegister0, 0);
as.Assert(Condition::kEqual, AbortReason::kNoReason);
as.jmp(&can_convert);
FinalizeAndRun(&can_convert, &cannot_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToUint32Large) {
as.CodeEntry();
as.Move(kFPReturnRegister0, std::numeric_limits<uint32_t>::max());
Label can_convert, cannot_convert;
as.TryTruncateDoubleToUint32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.Cmp(kReturnRegister0, std::numeric_limits<uint32_t>::max());
as.Assert(Condition::kEqual, AbortReason::kNoReason);
as.jmp(&can_convert);
FinalizeAndRun(&can_convert, &cannot_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToUint32TooLarge) {
as.CodeEntry();
as.Move(kFPReturnRegister0,
static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToUint32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.jmp(&can_convert);
FinalizeAndRun(&cannot_convert, &can_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToUint32Negative) {
as.CodeEntry();
as.Move(kFPReturnRegister0, -1.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToUint32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.jmp(&can_convert);
FinalizeAndRun(&cannot_convert, &can_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToUint32NegativeZero) {
as.CodeEntry();
as.Move(kFPReturnRegister0, -0.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToUint32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.jmp(&can_convert);
FinalizeAndRun(&cannot_convert, &can_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToUint32NotItegral) {
as.CodeEntry();
as.Move(kFPReturnRegister0, 1.1);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToUint32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.jmp(&can_convert);
FinalizeAndRun(&cannot_convert, &can_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32One) {
as.CodeEntry();
as.Move(kFPReturnRegister0, 1.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.Cmp(kReturnRegister0, 1);
as.Assert(Condition::kEqual, AbortReason::kNoReason);
as.jmp(&can_convert);
FinalizeAndRun(&can_convert, &cannot_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32MinusOne) {
as.CodeEntry();
as.Move(kFPReturnRegister0, -1.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.Cmp(kReturnRegister0, static_cast<uint32_t>(-1));
as.Assert(Condition::kEqual, AbortReason::kNoReason);
as.jmp(&can_convert);
FinalizeAndRun(&can_convert, &cannot_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32Zero) {
as.CodeEntry();
as.Move(kFPReturnRegister0, 0.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.Cmp(kReturnRegister0, 0);
as.Assert(Condition::kEqual, AbortReason::kNoReason);
as.jmp(&can_convert);
FinalizeAndRun(&can_convert, &cannot_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32Large) {
as.CodeEntry();
as.Move(kFPReturnRegister0, std::numeric_limits<int32_t>::max());
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.Cmp(kReturnRegister0, std::numeric_limits<int32_t>::max());
as.Assert(Condition::kEqual, AbortReason::kNoReason);
as.jmp(&can_convert);
FinalizeAndRun(&can_convert, &cannot_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32Small) {
as.CodeEntry();
as.Move(kFPReturnRegister0, std::numeric_limits<int32_t>::min());
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.Cmp(kReturnRegister0,
static_cast<uint32_t>(std::numeric_limits<int32_t>::min()));
as.Assert(Condition::kEqual, AbortReason::kNoReason);
as.jmp(&can_convert);
FinalizeAndRun(&can_convert, &cannot_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32NegativeZero) {
as.CodeEntry();
as.Move(kFPReturnRegister0, -0.0);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.jmp(&can_convert);
FinalizeAndRun(&cannot_convert, &can_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32NotItegral) {
as.CodeEntry();
as.Move(kFPReturnRegister0, 1.1);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.jmp(&can_convert);
FinalizeAndRun(&cannot_convert, &can_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32TooLarge) {
as.CodeEntry();
as.Move(kFPReturnRegister0,
static_cast<double>(std::numeric_limits<int32_t>::max()) + 1);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.jmp(&can_convert);
FinalizeAndRun(&cannot_convert, &can_convert);
}
TEST_F(MaglevAssemblerTest, TryTruncateDoubleToInt32TooSmall) {
as.CodeEntry();
as.Move(kFPReturnRegister0,
static_cast<double>(std::numeric_limits<int32_t>::min()) - 1);
Label can_convert, cannot_convert;
as.TryTruncateDoubleToInt32(kReturnRegister0, kFPReturnRegister0,
&cannot_convert);
as.jmp(&can_convert);
FinalizeAndRun(&cannot_convert, &can_convert);
}
} // namespace maglev
} // namespace internal
} // namespace v8
#endif // V8_ENABLE_MAGLEV

View File

@ -0,0 +1,37 @@
// Copyright 2023 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.
#ifdef V8_ENABLE_MAGLEV
#include "test/unittests/maglev/maglev-test.h"
#include "src/execution/isolate.h"
#include "src/handles/handles.h"
namespace v8 {
namespace internal {
namespace maglev {
MaglevTest::MaglevTest()
: TestWithNativeContextAndZone(kCompressGraphZone),
broker_(isolate(), zone(), v8_flags.trace_heap_broker, CodeKind::MAGLEV),
broker_scope_(&broker_, isolate(), zone()),
current_broker_(&broker_) {
if (!PersistentHandlesScope::IsActive(isolate())) {
persistent_scope_.emplace(isolate());
}
broker()->SetTargetNativeContextRef(isolate()->native_context());
}
MaglevTest::~MaglevTest() {
if (persistent_scope_) {
persistent_scope_->Detach();
}
}
} // namespace maglev
} // namespace internal
} // namespace v8
#endif // V8_ENABLE_MAGLEV

View File

@ -0,0 +1,39 @@
// Copyright 2023 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.
#ifndef V8_UNITTESTS_MAGLEV_MAGLEV_TEST_H_
#define V8_UNITTESTS_MAGLEV_MAGLEV_TEST_H_
#ifdef V8_ENABLE_MAGLEV
#include "src/compiler/js-heap-broker.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
namespace maglev {
class MaglevTest : public TestWithNativeContextAndZone {
public:
MaglevTest();
~MaglevTest() override;
compiler::JSHeapBroker* broker() { return &broker_; }
private:
compiler::JSHeapBroker broker_;
compiler::JSHeapBrokerScopeForTesting broker_scope_;
std::optional<PersistentHandlesScope> persistent_scope_;
compiler::CurrentHeapBrokerScope current_broker_;
};
} // namespace maglev
} // namespace internal
} // namespace v8
#endif // V8_ENABLE_MAGLEV
#endif // V8_UNITTESTS_MAGLEV_MAGLEV_TEST_H_

View File

@ -0,0 +1,204 @@
// Copyright 2023 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.
#ifdef V8_ENABLE_MAGLEV
#include "src/maglev/maglev-ir.h"
#include "test/unittests/maglev/maglev-test.h"
namespace v8 {
namespace internal {
namespace maglev {
static std::initializer_list<NodeType> kAllNodeTypes{
#define TYPE(Name, _) NodeType::k##Name,
NODE_TYPE_LIST(TYPE)
#undef TYPE
};
inline constexpr bool IsKnownNodeTypeConstant(NodeType type) {
switch (type) {
#define CASE(Name, _) case NodeType::k##Name:
NODE_TYPE_LIST(CASE)
#undef CASE
return true;
}
return false;
}
template <typename Function>
inline std::unordered_set<NodeType> CompleteLattice(Function Combine) {
std::unordered_set completed_lattice(kAllNodeTypes);
bool complete = false;
while (!complete) {
complete = true;
std::unordered_set<NodeType> discovered;
for (NodeType a : completed_lattice) {
for (NodeType b : completed_lattice) {
NodeType combined = Combine(a, b);
if (!completed_lattice.count(combined)) {
discovered.insert(combined);
}
}
}
if (!discovered.empty()) {
completed_lattice.insert(discovered.begin(), discovered.end());
complete = false;
}
}
return completed_lattice;
}
static std::unordered_set<NodeType> kJoinLattice =
CompleteLattice([](NodeType a, NodeType b) { return IntersectType(a, b); });
static std::unordered_set<NodeType> kMeetLattice =
CompleteLattice([](NodeType a, NodeType b) { return CombineType(a, b); });
static std::unordered_set<NodeType> kCompleteLattice = []() {
std::unordered_set completed_lattice(kJoinLattice.begin(),
kJoinLattice.end());
completed_lattice.insert(kMeetLattice.begin(), kMeetLattice.end());
return completed_lattice;
}();
// Allow-list of joins we have consciously omitted from the join lattice since
// they are not needed often. Checking these types can be more expensive in
// some cases.
std::unordered_set<NodeType> kMissingEntries{
// HeapNumberOrOddball
CombineType(NodeType::kNumberOrOddball, NodeType::kAnyHeapObject),
// BooleanOrHeapNumber
CombineType(NodeType::kNumberOrBoolean, NodeType::kAnyHeapObject),
};
// The missing node types must be inhabited.
TEST_F(MaglevTest, NodeTypeMissingEntriesExist) {
for (NodeType missing : kMissingEntries) {
CHECK(!NodeTypeCannotHaveInstances(missing));
}
}
// Ensures important NodeTypes are closed under intersection.
TEST_F(MaglevTest, NodeTypeIsClosedUnderIntersect) {
for (NodeType join : kJoinLattice) {
CHECK(NodeTypeIs(join, NodeType::kUnknown));
CHECK_EQ(!kMissingEntries.count(join), IsKnownNodeTypeConstant(join));
}
}
// Every join of node types must be inhabited.
TEST_F(MaglevTest, NodeTypeIntersectsAreInhabited) {
for (NodeType t : kCompleteLattice) {
CHECK_IMPLIES(kJoinLattice.count(t) || kMissingEntries.count(t),
!NodeTypeCannotHaveInstances(t));
CHECK_IMPLIES(NodeTypeCannotHaveInstances(t),
!kJoinLattice.count(t) && !kMissingEntries.count(t));
}
}
// Check that the uninhabitated check behaves.
TEST_F(MaglevTest, NodeTypeCheckIsUninhabited) {
for (NodeType t : kCompleteLattice) {
CHECK_IMPLIES(NodeTypeCannotHaveInstances(t),
!IsKnownNodeTypeConstant(t) && !kMissingEntries.count(t));
CHECK_IMPLIES(IsKnownNodeTypeConstant(t) || kMissingEntries.count(t),
!NodeTypeCannotHaveInstances(t));
}
}
// Check impossible pairs are actually impossible.
TEST_F(MaglevTest, NodeTypeCheckLeafTypes) {
for (auto pair : kNodeTypeExclusivePairs) {
for (NodeType t : kJoinLattice) {
CHECK(!NodeTypeIs(t, pair.first) || !NodeTypeIs(t, pair.second));
}
}
}
// Ensure StaticTypeForConstant is consistent with actual objects.
TEST_F(MaglevTest, ConstantNodeTypeApproximationIsConsistent) {
for (auto idx = RootIndex::kFirstRoot; idx <= RootIndex::kLastRoot; ++idx) {
Tagged<Object> obj = isolate()->roots_table().slot(idx).load(isolate());
if (obj.ptr() == kNullAddress || !obj.IsHeapObject()) continue;
compiler::HeapObjectRef ref = MakeRef(broker(), Cast<HeapObject>(obj));
NodeType t = StaticTypeForConstant(broker(), ref);
CHECK(!NodeTypeCannotHaveInstances(t));
for (NodeType a : kCompleteLattice) {
bool is_instance = IsInstanceOfNodeType(ref.map(broker()), a, broker());
bool is_subtype = NodeTypeIs(t, a);
CHECK_IMPLIES(is_subtype, is_instance);
CHECK_IMPLIES(!is_instance, !is_subtype);
}
}
}
// Ensure StaticTypeForMap is consistent with actual maps.
TEST_F(MaglevTest, NodeTypeApproximationIsConsistent) {
for (auto idx = RootIndex::kFirstRoot; idx <= RootIndex::kLastRoot; ++idx) {
Tagged<Object> obj = isolate()->roots_table().slot(idx).load(isolate());
if (obj.ptr() == kNullAddress || !IsMap(obj)) continue;
Tagged<Map> map = Cast<Map>(obj);
compiler::MapRef map_ref = MakeRef(broker(), map);
for (NodeType a : kCompleteLattice) {
bool is_instance = IsInstanceOfNodeType(map_ref, a, broker());
bool is_subtype = NodeTypeIs(StaticTypeForMap(map_ref, broker()), a);
CHECK_IMPLIES(is_subtype, is_instance);
CHECK_IMPLIES(!is_instance, !is_subtype);
}
}
}
// Ensure CombineType is consistent with actual maps.
TEST_F(MaglevTest, NodeTypeCombineIsConsistent) {
for (auto idx = RootIndex::kFirstRoot; idx <= RootIndex::kLastRoot; ++idx) {
Tagged<Object> obj = isolate()->roots_table().slot(idx).load(isolate());
if (obj.ptr() == kNullAddress || !IsMap(obj)) continue;
Tagged<Map> map = Cast<Map>(obj);
compiler::MapRef map_ref = MakeRef(broker(), map);
for (NodeType a : kCompleteLattice) {
for (NodeType b : kJoinLattice) {
NodeType combined_type = CombineType(a, b);
bool map_is_a = IsInstanceOfNodeType(map_ref, a, broker());
bool map_is_b = IsInstanceOfNodeType(map_ref, b, broker());
bool is_instance =
IsInstanceOfNodeType(map_ref, combined_type, broker());
CHECK_EQ(is_instance, map_is_a && map_is_b);
DCHECK_IMPLIES(NodeTypeCannotHaveInstances(combined_type),
!is_instance);
DCHECK_IMPLIES(is_instance,
!NodeTypeCannotHaveInstances(combined_type));
}
}
}
}
// Ensure IntersectType is consistent with actual maps.
TEST_F(MaglevTest, NodeTypeIntersectIsConsistent) {
for (auto idx = RootIndex::kFirstRoot; idx <= RootIndex::kLastRoot; ++idx) {
Tagged<Object> obj = isolate()->roots_table().slot(idx).load(isolate());
if (obj.ptr() == kNullAddress || !IsMap(obj)) continue;
Tagged<Map> map = Cast<Map>(obj);
compiler::MapRef map_ref = MakeRef(broker(), map);
for (NodeType a : kCompleteLattice) {
for (NodeType b : kMeetLattice) {
NodeType join_type = IntersectType(a, b);
bool map_is_a = IsInstanceOfNodeType(map_ref, a, broker());
bool map_is_b = IsInstanceOfNodeType(map_ref, b, broker());
CHECK_IMPLIES(map_is_a || map_is_b,
IsInstanceOfNodeType(map_ref, join_type, broker()));
CHECK_IMPLIES(!IsInstanceOfNodeType(map_ref, join_type, broker()),
!(map_is_a && map_is_b));
}
}
}
}
} // namespace maglev
} // namespace internal
} // namespace v8
#endif // V8_ENABLE_MAGLEV