Files

1102 lines
39 KiB
C++
Raw Permalink Normal View History

/* Copyright 2025 The xLLM Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/jd-opensource/xllm/blob/main/LICENSE
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "ops_api.h"
#if defined(USE_MLU)
#include "mlu/mlu_ops_api.h"
#elif defined(USE_NPU)
#include "core/kernels/npu/tilelang/tilelang_ops_api.h"
#include "npu/npu_ops_api.h"
#include "triton_npu/torch_api/triton_ops_api.h"
#elif defined(USE_CUDA)
#include "cuda/attention_runner.h"
#include "cuda/cuda_ops_api.h"
#elif defined(USE_ILU)
#include "ilu/ilu_ops_api.h"
#elif defined(USE_MUSA)
#include "cuda/cuda_ops_api.h"
#include "musa/musa_ops_api.h"
#endif
#include <numeric>
#include "common/macros.h"
#include "layers/common/attention_metadata.h"
namespace xllm::kernel {
void apply_rotary(RotaryParams& params) {
#if defined(USE_MLU)
mlu::apply_rotary(params.q,
params.k,
params.sin,
params.cos,
params.position_ids,
params.cu_query_lens,
params.interleaved,
params.discrete,
params.dynamic_ntk,
params.max_query_len);
#elif defined(USE_NPU)
npu::apply_rotary(
params.q, params.k, params.cos_sin, params.position_ids.value());
#elif defined(USE_CUDA) || defined(USE_MUSA)
bool is_neox = !params.interleaved;
torch::Tensor pos_ids;
torch::Tensor cos_sin;
if (params.position_ids.has_value()) {
// positions is already int64 on CUDA/MUSA (pre-converted in
// ForwardInput::to).
pos_ids = params.position_ids.value().to(torch::kInt64);
} else if (params.cu_query_lens.has_value()) {
auto cu = params.cu_query_lens.value().to(torch::kInt64);
CHECK(cu.numel() >= 2) << "apply_rotary (CUDA): cu_query_lens must have at "
"least 2 elements when "
"position_ids is not provided.";
int64_t seq_len = cu[1].item<int64_t>() - cu[0].item<int64_t>();
CHECK(seq_len > 0)
<< "apply_rotary (CUDA): invalid sequence length inferred from "
"cu_query_lens when position_ids is not provided.";
pos_ids = torch::arange(seq_len,
torch::TensorOptions()
.dtype(torch::kInt64)
.device(params.q.device()))
.contiguous();
} else {
// When neither position_ids nor cu_query_lens is provided,
// infer sequence length from q tensor and create default position IDs.
// This handles cases like LongCat-Image-Edit where rotary embedding
// is applied uniformly across all sequence positions.
int64_t seq_len = params.q.size(0);
CHECK(seq_len > 0) << "apply_rotary (CUDA): cannot infer valid sequence "
"length from q tensor.";
pos_ids = torch::arange(seq_len,
torch::TensorOptions()
.dtype(torch::kInt64)
.device(params.q.device()))
.contiguous();
}
if (params.precomputed_cos_sin.defined()) {
cos_sin = params.precomputed_cos_sin;
} else if (params.cos.defined() && params.sin.defined()) {
const int64_t head_dim = params.cos.size(-1);
const int64_t rot_half = head_dim / 2;
auto cos_sliced = params.cos.contiguous().slice(-1, 0, rot_half);
auto sin_sliced = params.sin.contiguous().slice(-1, 0, rot_half);
cos_sin = torch::cat({cos_sliced, sin_sliced}, -1);
} else if (params.cos_sin.defined()) {
auto cos_sin_vec = params.cos_sin.chunk(4, -1);
auto cos = cos_sin_vec[0];
auto sin = cos_sin_vec[2];
cos_sin = torch::cat({cos, sin}, -1);
} else {
LOG(FATAL) << "apply_rotary (CUDA): neither cos_sin nor cos/sin "
"provided; cannot infer cos_sin.";
}
cuda::rotary_embedding(pos_ids, params.q, params.k, cos_sin, is_neox);
#elif defined(USE_ILU)
torch::Tensor ilu_cos_sin;
if (params.precomputed_cos_sin.defined()) {
ilu_cos_sin = params.precomputed_cos_sin;
} else {
auto cos_sin_vec = params.cos_sin.chunk(4, -1);
ilu_cos_sin = torch::cat({cos_sin_vec[0], cos_sin_vec[2]}, -1);
}
// positions is already int64 on ILU (pre-converted in ForwardInput::to).
torch::Tensor long_position_ids = params.position_ids.value().to(at::kLong);
ilu::apply_rope_pos_ids_cos_sin_cache(
params.q, params.k, ilu_cos_sin, long_position_ids, params.interleaved);
#else
NOT_IMPLEMENTED();
#endif
}
void active(ActivationParams& params) {
#if defined(USE_MLU)
mlu::active(params.input,
params.output,
params.bias,
params.cusum_token_count,
params.act_mode,
params.is_gated,
params.start_expert_id,
params.expert_size);
#elif defined(USE_NPU)
params.output = npu::active(params.input, params.act_mode);
#elif defined(USE_CUDA) || defined(USE_MUSA)
cuda::act_and_mul(params.output, params.input, params.act_mode);
#elif defined(USE_ILU)
ilu::act_and_mul(params.output, params.input, params.act_mode);
#else
NOT_IMPLEMENTED();
#endif
}
void reshape_paged_cache(ReshapePagedCacheParams& params) {
#if defined(USE_MLU)
mlu::reshape_paged_cache(params.key,
params.value,
params.k_cache,
params.v_cache,
params.slot_mapping,
params.direction);
#elif defined(USE_NPU)
npu::reshape_paged_cache(params.key,
params.value,
params.k_cache,
params.v_cache,
params.slot_mapping);
#elif defined(USE_CUDA) || defined(USE_MUSA)
cuda::reshape_paged_cache(params.slot_mapping,
params.key,
params.value.value_or(torch::Tensor()),
params.k_cache,
params.v_cache.value_or(torch::Tensor()));
#elif defined(USE_ILU)
// auto v_cache = params.v_cache.value_or(torch::Tensor());
ilu::reshape_paged_cache(params.key,
params.value,
params.k_cache,
params.v_cache,
params.slot_mapping);
#else
NOT_IMPLEMENTED();
#endif
}
void reshape_from_cache(ReshapeFromCacheParams& params) {
#if defined(USE_MLU)
mlu::reshape_from_cache(params.key,
params.value,
params.key_cache,
params.value_cache,
params.context_lengths,
params.max_context_len,
params.context_seq_offset,
params.block_tables,
params.cache_seq_offset);
#else
NOT_IMPLEMENTED();
#endif
}
void quant_to_paged_cache(ReshapePagedCacheParams& params) {
#if defined(USE_MLU)
CHECK(params.k_cache_scale.has_value())
<< "k_cache_scale is required for quant_to_paged_cache";
mlu::quant_to_paged_cache(params.key,
params.value,
params.k_cache,
params.v_cache,
params.k_cache_scale.value(),
params.v_cache_scale,
params.slot_mapping);
#else
NOT_IMPLEMENTED();
#endif
}
void dequant_from_paged_cache(ReshapeFromCacheParams& params) {
#if defined(USE_MLU)
CHECK(params.key_cache_quant_scale.has_value())
<< "key_cache_quant_scale is required for dequant_from_paged_cache";
mlu::dequant_from_paged_cache(params.key,
params.value,
params.key_cache,
params.value_cache,
params.key_cache_quant_scale.value(),
params.value_cache_quant_scale,
params.context_lengths,
params.max_context_len,
params.context_seq_offset,
params.block_tables.value(),
params.quant_mode,
params.quant_bit);
#else
NOT_IMPLEMENTED();
#endif
}
void fused_layernorm(FusedLayerNormParams& params) {
#if defined(USE_MLU)
mlu::fused_layernorm(params.input,
params.output,
params.residual,
params.weight,
params.beta,
params.bias,
params.quant_scale,
params.residual_out,
params.smooth_quant_scale,
params.normed_out,
params.mode,
params.eps,
params.store_output_before_norm,
params.store_output_after_norm,
params.dynamic_quant);
#elif defined(USE_MUSA)
musa::fused_layernorm(params.input,
params.output,
params.residual,
params.weight,
params.beta,
params.bias,
params.quant_scale,
params.residual_out,
params.smooth_quant_scale,
params.normed_out,
params.mode,
params.eps,
params.store_output_before_norm,
params.store_output_after_norm,
params.dynamic_quant);
#elif defined(USE_NPU)
if (params.residual.has_value()) {
std::tie(params.output, std::ignore, params.residual_out) =
npu::add_rms_norm(
params.input, params.residual.value(), params.weight, params.eps);
} else {
params.output =
npu::rms_norm(params.input, params.weight, params.eps, params.mode);
}
#elif defined(USE_CUDA) || defined(USE_MUSA)
if (params.residual.has_value()) {
cuda::fused_add_rms_norm(
params.input, params.residual.value(), params.weight, params.eps);
params.output = params.input;
params.residual_out = params.residual;
} else {
cuda::rms_norm(params.output, params.input, params.weight, params.eps);
}
#elif defined(USE_ILU)
if (params.residual.has_value()) {
ilu::residual_layer_norm(params.input,
params.output,
params.residual,
params.weight,
params.bias, // residual_bias
params.residual_out,
params.eps);
} else {
ilu::rms_norm(params.output, params.input, params.weight, params.eps);
}
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor matmul(MatmulParams& params) {
#if defined(USE_MLU)
return mlu::matmul(
params.a, params.b, params.bias, params.c, params.alpha, params.beta);
#elif defined(USE_NPU)
return npu::matmul(params.a, params.b, params.bias);
#elif defined(USE_CUDA) || defined(USE_MUSA)
return cuda::matmul(params.a, params.b, params.bias);
#elif defined(USE_ILU)
return ilu::matmul(params.a, params.b, params.bias);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor group_gemm(GroupGemmParams& params) {
#if defined(USE_MLU)
return mlu::group_gemm(params.a,
params.b,
params.token_count,
params.output,
params.a_scale,
params.b_scale,
params.quant_flag,
params.max_dim,
params.trans_a,
params.trans_b,
params.a_quant_bit);
#elif defined(USE_NPU)
std::vector<torch::Tensor> x_list;
std::vector<torch::Tensor> weight_list;
torch::TensorList x_ref;
torch::TensorList weight_ref;
if (params.x_list.has_value()) {
x_ref = params.x_list.value();
} else {
x_list = {params.a};
x_ref = x_list;
}
if (params.weight_list.has_value()) {
weight_ref = params.weight_list.value();
} else {
weight_list = {params.b};
weight_ref = weight_list;
}
std::optional<torch::Tensor> group_list = params.group_list;
if (!group_list.has_value()) {
group_list = params.token_count;
}
auto outputs =
npu::apply_npu_grouped_matmul(x_ref,
weight_ref,
params.bias_list,
params.scale_list,
params.offset_list,
params.antiquant_scale_list,
params.antiquant_offset_list,
params.per_token_scale_list,
group_list,
params.activation_input_list,
params.activation_quant_scale_list,
params.activation_quant_offset_list,
params.split_item,
params.group_type,
params.group_list_type,
params.act_type,
params.tuning_config,
params.output_dtype);
return outputs.back();
#elif defined(USE_ILU)
return ilu::group_gemm(params.a,
params.b,
params.token_count,
params.combine_idx,
params.output);
#else
NOT_IMPLEMENTED();
#endif
}
std::tuple<torch::Tensor, torch::Tensor> moe_active_topk(
MoeFusedTopkParams& params) {
#if defined(USE_MLU)
return mlu::moe_active_topk(params.input,
params.topk,
params.num_expert_group,
params.topk_group,
params.normalize,
params.mask,
params.normed_by,
params.scoring_func,
params.route_scale,
params.e_score_correction_bias);
#elif defined(USE_NPU)
CHECK_EQ(params.scoring_func, "softmax")
<< "Only softmax is supported for NPU";
auto [topk_weights, topk_ids, row_ids] = npu::apply_moe_gating_topk_softmax(
params.input, params.finished, params.topk);
(void)row_ids;
return std::make_tuple(topk_weights, topk_ids);
#elif defined(USE_ILU)
return ilu::moe_active_topk(params.input,
params.topk,
params.num_expert_group,
params.topk_group,
params.normalize,
params.mask,
params.normed_by,
params.scoring_func,
params.route_scale,
params.e_score_correction_bias);
#elif defined(USE_CUDA) || defined(USE_MUSA)
return cuda::moe_fused_topk(params.input,
params.topk,
params.normalize,
params.e_score_correction_bias,
params.scoring_func);
#else
NOT_IMPLEMENTED();
#endif
}
std::vector<torch::Tensor> moe_gen_idx(MoeGenIdxParams& params) {
#if defined(USE_MLU)
return mlu::moe_gen_idx(params.expert_id, params.expert_num);
#elif defined(USE_ILU)
return ilu::moe_gen_idx(params.expert_id, params.expert_num);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor moe_expand_input(MoeExpandInputParams& params) {
#if defined(USE_MLU)
return mlu::moe_expand_input(params.input,
params.gather_index,
params.cusum_token_count,
params.start_expert_id,
params.expert_size);
#elif defined(USE_ILU)
return ilu::moe_expand_input(
params.input, params.gather_index, params.combine_idx, params.topk);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor moe_combine_result(MoeCombineResultParams& params) {
#if defined(USE_MLU)
return mlu::moe_combine_result(params.input,
params.reduce_weight,
params.gather_ids,
params.residual,
params.cusum_token_count,
params.start_expert_id,
params.expert_size,
params.bias);
#elif defined(USE_NPU)
std::optional<torch::Tensor> probes =
params.probes.has_value()
? params.probes
: std::optional<torch::Tensor>(params.reduce_weight);
auto output = npu::apply_npu_moe_token_unpermute(params.input,
params.gather_ids,
probes,
params.padded_mode,
params.restore_shape);
if (params.residual.has_value()) {
output = output + params.residual.value();
}
return output;
#elif defined(USE_ILU)
return ilu::moe_combine_result(params.input, params.reduce_weight);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor moe_all2all_gen_send_layout(
MoeAll2AllGenSendLayoutParams& params) {
#if defined(USE_MLU)
return mlu::moe_all2all_gen_send_layout(params.token_count, params.nrank);
#else
NOT_IMPLEMENTED();
#endif
}
std::vector<torch::Tensor> moe_all2all_gen_gather_index(
MoeAll2AllGenGatherIndexParams& params) {
#if defined(USE_MLU)
return mlu::moe_all2all_gen_gather_index(
params.token_num, params.pad_num, params.return_cusum_token_count);
#else
NOT_IMPLEMENTED();
#endif
}
std::vector<torch::Tensor> moe_all2all_create(MoeAll2AllCreateParams& params) {
#if defined(USE_MLU)
return mlu::moe_all2all_create(params.dispatch_token_byte,
params.combine_token_byte,
params.max_expert_num,
params.max_token_num,
params.rank,
params.nrank,
params.device);
#else
NOT_IMPLEMENTED();
#endif
}
void moe_all2all_init(MoeAll2AllInitParams& params) {
#if defined(USE_MLU)
mlu::moe_all2all_init(params.handle, params.all_exchange_info, params.device);
#else
NOT_IMPLEMENTED();
#endif
}
void moe_all2all_dispatch(MoeAll2AllDispatchParams& params) {
#if defined(USE_MLU)
mlu::moe_all2all_dispatch(params.handle,
params.token_byte,
params.token_num,
params.send_layout,
params.send_token_num,
params.recv_layout,
params.recv_token_num,
params.send_token,
params.recv_token);
#else
NOT_IMPLEMENTED();
#endif
}
void moe_all2all_combine(MoeAll2AllCombineParams& params) {
#if defined(USE_MLU)
mlu::moe_all2all_combine(params.handle,
params.token_byte,
params.token_num,
params.send_src_layout,
params.send_dst_layout,
params.send_token,
params.recv_token);
#else
NOT_IMPLEMENTED();
#endif
}
void moe_all2all_destroy(MoeAll2AllDestroyParams& params) {
#if defined(USE_MLU)
mlu::moe_all2all_destroy(params.handle, params.device);
#else
NOT_IMPLEMENTED();
#endif
}
std::tuple<torch::Tensor, torch::Tensor> scaled_quantize(
ScaledQuantizeParams& params) {
#if defined(USE_MLU)
return mlu::scaled_quantize(params.x,
params.smooth,
params.zero,
params.token_count,
params.gather_index,
params.gather_index_start_position,
params.output,
params.output_scale,
params.act_mode,
params.active_coef,
params.is_gated,
params.quant_type);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor scaled_matmul(ScaledMatmulParams& params) {
#if defined(USE_MLU)
return mlu::scaled_matmul(params.a,
params.b,
params.a_scale,
params.b_scale,
params.output_dtype,
params.bias,
params.c,
params.act_mode,
params.quant_bit_size,
params.alpha,
params.beta,
params.use_hp_active,
params.a_quant_bit_size,
params.a_calib,
params.b_calib,
params.output);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor apply_top_k_top_p(TopKPParams& params) {
#if defined(USE_MLU)
return mlu::apply_top_k_top_p(
params.logits, params.temperatures, params.top_k, params.top_p);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor random_sample(RandomSampleParams& params) {
#if defined(USE_MLU)
return mlu::random_sample(params.logits);
#elif defined(USE_CUDA)
return cuda::random_sample(params.logits);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor rejection_sample(RejectionSampleParams& params) {
#if defined(USE_MLU)
return mlu::rejection_sample(params.draft_token_ids,
params.num_draft_tokens,
params.cu_num_draft_tokens,
params.draft_probs,
params.target_probs,
params.bonus_token_ids,
params.uniform_rand,
params.uniform_probs,
params.max_spec_len);
#else
NOT_IMPLEMENTED();
#endif
}
void masked_indexer_select_paged_kv(MaskedIndexerSelectPagedKVParams& params) {
#if defined(USE_MLU)
mlu::masked_indexer_select_paged_kv(params.query,
params.k_cache,
params.weights,
params.kv_cache_block_table,
params.cu_seq_q_lens,
params.cu_seq_k_lens,
params.k_context_lens,
params.k_cache_block_table,
params.is_prefill,
params.index_topk,
params.kv_cache_block_size,
params.softmax_scale,
params.q_scale,
params.k_scale_cache,
params.sparse_block_table,
params.sparse_context_lens);
#else
NOT_IMPLEMENTED();
#endif
}
void gather_split(GatherSplitParams& params) {
#if defined(USE_MLU)
mlu::gather_split(params.input,
params.gather_index,
params.valid_token_num,
params.output_head,
params.output_tail);
#else
NOT_IMPLEMENTED();
#endif
}
void fused_mla_q(FusedMlaQParams& params) {
#if defined(USE_MLU)
mlu::fused_mla_q(params.q,
params.output,
params.output_scale,
params.output_norm,
params.gamma,
params.smooth_quant_scale,
params.weight_b,
params.weight_b_scale,
params.weight_c,
params.sin,
params.cos,
params.position_id,
params.quant_mode,
params.eps,
params.interleaved);
#else
NOT_IMPLEMENTED();
#endif
}
void fused_mla_kv(FusedMlaKVParams& params) {
#if defined(USE_MLU)
mlu::fused_mla_kv(params.input_kv,
params.sin,
params.cos,
params.position_id,
params.gamma,
params.kv_cache,
params.kv_cache_scale,
params.slot_mapping,
params.cache_bs_id,
params.cache_seq_offset,
params.quant_mode,
params.is_paged_cache,
params.eps,
params.interleaved);
#else
NOT_IMPLEMENTED();
#endif
}
void fused_indexer_q(FusedIndexerQParams& params) {
#if defined(USE_MLU)
mlu::fused_indexer_q(params.input_q,
params.output,
params.output_scale,
params.w_q,
params.w_q_scale,
params.hadamard_matrix,
params.sin,
params.cos,
params.position_id,
params.quant_mode,
params.interleaved,
params.rope_at_front);
#else
NOT_IMPLEMENTED();
#endif
}
void fused_indexer_k(FusedIndexerKParams& params) {
#if defined(USE_MLU)
mlu::fused_indexer_k(params.x,
params.wk,
params.wproj,
params.sin_table,
params.cos_table,
params.position_id,
params.slot_mapping,
params.head_weights,
params.k_cache,
params.k_cache_scale,
params.hadamard_matrix,
params.interleaved,
params.gamma,
params.beta,
params.eps);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor l2_norm(torch::Tensor& x, double eps) {
#if defined(USE_NPU)
return npu::npu_l2norm_last_dim(x, eps);
#else
NOT_IMPLEMENTED();
#endif
}
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor>
moe_init_routing_v2(MoeInitRoutingV2Params& params) {
#if defined(USE_NPU)
return npu::apply_npu_moe_init_routing_v2(params.x,
params.expert_idx,
params.scale,
params.offset,
params.active_num,
params.expert_capacity,
params.expert_num,
params.drop_pad_mode,
params.expert_tokens_num_type,
params.expert_tokens_num_flag,
params.quant_mode,
params.active_expert_range,
params.row_idx_type);
#else
NOT_IMPLEMENTED();
#endif
}
std::tuple<torch::Tensor, torch::Tensor> fp8_scaled_quantize(
Fp8ScaledQuantizeParams& params) {
#if defined(USE_CUDA)
return cuda::fp8_scaled_quantize(params.input, params.output, params.scale);
#else
NOT_IMPLEMENTED();
#endif
}
std::pair<torch::Tensor, torch::Tensor> fused_gdn_gating(
FusedGdnGatingParams& params) {
#if defined(USE_NPU)
return npu::tilelang::fused_gdn_gating(params.A_log,
params.a,
params.b,
params.dt_bias,
params.beta,
params.threshold);
// return npu::npu_fused_gdn_gating(params.A_log,
// params.a,
// params.b,
// params.dt_bias,
// params.beta,
// params.threshold);
#else
NOT_IMPLEMENTED();
#endif
}
std::pair<torch::Tensor, torch::Tensor> fused_recurrent_gated_delta_rule(
FusedRecurrentGatedDeltaRuleParams& params) {
#if defined(USE_NPU)
return npu::npu_fused_recurrent_gated_delta_rule(
params.q,
params.k,
params.v,
params.g,
params.beta,
params.scale,
params.initial_state,
params.inplace_final_state,
params.cu_seqlens,
params.ssm_state_indices,
params.num_accepted_tokens,
params.use_qk_l2norm_in_kernel);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor fp8_scaled_matmul(Fp8ScaledMatmulParams& params) {
#if defined(USE_CUDA)
auto out_2d = cuda::fp8_scaled_matmul(params.a,
params.b,
params.a_scale,
params.b_scale,
params.output_dtype,
params.bias,
params.output);
// Auto reshape output if original input shape is provided
if (params.input_shape.has_value()) {
auto out_shape = params.input_shape.value();
out_shape.back() = params.b.size(0);
return out_2d.view(out_shape);
}
return out_2d;
#else
LOG(FATAL) << "fp8_scaled_matmul is only supported on CUDA";
return torch::Tensor();
#endif
}
void static_scaled_fp8_quant(StaticScaledFp8QuantParams& params) {
#if defined(USE_CUDA)
cuda::static_scaled_fp8_quant(params.output, params.input, params.scale);
#else
LOG(FATAL) << "static_scaled_fp8_quant is only supported on CUDA";
#endif
}
// Fused RMSNorm + Static FP8 Quantization
torch::Tensor rms_norm_static_fp8_quant(RmsNormStaticFp8QuantParams& params) {
#if defined(USE_CUDA)
auto org_shape = params.input.sizes().vec();
auto hidden_size = params.input.size(-1);
// Flatten input to 2D. Use reshape to support non-contiguous tensors.
auto input_2d = params.input.reshape({-1, hidden_size});
torch::Tensor output =
torch::empty({input_2d.size(0), hidden_size},
input_2d.options().dtype(torch::kFloat8_e4m3fn));
// Call fused kernel
cuda::rms_norm_static_fp8_quant(
output, input_2d, params.weight, params.scale, params.epsilon);
return output.reshape(org_shape);
#else
LOG(FATAL) << "rms_norm_static_fp8_quant is only supported on CUDA";
return torch::Tensor();
#endif
}
std::tuple<torch::Tensor, torch::Tensor> fused_add_rms_norm_static_fp8_quant(
FusedAddRmsNormStaticFp8QuantParams& params) {
#if defined(USE_CUDA)
auto org_shape = params.input.sizes().vec();
auto hidden_size = params.input.size(-1);
// Flatten tensors to 2D. Use reshape to support non-contiguous tensors.
auto input_2d = params.input.reshape({-1, hidden_size});
auto residual_2d = params.residual.reshape({-1, hidden_size});
torch::Tensor output =
torch::empty({input_2d.size(0), hidden_size},
input_2d.options().dtype(torch::kFloat8_e4m3fn));
// Call fused kernel (residual is updated in-place)
cuda::fused_add_rms_norm_static_fp8_quant(output,
input_2d,
residual_2d,
params.weight,
params.scale,
params.epsilon);
// Reshape outputs
auto output_reshaped = output.reshape(org_shape);
auto residual_reshaped = residual_2d.reshape(org_shape);
return std::make_tuple(output_reshaped, residual_reshaped);
#else
LOG(FATAL) << "fused_add_rms_norm_static_fp8_quant is only supported on CUDA";
return std::make_tuple(torch::Tensor(), torch::Tensor());
#endif
}
torch::Tensor causal_conv1d_update(CausalConv1dUpdateParams& params) {
#if defined(USE_NPU)
if (params.conv_state_indices.has_value()) {
CHECK(params.conv_state_indices.value().is_contiguous())
<< "causal_conv1d_update: conv_state_indices must be contiguous.";
}
return npu::npu_causal_conv1d_update_v2(params.x,
params.conv_state,
params.weight,
params.activation,
params.bias,
params.conv_state_indices,
params.query_start_loc,
params.max_query_len,
params.pad_slot_id,
params.block_idx_last_scheduled_token,
params.initial_state_idx,
params.validate_data);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor gated_layer_norm(GatedLayerNormParams& params) {
#if defined(USE_NPU)
return npu::layer_norm_fwd(params.x,
params.weight,
params.bias,
params.eps,
params.z,
params.group_size,
params.norm_before_gate,
params.is_rms_norm);
#elif defined(USE_MLU)
return mlu::gated_layer_norm(params.x,
params.weight,
params.bias,
params.eps,
params.z,
params.group_size,
params.norm_before_gate);
#else
NOT_IMPLEMENTED();
#endif
}
std::pair<torch::Tensor, torch::Tensor> partial_rotary_embedding(
PartialRotaryEmbeddingParams& params) {
#if defined(USE_NPU)
return npu::apply_npu_partial_rotary_embedding(params.positions,
params.query,
params.key,
params.head_size,
params.rotary_dim,
params.cos_sin_cache,
params.is_neox_style);
#else
NOT_IMPLEMENTED();
#endif
}
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor>
fused_qkvzba_split_reshape_cat(FusedQkvzbaSplitReshapeParams& params) {
#if defined(USE_NPU)
return npu::npu_fused_qkvzba_split_reshape_cat(params.mixed_qkvz,
params.mixed_ba,
params.num_heads_qk,
params.num_heads_v,
params.head_qk,
params.head_v);
#else
NOT_IMPLEMENTED();
#endif
}
void gemma_rms_norm(GemmaRMSNormParams& params) {
#if defined(USE_NPU)
npu::npu_gemma_rms_norm(
params.x, params.gamma, params.epsilon, params.rstd_out, params.norm_out);
#elif defined(USE_MLU)
mlu::gemma_rms_norm(params.x, params.gamma, params.epsilon, params.norm_out);
#else
NOT_IMPLEMENTED();
#endif
}
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor>
split_qkv_rmsnorm_mrope(SplitQkvRmsnormMropeParams& params) {
#if defined(USE_NPU)
return npu::tilelang::split_qkv_rmsnorm_mrope(params.qkvg,
params.q_weight,
params.k_weight,
params.cos_sin,
params.gather_pattern,
params.eps,
params.num_q_heads,
params.num_kv_heads,
params.head_size);
#else
NOT_IMPLEMENTED();
#endif
}
bool has_split_qkv_rmsnorm_mrope_specialization(int64_t num_q_heads,
int64_t num_kv_heads,
int64_t head_size) {
#if defined(USE_NPU)
return npu::tilelang::has_split_qkv_rmsnorm_mrope_specialization(
num_q_heads, num_kv_heads, head_size);
#else
return false;
#endif
}
torch::Tensor build_split_qkv_rmsnorm_mrope_gather_pattern(
int64_t rope_dim,
const std::vector<int64_t>& mrope_section,
bool is_interleaved,
const torch::Device& device) {
#if defined(USE_NPU)
return npu::tilelang::build_split_qkv_rmsnorm_mrope_gather_pattern(
rope_dim, mrope_section, is_interleaved, device);
#else
NOT_IMPLEMENTED();
#endif
}
std::pair<torch::Tensor, torch::Tensor> chunk_gated_delta_rule(
ChunkGatedDeltaRuleParams& params) {
#if defined(USE_NPU)
return npu::npu_chunk_gated_delta_rule(params.q,
params.k,
params.v,
params.g,
params.beta,
params.scale,
params.initial_state,
params.output_final_state,
params.cu_seqlens,
params.head_first,
params.use_qk_l2norm_in_kernel);
#else
NOT_IMPLEMENTED();
#endif
}
torch::Tensor recurrent_gated_delta_rule(
const torch::Tensor& query,
const torch::Tensor& key,
const torch::Tensor& value,
torch::Tensor& state,
const std::optional<torch::Tensor>& beta,
const std::optional<double> scale,
const std::optional<torch::Tensor>& actual_seq_lengths,
const std::optional<torch::Tensor>& ssm_state_indices,
const std::optional<torch::Tensor>& num_accepted_tokens,
const std::optional<torch::Tensor>& g,
const std::optional<torch::Tensor>& gk) {
#if defined(USE_NPU)
return npu::npu_recurrent_gated_delta_rule(query,
key,
value,
state,
beta,
scale,
actual_seq_lengths,
ssm_state_indices,
num_accepted_tokens,
g,
gk);
#else
NOT_IMPLEMENTED();
#endif
}
} // namespace xllm::kernel