mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Reduce the compile time of the typed_insts_test by a further 40% or so. (#3390)
Move the non-dependent portions of templates out into separate functions so that we don't need to repeatedly generate code for them.
This commit is contained in:
@@ -31,14 +31,17 @@ namespace {
|
||||
static_assert(Name::Kind == InstKind::Name);
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
|
||||
template <typename TypedInst>
|
||||
auto CommonFieldOrder() -> void {
|
||||
Inst inst = InstTestHelper::MakeInst(TypedInst::Kind, Parse::Node(1),
|
||||
TypeId(2), 3, 4);
|
||||
EXPECT_EQ(inst.kind(), TypedInst::Kind);
|
||||
auto MakeInstWithNumberedFields(InstKind kind) -> Inst {
|
||||
Inst inst = InstTestHelper::MakeInst(kind, Parse::Node(1), TypeId(2), 3, 4);
|
||||
EXPECT_EQ(inst.kind(), kind);
|
||||
EXPECT_EQ(inst.parse_node(), Parse::Node(1));
|
||||
EXPECT_EQ(inst.type_id(), TypeId(2));
|
||||
return inst;
|
||||
}
|
||||
|
||||
template <typename TypedInst>
|
||||
auto CommonFieldOrder() -> void {
|
||||
Inst inst = MakeInstWithNumberedFields(TypedInst::Kind);
|
||||
TypedInst typed = inst.As<TypedInst>();
|
||||
if constexpr (HasParseNode<TypedInst>) {
|
||||
EXPECT_EQ(typed.parse_node, Parse::Node(1));
|
||||
@@ -57,24 +60,24 @@ TEST(TypedInstTest, CommonFieldOrder) {
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
}
|
||||
|
||||
auto ExpectEqInsts(const Inst& inst1, const Inst& inst2,
|
||||
bool compare_parse_node, bool compare_type_id) -> void {
|
||||
EXPECT_EQ(inst1.kind(), inst2.kind());
|
||||
if (compare_parse_node) {
|
||||
EXPECT_EQ(inst1.parse_node(), inst2.parse_node());
|
||||
}
|
||||
if (compare_type_id) {
|
||||
EXPECT_EQ(inst1.type_id(), inst2.type_id());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TypedInst>
|
||||
auto RoundTrip() -> void {
|
||||
Inst inst1 = InstTestHelper::MakeInst(TypedInst::Kind, Parse::Node(1),
|
||||
TypeId(2), 3, 4);
|
||||
EXPECT_EQ(inst1.kind(), TypedInst::Kind);
|
||||
EXPECT_EQ(inst1.parse_node(), Parse::Node(1));
|
||||
EXPECT_EQ(inst1.type_id(), TypeId(2));
|
||||
|
||||
Inst inst1 = MakeInstWithNumberedFields(TypedInst::Kind);
|
||||
TypedInst typed1 = inst1.As<TypedInst>();
|
||||
Inst inst2 = typed1;
|
||||
|
||||
EXPECT_EQ(inst1.kind(), inst2.kind());
|
||||
if constexpr (HasParseNode<TypedInst>) {
|
||||
EXPECT_EQ(inst1.parse_node(), inst2.parse_node());
|
||||
}
|
||||
if constexpr (HasTypeId<TypedInst>) {
|
||||
EXPECT_EQ(inst1.type_id(), inst2.type_id());
|
||||
}
|
||||
ExpectEqInsts(inst1, inst2, HasParseNode<TypedInst>, HasTypeId<TypedInst>);
|
||||
|
||||
// If the typed instruction has no padding, we should get exactly the same
|
||||
// thing if we convert back from an instruction.
|
||||
@@ -87,9 +90,7 @@ auto RoundTrip() -> void {
|
||||
// because the fields not carried by the typed instruction are lost. But they
|
||||
// should be stable if we round-trip again.
|
||||
Inst inst3 = typed2;
|
||||
if constexpr (std::has_unique_object_representations_v<Inst>) {
|
||||
EXPECT_EQ(std::memcmp(&inst2, &inst3, sizeof(Inst)), 0);
|
||||
}
|
||||
ExpectEqInsts(inst2, inst3, true, true);
|
||||
}
|
||||
|
||||
TEST(TypedInstTest, RoundTrip) {
|
||||
@@ -101,31 +102,35 @@ TEST(TypedInstTest, RoundTrip) {
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
}
|
||||
|
||||
template <typename TypedInst>
|
||||
auto StructLayout() -> void {
|
||||
TypedInst typed =
|
||||
InstTestHelper::MakeInst(TypedInst::Kind, Parse::Node(1), TypeId(2), 3, 4)
|
||||
.template As<TypedInst>();
|
||||
|
||||
auto StructLayoutHelper(void* typed_inst, std::size_t typed_inst_size,
|
||||
bool has_parse_node, bool has_type_id) -> void {
|
||||
// Check that the memory representation of the typed instruction is what we
|
||||
// expect.
|
||||
// TODO: Struct layout is not guaranteed, and this test could fail in some
|
||||
// build environment. If so, we should disable it.
|
||||
int32_t fields[4] = {};
|
||||
int field = 0;
|
||||
if constexpr (HasParseNode<TypedInst>) {
|
||||
if (has_parse_node) {
|
||||
fields[field++] = 1;
|
||||
}
|
||||
if constexpr (HasTypeId<TypedInst>) {
|
||||
if (has_type_id) {
|
||||
fields[field++] = 2;
|
||||
}
|
||||
fields[field++] = 3;
|
||||
fields[field++] = 4;
|
||||
|
||||
ASSERT_LE(sizeof(TypedInst), sizeof(fields));
|
||||
ASSERT_LE(typed_inst_size, sizeof(int32_t) * field);
|
||||
EXPECT_EQ(std::memcmp(&fields, typed_inst, typed_inst_size), 0);
|
||||
}
|
||||
|
||||
template <typename TypedInst>
|
||||
auto StructLayout() -> void {
|
||||
// We can only do this check if the typed instruction has no padding.
|
||||
if constexpr (std::has_unique_object_representations_v<TypedInst>) {
|
||||
EXPECT_EQ(std::memcmp(&fields, &typed, sizeof(TypedInst)), 0);
|
||||
TypedInst typed =
|
||||
MakeInstWithNumberedFields(TypedInst::Kind).template As<TypedInst>();
|
||||
StructLayoutHelper(&typed, sizeof(typed), HasParseNode<TypedInst>,
|
||||
HasTypeId<TypedInst>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,22 +143,20 @@ TEST(TypedInstTest, StructLayout) {
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
}
|
||||
|
||||
template <typename TypedInst>
|
||||
auto InstKindMatches() {
|
||||
// TypedInst::Kind is an InstKind::Definition that extends InstKind, but
|
||||
// has different definitions of the `ir_name()` and `terminator_kind()`
|
||||
// methods. Here we test that values returned by the two different versions
|
||||
// of those functions match.
|
||||
InstKind as_kind = TypedInst::Kind;
|
||||
EXPECT_EQ(TypedInst::Kind.ir_name(), as_kind.ir_name());
|
||||
EXPECT_EQ(TypedInst::Kind.terminator_kind(), as_kind.terminator_kind());
|
||||
auto InstKindMatches(const InstKind::Definition& def, InstKind kind) {
|
||||
EXPECT_EQ(def.ir_name(), kind.ir_name());
|
||||
EXPECT_EQ(def.terminator_kind(), kind.terminator_kind());
|
||||
}
|
||||
|
||||
TEST(TypedInstTest, InstKindMatches) {
|
||||
#define CARBON_SEM_IR_INST_KIND(Name) \
|
||||
{ \
|
||||
SCOPED_TRACE(#Name); \
|
||||
InstKindMatches<Name>(); \
|
||||
// TypedInst::Kind is an InstKind::Definition that extends InstKind, but has
|
||||
// different definitions of the `ir_name()` and `terminator_kind()` methods.
|
||||
// Here we test that values returned by the two different versions of those
|
||||
// functions match.
|
||||
#define CARBON_SEM_IR_INST_KIND(Name) \
|
||||
{ \
|
||||
SCOPED_TRACE(#Name); \
|
||||
InstKindMatches(Name::Kind, Name::Kind); \
|
||||
}
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user