| 34 | // This is the strongest check the language allows. It cannot see whether the |
| 35 | // dispatch below actually *assigns* a field it has — that is what the unit |
| 36 | // tests and the table's dispatch-matching row order are for. |
| 37 | |
| 38 | #define DFLASH_ARCH_FIELD_TRAIT(trait_name, field_name) \ |
| 39 | template <class T, class = void> \ |
| 40 | struct trait_name : std::false_type {}; \ |
| 41 | template <class T> \ |
| 42 | struct trait_name<T, std::void_t<decltype(T::field_name)>> \ |
| 43 | : std::true_type {} |
| 44 | |
| 45 | DFLASH_ARCH_FIELD_TRAIT(has_draft_path, draft_path); |
| 46 | DFLASH_ARCH_FIELD_TRAIT(has_fa_window, fa_window); |
| 47 | DFLASH_ARCH_FIELD_TRAIT(has_verify_width, verify_width); |
| 48 | DFLASH_ARCH_FIELD_TRAIT(has_draft_swa, draft_swa_window); |
| 49 | DFLASH_ARCH_FIELD_TRAIT(has_ddtree_mode, ddtree_mode); |
| 50 | DFLASH_ARCH_FIELD_TRAIT(has_max_verify_tokens, max_verify_tokens); |
| 51 | DFLASH_ARCH_FIELD_TRAIT(has_paged_attention, paged_attention); |
| 52 | |
| 53 | #undef DFLASH_ARCH_FIELD_TRAIT |
| 54 | |
| 55 | // DDTree reaches qwen35's layer-split path as a max_verify_tokens budget |
| 56 | // rather than a ddtree_mode flag, so either field counts as a carrier. |
| 57 | template <class T> |
| 58 | struct has_ddtree : std::bool_constant<has_ddtree_mode<T>::value || |
| 59 | has_max_verify_tokens<T>::value> {}; |
| 60 | |
| 61 | // Architectures with no layer-split adapter. Pairing one of these with the |
| 62 | // split half of a check requires the row to be Monolithic or Never, which |
| 63 | // table_split_coherent() already guarantees. |
| 64 | struct NoLayerSplitConfig {}; |
| 65 | |
| 66 | constexpr bool monolithic_carries(FeatureSupport support) { |
| 67 | return support != FeatureSupport::Never; |
| 68 | } |
| 69 | constexpr bool layer_split_carries(FeatureSupport support) { |
| 70 | return support == FeatureSupport::Both; |
| 71 | } |
| 72 | |
| 73 | #define DFLASH_CHECK_ARCH_OPTION(arch_name, Mono, Split, trait, field) \ |
| 74 | static_assert( \ |
| 75 | trait<Mono>::value == \ |
| 76 | monolithic_carries(arch_capabilities(arch_name).field), \ |
| 77 | arch_name ": monolithic config and capability table disagree on " \ |
| 78 | #field); \ |
| 79 | static_assert( \ |
| 80 | trait<Split>::value == \ |
| 81 | layer_split_carries(arch_capabilities(arch_name).field), \ |
| 82 | arch_name ": layer-split config and capability table disagree on " \ |
| 83 | #field) |
| 84 | |
| 85 | #define DFLASH_CHECK_ARCH(arch_name, Mono, Split) \ |
| 86 | DFLASH_CHECK_ARCH_OPTION(arch_name, Mono, Split, has_draft_path, decode_draft); \ |
| 87 | DFLASH_CHECK_ARCH_OPTION(arch_name, Mono, Split, has_ddtree, ddtree); \ |
| 88 | DFLASH_CHECK_ARCH_OPTION(arch_name, Mono, Split, has_verify_width, verify_width); \ |
| 89 | DFLASH_CHECK_ARCH_OPTION(arch_name, Mono, Split, has_fa_window, fa_window); \ |
| 90 | DFLASH_CHECK_ARCH_OPTION(arch_name, Mono, Split, has_draft_swa, draft_swa) |
| 91 | |
| 92 | DFLASH_CHECK_ARCH("qwen35", Qwen35Config, Qwen35LayerSplitAdapterConfig); |
| 93 | DFLASH_CHECK_ARCH("qwen35moe", Qwen35Config, NoLayerSplitConfig); |
no test coverage detected