diff --git a/toolchain/sem_ir/typed_insts_test.cpp b/toolchain/sem_ir/typed_insts_test.cpp index 70167009ff0e..9356a4df1122 100644 --- a/toolchain/sem_ir/typed_insts_test.cpp +++ b/toolchain/sem_ir/typed_insts_test.cpp @@ -31,14 +31,17 @@ namespace { static_assert(Name::Kind == InstKind::Name); #include "toolchain/sem_ir/inst_kind.def" -template -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 +auto CommonFieldOrder() -> void { + Inst inst = MakeInstWithNumberedFields(TypedInst::Kind); TypedInst typed = inst.As(); if constexpr (HasParseNode) { 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 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(); Inst inst2 = typed1; - EXPECT_EQ(inst1.kind(), inst2.kind()); - if constexpr (HasParseNode) { - EXPECT_EQ(inst1.parse_node(), inst2.parse_node()); - } - if constexpr (HasTypeId) { - EXPECT_EQ(inst1.type_id(), inst2.type_id()); - } + ExpectEqInsts(inst1, inst2, HasParseNode, HasTypeId); // 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) { - 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 -auto StructLayout() -> void { - TypedInst typed = - InstTestHelper::MakeInst(TypedInst::Kind, Parse::Node(1), TypeId(2), 3, 4) - .template As(); - +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) { + if (has_parse_node) { fields[field++] = 1; } - if constexpr (HasTypeId) { + 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 +auto StructLayout() -> void { // We can only do this check if the typed instruction has no padding. if constexpr (std::has_unique_object_representations_v) { - EXPECT_EQ(std::memcmp(&fields, &typed, sizeof(TypedInst)), 0); + TypedInst typed = + MakeInstWithNumberedFields(TypedInst::Kind).template As(); + StructLayoutHelper(&typed, sizeof(typed), HasParseNode, + HasTypeId); } } @@ -138,22 +143,20 @@ TEST(TypedInstTest, StructLayout) { #include "toolchain/sem_ir/inst_kind.def" } -template -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(); \ + // 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" }