@@ -4447,6 +4447,91 @@ struct test_mul_mat_id_fusion : public test_case {
44474447 }
44484448};
44494449
4450+ // Merged MoE gate_up -> SWIGLU -> down MUL_MAT_ID chain.
4451+ struct test_moe_swiglu_down : public test_case {
4452+ const ggml_type type_a;
4453+ const int n_mats;
4454+ const int n_used;
4455+ const int64_t n_ff;
4456+ const int64_t n_tokens;
4457+ const int64_t n_embd;
4458+
4459+ std::string vars () override {
4460+ return VARS_TO_STR6 (type_a, n_mats, n_used, n_ff, n_tokens, n_embd);
4461+ }
4462+
4463+ double max_nmse_err () override {
4464+ return 5e-4 ;
4465+ }
4466+
4467+ double max_nmse_err (ggml_backend_t backend) override {
4468+ if ((type_a == GGML_TYPE_MXFP4 || type_a == GGML_TYPE_NVFP4 ) && backend_has_feature (backend, " BLACKWELL_NATIVE_FP4" )) {
4469+ // This whole-graph gate compounds two native-FP4 MUL_MAT_ID ops with
4470+ // SWIGLU between them, so it needs slightly more room than the
4471+ // single-op FP4 MUL_MAT_ID gate.
4472+ return 2.5e-2 ;
4473+ }
4474+ return max_nmse_err ();
4475+ }
4476+
4477+ uint64_t op_flops (ggml_tensor * t) override {
4478+ GGML_UNUSED (t);
4479+ return 2 * n_ff * n_embd * n_tokens * n_used * 3 ;
4480+ }
4481+
4482+ test_moe_swiglu_down (ggml_type type_a = GGML_TYPE_F32 , int n_mats = 128 , int n_used = 8 ,
4483+ int64_t n_ff = 768 , int64_t n_tokens = 128 , int64_t n_embd = 2048 )
4484+ : type_a(type_a), n_mats(n_mats), n_used(n_used), n_ff(n_ff), n_tokens(n_tokens), n_embd(n_embd) {
4485+ GGML_ASSERT (n_used <= n_mats);
4486+ }
4487+
4488+ ggml_tensor * build_graph (ggml_context * ctx) override {
4489+ ggml_tensor * gate_up = ggml_new_tensor_3d (ctx, type_a, n_embd, 2 * n_ff, n_mats);
4490+ ggml_set_name (gate_up, " gate_up" );
4491+
4492+ ggml_tensor * down = ggml_new_tensor_3d (ctx, type_a, n_ff, n_embd, n_mats);
4493+ ggml_set_name (down, " down" );
4494+
4495+ ggml_tensor * ids = ggml_new_tensor_2d (ctx, GGML_TYPE_I32 , n_mats, n_tokens);
4496+ ggml_set_name (ids, " ids" );
4497+ if (n_used != n_mats) {
4498+ ids = ggml_view_2d (ctx, ids, n_used, n_tokens, ids->nb [1 ], 0 );
4499+ ggml_set_name (ids, " view_of_ids" );
4500+ }
4501+
4502+ ggml_tensor * cur = ggml_new_tensor_3d (ctx, GGML_TYPE_F32 , n_embd, n_used, n_tokens);
4503+ ggml_set_name (cur, " cur" );
4504+
4505+ ggml_tensor * gate_up_out = ggml_mul_mat_id (ctx, gate_up, cur, ids);
4506+ ggml_set_name (gate_up_out, " gate_up_out" );
4507+
4508+ ggml_tensor * gate = ggml_view_3d (ctx, gate_up_out, n_ff, n_used, n_tokens, gate_up_out->nb [1 ], gate_up_out->nb [2 ], 0 );
4509+ ggml_set_name (gate, " gate" );
4510+
4511+ ggml_tensor * up = ggml_view_3d (ctx, gate_up_out, n_ff, n_used, n_tokens, gate_up_out->nb [1 ], gate_up_out->nb [2 ], n_ff * gate_up_out->nb [0 ]);
4512+ ggml_set_name (up, " up" );
4513+
4514+ ggml_tensor * act = ggml_swiglu_split (ctx, gate, up);
4515+ ggml_set_name (act, " swiglu" );
4516+
4517+ ggml_tensor * out = ggml_mul_mat_id (ctx, down, act, ids);
4518+ ggml_set_name (out, " out" );
4519+
4520+ return out;
4521+ }
4522+
4523+ void initialize_tensors (ggml_context * ctx) override {
4524+ init_mul_mat_id_tensors (ctx, n_mats);
4525+ }
4526+
4527+ bool run_whole_graph () override { return true ; }
4528+
4529+ std::string op_desc (ggml_tensor * t) override {
4530+ GGML_UNUSED (t);
4531+ return " MOE_SWIGLU_DOWN" ;
4532+ }
4533+ };
4534+
44504535// GGML_OP_OUT_PROD
44514536struct test_out_prod : public test_case {
44524537 const ggml_type type_a;
@@ -8759,6 +8844,13 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_eval() {
87598844 }
87608845 }
87618846
8847+ // [paged Phase 7] Merged MoE gate_up -> SWIGLU -> down projection gate for the
8848+ // serving candidate that fuses SWIGLU into NVFP4 down-input quantization.
8849+ test_cases.emplace_back (new test_moe_swiglu_down (GGML_TYPE_F32 , 8 , 2 , 32 , 8 , 64 ));
8850+ for (int n : {16 , 33 , 64 , 128 , 130 , 200 }) {
8851+ test_cases.emplace_back (new test_moe_swiglu_down (GGML_TYPE_NVFP4 , 128 , 8 , 768 , n, 2048 ));
8852+ }
8853+
87628854 // [paged P0 / track B] NVFP4/MXFP4 dense decode-shape mmq_y-down bit-exact gate.
87638855 // The dense FP4 weight GEMM is the track-B target; P1 lowers mmq_y (the weight-row tile) on the
87648856 // NVFP4 decode path to raise resident-CTA occupancy. mmq_y is a pure N-row tiling knob, so a
0 commit comments