test(hex8): pin uniform packet branches and inactive overflow routing

This commit is contained in:
KOKO\Mimi
2026-10-14 20:23:38 +09:00
parent 9b8e53dcfd
commit b37fddd4e6
+70 -1
View File
@@ -142,7 +142,9 @@ TEST(Hex8HighLow, FourColumnMaterialPacketMatchesFrozenScalarBits) {
{std::numeric_limits<double>::min()}, {maximum}, {-maximum},
{1, tiny}, {1, -tiny}, {std::nextafter(1.0, 2.0)},
{1, 1}, {0, tiny}, {std::numeric_limits<double>::infinity(), 0},
{std::numeric_limits<double>::quiet_NaN(), 0}};
{std::numeric_limits<double>::quiet_NaN(), 0},
{std::numeric_limits<double>::signaling_NaN(), 0},
{0, std::numeric_limits<double>::signaling_NaN()}};
for (std::size_t first = 0; first < boundary.size(); ++first)
for (std::size_t second = 0; second < boundary.size(); ++second) {
MaterialPacketInput input;
@@ -230,6 +232,73 @@ TEST(Hex8HighLow, PacketSpecialLaneDoesNotChangeOtherColumns) {
}
}
TEST(Hex8HighLow, UniformDyadicPacketsExerciseEachLowZeroShape) {
std::size_t checks = 0, avx2_checks = 0;
for (int shape = 0; shape < 4; ++shape)
for (int low_weight = 0; low_weight < 2; ++low_weight)
for (int zero_accumulator = 0; zero_accumulator < 2; ++zero_accumulator) {
fesa::hex8_internal::MaterialPacketInput input;
input.weight = {0.5, low_weight != 0 ? std::ldexp(1.0, -57) : 0.0};
for (std::size_t lane = 0; lane < 4; ++lane) {
const bool left_low = (shape & 1) != 0;
const bool right_low = (shape & 2) != 0;
// Every lane has the same normalized nonzero dyadic inputs. Component
// LBE sums are >= -116 and all Add intermediates are bounded by 4.
// Thus each Multiply low-shape is uniform and its component products
// bypass zero/unsupported-tail fallback. No mixed-zero Add fallback
// is possible; the initial zero accumulator is uniform across lanes.
input.deviatoric_left[lane] = {1, left_low ? std::ldexp(1.0, -54) : 0};
input.deviatoric_right[lane] = {2, right_low ? std::ldexp(1.0, -54) : 0};
input.shear_left[lane] = {0.5, left_low ? std::ldexp(1.0, -56) : 0};
input.shear_right[lane] = {0.25, right_low ? std::ldexp(1.0, -57) : 0};
input.tensor_left[lane] = {0.75, left_low ? std::ldexp(1.0, -56) : 0};
input.gradient_dot[lane] = {0.125, right_low ? std::ldexp(1.0, -58) : 0};
input.accumulated[lane] = zero_accumulator != 0 ? HighLow{}
: HighLow{0.0625};
}
avx2_checks += ExpectFrozenMaterialPacket(input) ? 1U : 0U;
++checks;
}
RecordProperty("uniform_low_shape_checks", static_cast<int>(checks));
RecordProperty("avx2_uniform_low_shape_checks", static_cast<int>(avx2_checks));
}
TEST(Hex8HighLow, OverflowLaneIsNeutralizedBeforeResidualFma) {
const auto evaluator = fesa::hex8_internal::SelectMaterialPacketEvaluator();
if (evaluator == fesa::hex8_internal::EvaluateMaterialPacketScalar)
GTEST_SKIP() << "AVX2 masked environment is not selected; routing unverified.";
std::fenv_t original;
ASSERT_EQ(std::fegetenv(&original), 0);
for (std::size_t bad = 0; bad < 4; ++bad) {
fesa::hex8_internal::MaterialPacketInput input;
input.weight = {0.5};
for (std::size_t lane = 0; lane < 4; ++lane) {
input.deviatoric_left[lane] = {
lane == bad ? std::numeric_limits<double>::max() : 1};
input.deviatoric_right[lane] = {2};
input.shear_left[lane] = {0.5};
input.shear_right[lane] = {0.25};
input.tensor_left[lane] = {0.75};
input.gradient_dot[lane] = {0.125};
input.accumulated[lane] = {0.0625};
}
// All operands are finite/nonzero and max*2 has LBE sum 972, so Product
// reaches its vector multiply; only the post-product finite mask rejects it.
const auto expected = FrozenMaterialPacket(input);
EXPECT_EQ(std::feclearexcept(FE_ALL_EXCEPT), 0);
fesa::hex8_internal::PairPacket output;
evaluator(input, &output);
const bool extra_invalid = (std::fetestexcept(FE_INVALID) & FE_INVALID) != 0;
EXPECT_EQ(std::fesetenv(&original), 0);
EXPECT_FALSE(extra_invalid);
for (std::size_t lane = 0; lane < 4; ++lane) {
EXPECT_EQ(PairBits(output[lane].high), PairBits(expected[lane].high));
EXPECT_EQ(PairBits(output[lane].low), PairBits(expected[lane].low));
}
}
RecordProperty("avx2_product_overflow_positions", 4);
}
TEST(Hex8HighLow, PacketBackendSelectionRecoversAfterEnvironmentRestoration) {
const auto initial = fesa::hex8_internal::SelectMaterialPacketEvaluator();
const int rounding = std::fegetround();